以太坊学习路线——(四、上)Truffle安装、truffle项目创建、编译、部署

这篇博客演示的基本操作系统环境是CentOS 7,参考书籍:以太坊开发实战——以太坊关键技术与案例分析 第十章(吴寿鹤、冯翔、刘涛、周广益   著)。鉴于内容较多,分成两篇,下一篇博文请见:以太坊学习路线——(四、下)truffle项目合约交互、合约测试、配置文件、依赖管理

文章结构:

一、Truffle简介

二、安装Truffle

三、创建并初始化项目

四、创建合约

五、编译合约

六、迁移合约

 

一、Truffle简介

Truffle是一套针对以太坊Solidity语言的开发框架,本身基于javascript。Truffle为以太坊提供了开发环境、测试框架和资产管道(pipeline),旨在使以太坊开发更加容易。Truffle特性:

  • 内置的智能合约编译,链接,部署和二进制文件的管理。
  • 快速开发下的自动合约测试。
  • 脚本化的,可扩展的部署与发布框架。
  • 部署到不管多少的公网或私网的网络环境管理功能
  • 使用EthPM&NPM提供的包管理,使用ERC190标准。
  • 与合约直接通信的直接交互控制台(写完合约就可以命令行里验证了)。
  • 可配的构建流程,支持紧密集成。
  • 在Truffle环境里支持执行外部的脚本。

二、安装Truffle

$ npm install -g truffle

检查Turffle是否正确安装:

[root@localhost myproject]# truffle
Truffle v5.0.10 - a development framework for Ethereum

Usage: truffle <command> [options]

Commands:
  build     Execute build pipeline (if configuration present)
  compile   Compile contract source files
  config    Set user-level configuration options
  console   Run a console with contract abstractions and commands available
  create    Helper to create new contracts, migrations and tests
  debug     Interactively debug any transaction on the blockchain
            (experimental)
  deploy    (alias for migrate)
  develop   Open a console with a local development blockchain
  exec      Execute a JS module within this Truffle environment
  help      List all commands or provide information about a specific command
  init      Initialize new and empty Ethereum project
  install   Install a package from the Ethereum Package Registry
  migrate   Run migrations to deploy contracts
  networks  Show addresses for deployed contracts on each network
  obtain    Fetch and cache a specified compiler
  opcode    Print the compiled opcodes for a given contract
  publish   Publish a package to the Ethereum Package Registry
  run       Run a third-party command
  test      Run JavaScript and Solidity tests
  unbox     Download a Truffle Box, a pre-built Truffle project
  version   Show version number and exit
  watch     Watch filesystem for changes and rebuild the project
            automatically

See more at http://truffleframework.com/docs
//我的truffle版本
[root@localhost myproject]# truffle version
Truffle v5.0.10 (core: 5.0.10)
Solidity v0.5.0 (solc-js)
Node v11.13.0
Web3.js v1.0.0-beta.37

 三、创建并初始化项目

$ mkdir myproject
$ cd myproject
$ truffle init

//完成后目录结构如下:
[root@localhost myproject1]# tree ./
./
├── contracts
│   └── Migrations.sol
├── migrations
│   └── 1_initial_migration.js
├── test
└── truffle-config.js
  • contracts/:存放我们编写的合约。
  • migrations/:存放迁移部署脚本
  • test/:存放合约测试脚本。
  • truffle-config.js/:存放truffle配置文件。

较早版本truffle init会在目录中创建一个名叫MetaCoin的代币应用。将这个应用相关文件删除,直到和上面的目录结构相同。

四、创建合约

在contracts目录下创建自己的合约Storage.sol:

$ cd contracts/
$ vi Storage.sol

//合约内容如下:根据编译器版本不同,可能会出现不同的错误与警告,请自己核实处理
pragma solidity >=0.4.21 <0.6.0;

contract Storage {

        uint256 public storedData;

        function set(uint256 data) public {
                storedData = data;
        }

        function get() public view returns (uint256) {
                return storedData;
        }
}

五、编译合约

[root@localhost myproject]# truffle compile

Compiling your contracts...
===========================
> Compiling ./contracts/Storage.sol
> Artifacts written to /opt/myproject/build/contracts
> Compiled successfully using:
   - solc: 0.5.0+commit.1d4f565a.Emscripten.clang

 从输出结果可以看到,合约编译后的文件会写入./build/contracts目录中,这些合约编译好之后的文件对于Truffle框架能否正常工作至关重要。请不要手动修改这些文件,因为即使修改了,再次执行编译命令时又会被覆盖。

Truffle默认只编译自上次编译后修改过的合约,目的是减少不必要的编译。如果你想编译全部合约,可以使用--all选项。

$ truffle compile --all

