Solidity的Truffle框架实战(Windows)

1.github项目下载
结构:

Solidity的Truffle框架实战(Windows)_第1张图片

目录结构简单说明如下:

app/ - 你的应用文件运行的默认目录。这里面包括推荐的javascript文件和css样式文件目录,但你可以完全决定如何使用这些目录。
contract/ - Truffle默认的合约文件存放地址。
migrations/ - 存放发布脚本文件
test/ - 用来测试应用和合约的测试文件
truffle.js - Truffle的配置文件
详细说明:配置说明
2.放入自己的合约
删除./contract目录下的自带demo合约,切记不要删除./contract/Migrations.sol合约,它是Truffle用来帮助部署的。
在./contract目录下创建一个自己的合约文件Greeter.sol。

pragma solidity ^0.4.0;

contract Greeter         
{
    address creator;     
    string greeting;     

    function Greeter(string _greeting) public   
    {
        creator = msg.sender;
        greeting = _greeting;
    }

    function greet() constant returns (string)          
    {
        return greeting;
    }

    function setGreeting(string _newgreeting) 
    {
        greeting = _newgreeting;
    }

     /**********
     Standard kill() function to recover funds 
     **********/

    function kill()
    { 
        if (msg.sender == creator)
            suicide(creator);  // kills this contract and sends remaining funds back to creator
    }

}

代码来自fiveDogIt的一段入门代码05_greeter.sol。
3.修改发布脚本
将./migrations/2_deploy_contracts.js下的内容由:

module.exports = function(deployer) {
  deployer.deploy(ConvertLib);
  deployer.autolink();
  deployer.deploy(MetaCoin);
};

修改为:

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

目的是去掉原有自带的Demo部署流程,修改为要部署的合约。修改完后,记得保存,不然发布时会报错,找不到相关合约。详细发布流程参考:部署(migrate)
4. 编译
进入到工程根目录./webpack-box-master目录下,进行编译:

C:\Users\LiYing\Desktop\区块链\webpack-box-master>truffle.cmd compile
Compiling .\contracts\ConvertLib.sol...
Compiling .\contracts\Greeter.sol...
Compiling .\contracts\MetaCoin.sol...
Compiling .\contracts\Migrations.sol...

如果出现警告,可忽略.不是err就行.
5.启动客户端
如果你已经安装了ganache-cli,那么直接在webpack-box-master下:

C:\Users\LiYing\Desktop\区块链\webpack-box-master>ganache-cli

否则先安装

npm install -g ganache-cli truffle

再执行即可
Solidity的Truffle框架实战(Windows)_第2张图片

参考文档1
参考文档2
如果出现Error: Cannot find module ‘babel-register’,点击此处
可以看到ganache-cli启动后自动建立了10个帐号(Accounts),与每个帐号对应的私钥(Private Key)。每个帐号中都有100个测试用的以太币(Ether)。要注意ganache-cli仅运行在內存中,因此每次重开时都会回到全新的状态。

建立项目
开启另一个终端窗口,输入以下命令以建立项目:

C:\Users\LiYing\Desktop\区块链>mkdir SmartContractDemo

C:\Users\LiYing\Desktop\区块链>cd SmartContractDemo

C:\Users\LiYing\Desktop\区块链\SmartContractDemo>mkdir HelloWord

C:\Users\LiYing\Desktop\区块链\SmartContractDemo>cd HelloWord

C:\Users\LiYing\Desktop\区块链\SmartContractDemo\HelloWord>truffle init
Downloading...
Unpacking...
Setting up...
Unbox successful. Sweet!

Commands:

  Compile:        truffle compile
  Migrate:        truffle migrate
  Test contracts: truffle test

目录结构:
Solidity的Truffle框架实战(Windows)_第3张图片
/contracts:存放智能合约原始代码的地方,可以看到里面已经有一个sol文件,我们开发的HelloWorld.sol文件就存放在这个文件夹。

type nul>HelloWorld.sol

HelloWorld.sol文件內容如下:

pragma solidity ^0.4.17;
contract HelloWorld {
  function sayHello() returns (string) {
    return "HelloWorld";
  }
}