六、迁移合约

迁移脚本是由一些javascript文件组成,在truffle中部署合约需要用到迁移脚本。这是因为你的部署需求会随着时间改变。随着项目的发展,你可以创建新的迁移脚本把这些变化的合约部署到区块链上。之前你运行的迁移历史记录,会被一个特殊的Migrations.sol合约记录在区块链。

迁移合约命名规则:文件以数字开头,以一个描述性的后缀结尾。数字前缀是必须的,用于记录移植是否成功。后缀仅仅是为了提高可读性,以方便理解。

下面进入migrations目录中为Storage合约创建一个迁移脚本:

$ cd migrations
$ touch 2_storage_migrations.js


//迁移脚本2_storage_migrations.js内容:
const Migrations = artifacts.require("Storage");

module.exports = function(deployer) {
  deployer.deploy(Migrations);
};

1.artifacts.require()

在迁移脚本中的最开始,通过artifacts.require()方法告诉truffle我们将要与哪个合约交互。这个方法类似于Nodejs中的require,但在这里,它返回的是一个合约抽象。我们可以在迁移脚本的其余部分中使用这个合约抽象。artifacts.require()参数中使用的名字不是必须与合约源文件的文件名相同,相反,它应该与在合约源代码中定义的合约类定义的合约类的名称相同。

2.module.exports

在迁移合约脚本最后,我们通过module.exports导出一个函数,被迁移脚本导出的函数都应高接受一个depoyer对象作为其第一个参数。

3.迁移合约

至此就可以把Storage.sol部署到区块链上了,这次把智能合约部署到Testrpc环境中。

//如果你还没有安装Testrpc那么先执行下面的命令,其需要Node较高版本的环境依赖
$ npm install -g ethereumjs-testrpc


//安装完成后启动Testrpc:
$ testrpc

testrpc启动后,回到myproject项目的目录中,通过执行下面的命令就可以完成合约迁移:

$ truffle migrate

但是由于的truffle版本是,所以出现了如下问题:

Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.


Could not connect to your Ethereum client with the following parameters:
    - host       > 127.0.0.1
    - port       > 7545
    - network_id > 5777
Please check that your Ethereum client:
    - is running
    - is accepting RPC connections (i.e., "--rpc" option is used in geth)
    - is accessible over the network
    - is properly configured in your Truffle configuration file (truffle-config.js)

Truffle v5.0.10 (core: 5.0.10)
Node v11.13.0