讲解

pragma solidity ^0.4.17;

第一行指的是目前使用的solidity版本,不同版本的solidity可能会编译出不同的bytecode。^代表兼容solidity“0.4.17 ~ 0.4.9的版本。

contract HelloWorld {
    ...
}

contract关键字类似于其他语言中较常见的class。因为solidity是专为智能合约(Contact)设计的语言,声明contract后即内置了开发智能合约所需的功能。也可以把这句理解为class HelloWorld extends Contract。

 function sayHello() returns (string) {
    return "HelloWorld";
  }

函数的结构与其他程序类似,但如果有传入的参数或回传值,需要指定参数或回传值的类型(type)。

/migrations:这是 Truffle用来部署智能合约的功能,待会儿我们会新建一个类似1_initial_migration.js的文件来部署 HelloWorld.sol。

type nul>1_initial_migration.js

/test:测试智能合约的代码放在这里,支持js 与 sol 测试。

根目录下truffle.js/truffle-config.js: Truffle 的配置文件,需要配置要连接的以太坊网络
配置truffle.js文件

module.exports = {
  networks: {
    development: {
      host: "127.0.0.1",
      port: 8545,
      network_id: "*" // Match any network id
    }
  }
};

编译
现在执行truffle compile命令,我们可以将HelloWorld.sol原始码编译成Ethereum bytecode。

C:\Users\LiYing\Desktop\区块链\SmartContractDemo\HelloWord>truffle.cmd compile
Compiling .\contracts\HelloWorld.sol...
Compiling .\contracts\Migrations.sol...

Warning暂时忽略,编译成功后,会在HelloWorld文件夹下面的build/contracts文件夹下面看见HelloWorld.json文件。

部署
truffle框架中提供了方便部署合约的脚本。新建migrations/2_deploy_contracts.js文件(脚本使用Javascript编写),将内容修改如下:

var HelloWorld = artifacts.require("./HelloWorld.sol");
module.exports = function(deployer) {
  deployer.deploy(HelloWorld);
};

Solidity的Truffle框架实战(Windows)_第4张图片
使用artifacts.require语句来取得准备部署的合约。使用deployer.deploy语句将合约部署到区块链上。这边HelloWorld是contract的名称而不是文件名。因此可以用此语法读入任一.sol文件中的任一合约。
执行truffle migrate命令:
再次说下,如果执行truffle migrate会打开js文件,那就加上.cmd后缀如下图
Solidity的Truffle框架实战(Windows)_第5张图片
合约已经部署到ganache-cli中。切换到ganache-cli窗口,可以看到ganache-cli有反应了。
Solidity的Truffle框架实战(Windows)_第6张图片

与合约互动
truffle提供命令行工具,执行truffle console命令后,可用Javascript来和刚刚部署的合约互动。

C:\Users\LiYing\Desktop\区块链\SmartContractDemo\HelloWord>truffle console