猜测可能是提示检测的最后一条选项,所以打开truffle-config.js,设置其中部分内容如下:

 networks: {
    // Useful for testing. The `development` name is special - truffle uses it by default
    // if it's defined here and no other network is specified at the command line.
    // You should run a client (like ganache-cli, geth or parity) in a separate terminal
    // tab if you use this network and you must also set the `host`, `port` and `network_id`
    // options below to some value.
    //
    development: {
      host: "127.0.0.1",     // Localhost (default: none)
      port: 8545,            // Standard Ethereum port (default: none)
      network_id: "*",       // Any network (default: none)
    },

修改后重新迁移,部分显示结果如下:

2_storage_migration.js
======================

   Deploying 'Storage'
   -------------------
   > transaction hash:    0x92cb91d96ddce4c5f5f73ba7b31a6d26b7f92e6a9b559f5e624281e35be8a50c
   > Blocks: 0            Seconds: 0
   > contract address:    0x92Afc835189BAf7a82AFfa45282eFbAa449da4c6
   > account:             0xF8A0A572fF93C87A711D7B6FD71b7b81650daCE1
   > balance:             99.99084662
   > gas used:            130727
   > gas price:           20 gwei
   > value sent:          0 ETH
   > total cost:          0.00261454 ETH


   > Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:          0.00261454 ETH

 从显示信息可以看出在部署Storage合约时,是以交易的形式将合约发布到测试网络中,可以看到发布合约的交易地址hash,合约地址、合约用户account帐号……,而且在testrpc终端也可以看到相同的操作记录:

  Transaction: 0x92cb91d96ddce4c5f5f73ba7b31a6d26b7f92e6a9b559f5e624281e35be8a50c
  Contract created: 0x92afc835189baf7a82affa45282efbaa449da4c6
  Gas usage: 130727
  Block Number: 3
  Block Time: Tue Apr 02 2019 09:26:46 GMT+0800 (Hong Kong Standard Time)

truffle migrate命令会执行所有位于migrates目录内的迁移脚本。如果你之前已经成功执行过迁移脚本,那么truffle migrage仅会执行新创建的迁移。如果没有新的迁移脚本,这个命令不会执行任何操作,可使用选项--reset来重新执行全部迁移脚本。

$ truffle migrate --reset

4.初始化性的迁移合约

为了使用迁移功能,Truffle要求你要有一个迁移合约。这个合约必须包含一个特定的接口,对于大多数项目来说,这个合约只会在第一次做迁移的时被部署,以后都不会做任何更改了。这个合约就是在一开始truffle init之后在contracts目录下默认创建的那个Migrations.sol文件。

为了利用迁移的特性,首先必须部署这个Migrations.sol合约,所以truffle init时也默认在migrations目录下创建了该合约的迁移脚本:1_initial_migrations.js      要部署其他合约你可以递增数字编号前缀来创建新的迁移脚本。

5.部署器(deployer)

你的迁移脚本会使用deployer对象来组织部署任务。deployer对象会同步执行部署任务,故你可以按顺序编写部署任务。

//先部署A,后部署B
deployer.deploy(A);
deployer.deploy(B);

另外,deployer上的每一个函数都会返回一个promise,通过promise可以把有执行顺序依赖关系的部署任务组成队列。

//先部署A,然后部署B,把A部署后的地址传给B
deployer.deploy(A).then( function () {
    return deployer.deploy(B,A.address);
});

6.deployer API

(1).deployer.deploy(CONTRACT,ARGS…,OPTIONS)

这个API用来部署合约,contract参数传入需要部署的合约名字,args参数传入合约的构造函数需要的参数,options是一个可选参数,它的值是{overwrite:true/false}。如果overwrite被设置为false,那么当这个合约之前已经部署过了,这个deployer就不会再部署这个合约,这在一个合约的依赖由另一个外部地址提供的情况下是有用的。为了快速进行部署多个合约,你可以向deployer。deploy(…)函数中传入一个或多个数组。eg:

//部署单个合约,不带任何构造参数
deployer.deploy(A);

//部署单个合约带有构造参数
deployer.deploy(A,arg1,arg2,……);

//部署多个合约,有的带有构造参数,有的不带构造参数
//比写三次deployer.deploy()语句更快,因为deployer可以把所有的合约部署一次性打包提交
deployer.deploy([
    [A,arg1,arg2,…],
    [B],
    [C,arg1]
]);

//外部依赖的例子:
//overwrite:false表示如果SomeDependency合约之前已经被部署过,那么不再重复部署,之结使用之前已经部署好的地址
//如果合约要运行在自己的测试链上,或者将要运行的链上没有SomeDependency合约,
//那么把overwrite:false改为ovwewrite:true,表示不再检查之前SomeDependency有没有部署过,一律覆盖部署
deployer.deploy(SomeDependency,{overwrite:false});

(2).deployer.link(LIBRARY,DESTINATIONS)

把一个已部署好的库链接到一个或多个合约里。destinations可以传入一个合约,也可以传入一组合约。如果destinations中的某个合约不依赖这个库,那么deployer的link函数就会忽略这个合约。

//部署库LibA,然后把LibA链接到合约B,然后部署合约B
deployer.deploy(LibA);
deployer.link(LibA,B);
deployer.deploy(B);

//库LibA链接到多个合约
deployer.link(LibA,[B,C,D]);

(3).deployer.then(function() {…})

在迁移过程中使用它调用特定合约的函数来部署新的合约,为已部署的合约做一些初始化工作等。eg:

var a,b;
deployer.then(function () {
    //部署合约A的一个新版本到网络上
    return A.new();
}).then(function (instance) {
    a = instance;
    //获取已部署的合约B的实例
    return B.deployed();
}).then(function (instance) {
    b = instance;
    //使用合约B的setA()方法设置A的地址的新实例
    return b.setA(a.address);
});

(4).网络相关

在执行迁移时,Truffle会把truffle-config.js里配置的networks传递给迁移脚本,你可以在迁移脚本中的module.exports导出函数中的第二个参数位置接受这个networks参数值。

//truffle-config.js文件
module.exports = {
    networks: {
        development: {
          host: "127.0.0.1",     // Localhost (default: none)
          port: 8545,            // Standard Ethereum port (default: none)
          network_id: "*",       // Any network (default: none)
        }
    }
};

//在迁移脚本中接受networks:
module.exports = function(deployer.network) {
    if (network == "live") {
        //TODO
    } else {
        //TODO
    }
}

(5).可用的账户

在执行迁移时,Truffle会把当前以太坊客户端或web3.provider中可用的账户列表传递给迁移脚本,这个账户列表与web3.eth.getAccount()返回的账户列表完全一样。你可以在迁移脚本中的module.exports导出函数中第三个参数位置接受这个accounts参数值。

module.exports = function(deployer,networks,accounts) {
    //在你的迁移脚本中使用账户
}

猜你喜欢

转载自blog.csdn.net/GDUYT_gduyt/article/details/88957688