C:\Users\LiYing\Desktop\区块链\SmartContractDemo\HelloWord>truffle.cmd console
truffle(development)> let contract
undefined
truffle(development)> HelloWorld.deployed().then(instance => contract = instance
)
TruffleContract {
  constructor:
   { [Function: TruffleContract]
     _static_methods:
      { setProvider: [Function: setProvider],
        new: [Function: new],
        at: [Function: at],
        deployed: [Function: deployed],
        defaults: [Function: defaults],
        hasNetwork: [Function: hasNetwork],
        isDeployed: [Function: isDeployed],
        detectNetwork: [Function: detectNetwork],
        setNetwork: [Function: setNetwork],
        resetAddress: [Function: resetAddress],
        link: [Function: link],
        clone: [Function: clone],
        addProp: [Function: addProp],
        toJSON: [Function: toJSON] },
     _properties:
      { contract_name: [Object],
        contractName: [Object],
        abi: [Object],
        network: [Function: network],
        networks: [Function: networks],
        address: [Object],
        transactionHash: [Object],
        links: [Function: links],
        events: [Function: events],
        binary: [Function: binary],
        deployedBinary: [Function: deployedBinary],
        unlinked_binary: [Object],
        bytecode: [Object],
        deployedBytecode: [Object],
        sourceMap: [Object],
        deployedSourceMap: [Object],
        source: [Object],
        sourcePath: [Object],
        legacyAST: [Object],
        ast: [Object],
        compiler: [Object],
        schema_version: [Function: schema_version],
        schemaVersion: [Function: schemaVersion],
        updated_at: [Function: updated_at],
        updatedAt: [Function: updatedAt] },
     _property_values: {},
     _json:
      { contractName: 'HelloWorld',
        abi: [Array],
        bytecode:
         '0x608060405234801561001057600080fd5b5061013f806100206000396000f3006080
60405260043610610041576000357c01000000000000000000000000000000000000000000000000
00000000900463ffffffff168063ef5fb05b14610046575b600080fd5b34801561005257600080fd
5b5061005b6100d6565b604051808060200182810382528381815181526020019150805190602001
9080838360005b8381101561009b578082015181840152602081019050610080565b505050509050
90810190601f1680156100c85780820380516001836020036101000a031916815260200191505b50
9250505060405180910390f35b60606040805190810160405280600a81526020017f48656c6c6f57
6f726c64000000000000000000000000000000000000000000008152509050905600a165627a7a72
305820232cfce6518204d3739a689f5b59477beb3c3188f7f57b5ae002f164390df7330029',
        deployedBytecode:
         '0x608060405260043610610041576000357c0100000000000000000000000000000000
000000000000000000000000900463ffffffff168063ef5fb05b14610046575b600080fd5b348015
61005257600080fd5b5061005b6100d6565b60405180806020018281038252838181518152602001
91508051906020019080838360005b8381101561009b578082015181840152602081019050610080
565b50505050905090810190601f1680156100c85780820380516001836020036101000a03191681
5260200191505b509250505060405180910390f35b60606040805190810160405280600a81526020
017f48656c6c6f576f726c6400000000000000000000000000000000000000000000815250905090
5600a165627a7a72305820232cfce6518204d3739a689f5b59477beb3c3188f7f57b5ae002f16439
0df7330029',
        sourceMap: '25:93:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;25:93:0;;;;;;;',

        deployedSourceMap:
         '25:93:0:-;;;;;;;;;;;;;;;;;;;;;;;;49:67;;8:9:-1;5:2;;;30:1;27;20:12;5:2
;49:67:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;
;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:1
4;49:67:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;78:6;92:19;;;;;;;;;;;;
;;;;;;;;49:67;:::o',
        source:
         'pragma solidity ^0.4.17;\ncontract HelloWorld {\n  function sayHello()
 returns (string) {\n    return "HelloWorld";\n  }\n}',
        sourcePath:
         'C:\\Users\\LiYing\\Desktop\\区块链\\SmartContractDemo\\HelloWord\\cont
racts\\HelloWorld.sol',
        ast: [Object],
        legacyAST: [Object],
        compiler: [Object],
        networks: [Object],
        schemaVersion: '2.0.1',
        updatedAt: '2018-08-30T13:57:12.712Z' },
     setProvider: [Function: bound setProvider],
     new: [Function: bound new],
     at: [Function: bound at],
     deployed: [Function: bound deployed],
     defaults: [Function: bound defaults],
     hasNetwork: [Function: bound hasNetwork],
     isDeployed: [Function: bound isDeployed],
     detectNetwork: [Function: bound detectNetwork],
     setNetwork: [Function: bound setNetwork],
     resetAddress: [Function: bound resetAddress],
     link: [Function: bound link],
     clone: [Function: bound clone],
     addProp: [Function: bound addProp],
     toJSON: [Function: bound toJSON],
     web3:
      Web3 {
        _requestManager: [RequestManager],
        currentProvider: [Provider],
        eth: [Eth],
        db: [DB],
        shh: [Shh],
        net: [Net],
        personal: [Personal],
        bzz: [Swarm],
        settings: [Settings],
        version: [Object],
        providers: [Object],
        _extend: [Function] },
     class_defaults:
      { from: '0x1a1cf647a974c7baa2156af94a415adffb9a8062',
        gas: 6721975,
        gasPrice: 100000000000 },
     currentProvider:
      HttpProvider {
        host: 'http://127.0.0.1:8545',
        timeout: 0,
        user: undefined,
        password: undefined,
        headers: undefined,
        send: [Function],
        sendAsync: [Function],
        _alreadyWrapped: true },
     network_id: '1535636698643' },
  abi:
   [ { constant: false,
       inputs: [],
       name: 'sayHello',
       outputs: [Array],
       payable: false,
       stateMutability: 'nonpayable',
       type: 'function' } ],
  contract:
   Contract {
     _eth:
      Eth {
        _requestManager: [RequestManager],
        getBalance: [Function],
        getStorageAt: [Function],
        getCode: [Function],
        getBlock: [Function],
        getUncle: [Function],
        getCompilers: [Function],
        getBlockTransactionCount: [Function],
        getBlockUncleCount: [Function],
        getTransaction: [Function],
        getTransactionFromBlock: [Function],
        getTransactionReceipt: [Function],
        getTransactionCount: [Function],
        call: [Function],
        estimateGas: [Function],
        sendRawTransaction: [Function],
        signTransaction: [Function],
        sendTransaction: [Function],
        sign: [Function],
        compile: [Object],
        submitWork: [Function],
        getWork: [Function],
        coinbase: [Getter],
        getCoinbase: [Function],
        mining: [Getter],
        getMining: [Function],
        hashrate: [Getter],
        getHashrate: [Function],
        syncing: [Getter],
        getSyncing: [Function],
        gasPrice: [Getter],
        getGasPrice: [Function],
        accounts: [Getter],
        getAccounts: [Function],
        blockNumber: [Getter],
        getBlockNumber: [Function],
        protocolVersion: [Getter],
        getProtocolVersion: [Function],
        iban: [Function],
        sendIBANTransaction: [Function: bound transfer] },
     transactionHash: null,
     address: '0x9fac2e57170b5b700b0e3e1f8fd16cc5980eee87',
     abi: [ [Object] ],
     sayHello:
      { [Function: bound ]
        request: [Function: bound ],
        call: [Function: bound ],
        sendTransaction: [Function: bound ],
        estimateGas: [Function: bound ],
        getData: [Function: bound ],
        '': [Circular] },
     allEvents: [Function: bound ] },
  sayHello:
   { [Function]
     call: [Function],
     sendTransaction: [Function],
     request: [Function: bound ],
     estimateGas: [Function] },
  sendTransaction: [Function],
  send: [Function],
  allEvents: [Function: bound ],
  address: '0x9fac2e57170b5b700b0e3e1f8fd16cc5980eee87',
  transactionHash: null }
truffle(development)>
truffle(development)> contract.sayHello.call()
'HelloWorld'

讲解

HelloWorld.deployed().then(instance => contract = instance)

truffle console中预载了truffle-contract函数库,以方便操作部署到区块链上的合约。

这边使用HelloWorld.deployed().then语句来取得HelloWorld合约的Instance(实例),并存到contract变量中,以方便后续的调用。

上面用的是Javascript ES6+的语法,这句也可以写成:

HelloWorld.deployed().then(instance => {contract = instance});

还可以用 ES5 的写法(直接copy请去掉换行符):

HelloWorld.deployed().then(function(instance) {
  hello = instance;
});
truffle(development)> contract.sayHello.call()
'Hello World'

我们已写好并部署完成了第一个智能合约,也验证了合约确实可以运作
加入新方法
我们在HelloWorld.sol中再加入一个echo方法,echo方法接受输入一个参数,并回传传送的参数。

function echo(string name) constant returns (string) {
    return name;
}

新的echo方法中传入了一个name参数。我们也为echo方法加入一个constant声明,表示调用这个方法并不会改变区块链的状态。如此一来,透过truffle-contract来调用此方法时,会自动选用call来呼叫,也不需要额外提供 gas。

由于更新了合约内容,我们需要先重新新编译一次,将编译结果部署到ganache-cli上,再透过truffle console执行看看结果。
待续…

你可能感兴趣的:(框架搭建)