美文网首页Blockchain区块链研习社区块链研究
Truffle3.0集成NodeJS并完全跑通(附详细实例,可能

Truffle3.0集成NodeJS并完全跑通(附详细实例,可能

作者: TryBlockchain | 来源:发表于2017-04-03 21:35 被阅读3652次

    升级到Truffle3.0

    如果之前安装的是Truffle2.0版本,需要主动升级到Truffle3.0,两者的语法变化有点大。

    由于Truffle是一个命令行工具,需要更新全局空间安装的Truffle

    $ sudo npm update -g truffle
    

    注意需要root权限运行命令,否则可能会报错无足够的访问权限,导致升级失败。

    安装成功后,可以通过版本命令查看当前的版本,如出现下述类似字样说明升级成功:

    $ truffle version
    Truffle v3.1.2
    

    初始化工程

    使用Truffle3.0初始化工程

    我们创建一个新工程目录,并在truffle3目录内初始化Truffle框架。

    $ mkdir truffle3 && cd truffle3
    $ truffle init
    Downloading project...
    Project initialized.
    
      Documentation: http://truffleframework.com/docs
    
    Commands:
    
      Compile: truffle compile
    
      Migrate: truffle migrate
      Test:    truffle test
    

    我们创建了一个新工程目录truffle3,进入到这个目录,使用truffle init命令,初始化了一个全新的Truffle 3.0的工程,工程目录如下:

    truffle3-project.jpg

    集成NodeJS

    truffle console命令会默认集成web3,合约抽象层。如果想要在自已的NodeJS环境使用Truffle合约,就要手动集成这两个模块。在集成前,我们需要创建工程的npm包管理环境,首先进入truffle3工程目录,使用npm init来初始化工程的npm包管理环境:

    $ npm init
    This utility will walk you through creating a package.json file.
    It only covers the most common items, and tries to guess sensible defaults.
    
    See `npm help json` for definitive documentation on these fields
    and exactly what they do.
    
    Use `npm install <pkg> --save` afterwards to install a package and
    save it as a dependency in the package.json file.
    
    
    Press ^C at any time to quit.
    name: (truffle3) TruffleForTest
    Sorry, name can no longer contain capital letters.
    name: (truffle3) truffle3
    version: (1.0.0) 1.0.0
    description: This is a sample project for integrate truffle 3.0 with nodejs.
    entry point: (truffle.js) main.js
    test command: truffle3
    git repository:main.js
    keywords: truffle3.0
    author: TryBlockchain
    license: (ISC)
    About to write to /Users/TryBlockchain/develop/blockchain_workspace/truffle3/package.json:
    
    {
      "name": "truffle3",
      "version": "1.0.0",
      "description": "This is a sample project for integrate truffle 3.0 with nodejs.",
    
      "main": "main.js",
      "directories": {
        "test": "test"
      },
      "scripts": {
        "test": "truffle3"
      },
      "keywords": [
        "truffle3.0"
      ],
      "author": "TryBlockchain",
      "license": "ISC"
    }
    
    
    Is this ok? (yes) yes
    

    如果不进行npm init初始化,就进行后续模块安装,会报如下错误:

    $ npm install truffle-contract
    /Users/TryBlockchain
    └─┬ truffle-contract@1.1.10
      ├─┬ ethjs-abi@0.1.9
      │ ├── bn.js@4.11.6
      │ ├── js-sha3@0.5.5
      │ └─┬ number-to-bn@1.7.0
      │   ├── bn.js@4.11.6  deduped
      │   └─┬ strip-hex-prefix@1.0.0
      │     └── is-hex-prefixed@1.0.0
    
      ├── truffle-blockchain-utils@0.0.1
      ├─┬ truffle-contract-schema@0.0.5
      │ └── crypto-js@3.1.9-1
      └─┬ web3@0.16.0
        └── bignumber.js@2.0.7  (git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2)
    
    npm WARN enoent ENOENT: no such file or directory, open '/Users/TryBlockchain/package.json'
    npm WARN TryBlockchain No description
    npm WARN TryBlockchain No repository field.
    npm WARN TryBlockchain No README data
    npm WARN TryBlockchain No license field.
    

    由于没有包管理环境,所以对package.json的包依赖写入会失败。报错npm WARN enoent ENOENT: no such file or directory, open '/Users/TryBlockchain/package.json'。要解决这个问题,需要使用npm init来初始化当前工程的包管理环境。

    安装NodeJS中用到的Truffle合约抽象层运行环境

    这个工具是Truffle提供的,用于在NodeJS和浏览器中集成Truffle的合约抽象运行环境[1]

    $ npm install truffle-contract
    truffle3@1.0.0 /Users/TryBlockchain/develop/blockchain_workspace/truffle3
    └─┬ truffle-contract@1.1.10
      ├─┬ ethjs-abi@0.1.9
      │ ├── bn.js@4.11.6
      │ ├── js-sha3@0.5.5
      │ └─┬ number-to-bn@1.7.0
      │   ├── bn.js@4.11.6  deduped
      │   └─┬ strip-hex-prefix@1.0.0
    
      │     └── is-hex-prefixed@1.0.0
      ├─┬ truffle-blockchain-utils@0.0.1
      │ └─┬ web3@0.18.2
      │   ├── bignumber.js@2.0.7  (git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2)
      │   ├── crypto-js@3.1.8  deduped
      │   ├── utf8@2.1.2  deduped
      │   ├── xhr2@0.1.4
      │   └── xmlhttprequest@1.8.0  deduped
      ├─┬ truffle-contract-schema@0.0.5
      │ └── crypto-js@3.1.9-1
      └─┬ web3@0.16.0
        ├── bignumber.js@2.0.7  (git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2)
        ├── crypto-js@3.1.8
        ├── utf8@2.1.2
        └── xmlhttprequest@1.8.0
    

    安装NodeJS中用到的Truffle运行时需要的web3环境

    $ npm install web3
    - bignumber.js@2.0.7 node_modules/web3/node_modules/bignumber.js
    truffle3@1.0.0 /Users/TryBlockchain/develop/blockchain_workspace/truffle3
    └── web3@0.18.2
    

    我们使用npm install web3即可安装web3模块。如果没有集成web3环境,就跑相关的代码,可能会报下述错:

    $ node main.js
    /Users/TryBlockchain/develop/blockchain_workspace/truffle3/main/main.js:4
    var provider = new Web3.providers.HttpProvider("http://localhost:8545");
                       ^
    
    ReferenceError: Web3 is not defined
        at Object.<anonymous> (/Users/TryBlockchain/develop/blockchain_workspace/truffle3/main/main.js:4:20)
        at Module._compile (module.js:571:32)
        at Object.Module._extensions..js (module.js:580:10)
        at Module.load (module.js:488:32)
        at tryModuleLoad (module.js:447:12)
        at Function.Module._load (module.js:439:3)
        at Module.runMain (module.js:605:10)
        at run (bootstrap_NodeJS:420:7)
        at startup (bootstrap_NodeJS:139:9)
        at bootstrap_NodeJS:535:3
    

    创建自己的合约文件

    新增加测试合约

    truffle3/contracts目录下创建测试合约文件Test.sol

    pragma solidity ^0.4.4;
    
    contract Test{
        function f() returns (string){
            return "method f()";
        }
        function g() returns (string){
            return "method g()";
        }
    }
    
    

    在上述代码中,我们提供两个函数,f()g()。分别返回用于说明它们是哪个函数的返回结果的字符串说明。

    增加deploy配置

    修改migrations/2_deploy_contracts.js为如下:

    var ConvertLib = artifacts.require("./ConvertLib.sol");
    var MetaCoin = artifacts.require("./MetaCoin.sol");
    var Test = artifacts.require("./Test.sol");
    
    module.exports = function(deployer) {
      deployer.deploy(ConvertLib);
      deployer.link(ConvertLib, MetaCoin);
      deployer.deploy(MetaCoin);
      deployer.deploy(Test);
    };
    

    上述代码主要增加两行,一行为var Test = artifacts.require("./Test.sol");声明一个新的合约文件实例并命名为Test;增加的另一行内容deployer.deploy(Test);用于将Test进行部署。

    编译合约

    下面我们使用truffle migrate --reset来强制重编译并发布所有合约,由于合约移植是懒编译的,如果发现已经发布过,且发布的版本号没有变化就不会再发布,所以使用--reset。请务必弄清楚为何使用--reset再使用这个命令[2]。运行truffle migrate前,需要确认节点处于运行状态。

    $ truffle migrate --reset
    Using network 'development'.
    
    Running migration: 1_initial_migration.js
    
      Replacing Migrations...
      Migrations: 0xdc59c5de4e7b1dcf23f864425a704020e53666b5
    Saving successful migration to network...
    Saving artifacts...
    Running migration: 2_deploy_contracts.js
      Replacing ConvertLib...
      ConvertLib: 0x19cf958fede2e0f082cbcf5629f1a1344b221bf3
      Linking ConvertLib to MetaCoin
      Replacing MetaCoin...
      MetaCoin: 0x39073d502491f57537f999584071691d19cf5f24
      Replacing Test...
      Test: 0x8ca770415902e5a64ef53062b5ba85626c3dd5dc
    Saving successful migration to network...
    Saving artifacts...
    

    使用NodeJS集成Truffle3.0代码完整DEMO

    var Web3 = require('web3');
    var contract = require("truffle-contract");
    
    var provider = new Web3.providers.HttpProvider("http://localhost:8545");
    
    //使用truffle-contract包的contract()方法
    //请务必使用你自己编译的.json文件内容
    var Test = contract({
      "contract_name": "Test",
      "abi": [
        {
          "constant": false,
          "inputs": [],
          "name": "f",
          "outputs": [
            {
              "name": "",
              "type": "string"
            }
          ],
          "payable": false,
          "type": "function"
        },
        {
          "constant": false,
          "inputs": [],
          "name": "g",
          "outputs": [
            {
              "name": "",
              "type": "string"
            }
          ],
          "payable": false,
          "type": "function"
        }
      ],
      "unlinked_binary": "0x606060405234610000575b6101ff806100196000396000f300606060405263ffffffff60e060020a60003504166326121ff0811461002f578063e2179b8e146100bc575b610000565b346100005761003c610149565b604080516020808252835181830152835191928392908301918501908083838215610082575b80518252602083111561008257601f199092019160209182019101610062565b505050905090810190601f1680156100ae5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b346100005761003c61018e565b604080516020808252835181830152835191928392908301918501908083838215610082575b80518252602083111561008257601f199092019160209182019101610062565b505050905090810190601f1680156100ae5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b604080516020818101835260009091528151808301909252600a82527f6d6574686f642066282900000000000000000000000000000000000000000000908201525b90565b604080516020818101835260009091528151808301909252600a82527f6d6574686f642067282900000000000000000000000000000000000000000000908201525b905600a165627a7a72305820c238bd4de6aa330fcc88946b9948bc265c7ac1408dc5c8b7ee6e648413ae540f0029",
      "networks": {
        "1489826524891": {
          "events": {},
          "links": {},
          "address": "0x9db90af99faa32ed14dccfb19326e917efac456b",
          "updated_at": 1489827968151
        }
      },
      "schema_version": "0.0.5",
      "updated_at": 1489827968151
    });
    
    Test.setProvider(provider);
    
    //没有默认地址,会报错
    //UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 3): Error: invalid address
    //务必设置为自己的钱包地址,如果不知道,查看自己的客户端启动时,观察打印到控制台的地址
    Test.defaults({
      from : "0x299127d72e28cb92d09f856aaedeb139d1e7e74a"
    });
    
    
    var instance;
    Test.deployed().then(function(contractInstance) {
      instance = contractInstance;
      return instance.f.call();
    }).then(function(result){
      console.log(result);
      return instance.g.call();
    }).then(function(result){
      console.log(result);
    });
    
    

    集成示例详解

    引入web3

    要在NodeJS中使用Truffle,我们要先引入web3

    var Web3 = require('web3');
    var provider = new Web3.providers.HttpProvider("http://localhost:8545");
    
    //省略了无关代码
    //合约初始化
    var Test = contract(/*合约JSON*/);
    
    //设置连接
    Test.setProvider(provider);
    

    在上例中,我们先通过var Web3 = require('web3');引入依赖,并初始化一个实例Web3,并为实例设置了HttpProvider

    truffle-contractcontract()方法

    要在NodeJS初始化Truffle编译好的合约,要使用contract()方法。请将Truffle3.0编译后的.json文件,一般在build/contracts/Test.json。请将此文件的内容放入contract()的括号内。

    var contract = require("truffle-contract");
    
    //请使用使用Truffle3.0编译的.json文件内容
    var Test = contract(/*参数是`JSON`对象,放入Truffle3.0生成的.json文件内容*/)
    

    然后使用.deployed()at(/*某个地址*/)来进行调用[1]

    contract()引入的JSON定义有问题

    如果引入的JSON数据有问题,你可能会看到下面的错误:

    $ node main.js
    /Users/TryBlockchain/develop/blockchain_workspace/truffle3/node_modules/truffle-contract/node_modules/web3/lib/web3/contract.js:56
        contract.abi.filter(function (json) {
    
                    ^
    
    TypeError: Cannot read property 'filter' of undefined
        at addFunctionsToContract (/Users/TryBlockchain/develop/blockchain_workspace/truffle3/node_modules/truffle-contract/node_modules/web3/li
    b/web3/contract.js:56:17)
        at ContractFactory.at (/Users/TryBlockchain/develop/blockchain_workspace/truffle3/node_modules/truffle-contract/node_modules/web3/lib/we
    b3/contract.js:255:5)
        at TruffleContract.Contract (/Users/TryBlockchain/develop/blockchain_workspace/truffle3/node_modules/truffle-contract/contract.js:257:33
    )
        at new TruffleContract (/Users/TryBlockchain/develop/blockchain_workspace/truffle3/node_modules/truffle-contract/contract.js:572:25)
        at Function.at (/Users/TryBlockchain/develop/blockchain_workspace/truffle3/node_modules/truffle-contract/contract.js:390:22)
        at Object.<anonymous> (/Users/TryBlockchain/develop/blockchain_workspace/truffle3/main/main.js:54:6)
        at Module._compile (module.js:571:32)
        at Object.Module._extensions..js (module.js:580:10)
        at Module.load (module.js:488:32)
        at tryModuleLoad (module.js:447:12)
    

    如果你出现了上述报错,请再次确认是否原封不动的把合约编译后的.json文件的内容,复制进contract()的括号内的,不要加任何东西,因为.json文件内就是一个JSON对象。

    默认帐户地址

    truffle-contract框架默认没有读取coinbase的默认地址,所以需要按如下方式主动设置:

    //没有默认地址,会报错
    //UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 3): Error: invalid address
    Test.defaults({
      from : "0x299127d72e28cb92d09f856aaedeb139d1e7e74a"
    });
    

    否则会报错UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 3): Error: invalid address[3]

    语法注意

    对于新的Truffle3.0语法,需要注意的是函数调用方式要遵循调用规则[4]。对于一个不会改写区块链状态的f()函数,使用instance.f.call();;而对于一个会改写区块链状态的函数f(),使用instance.f()。底层在实现调用上,会使用不同gas计算方式。

    var instance;
    Test.deployed().then(function(contractInstance) {
      instance = contractInstance;
      return instance.f.call();
    }).then(function(result){
      console.log(result);
      return instance.g.call();
    }).then(function(result){
      console.log(result);
    });
    

    如果对于一个不会改写状态f(),使用instance.f()会返回对应的交易状态结果。

    $ node main.js
    { tx: '0x2ac645310278d971e3911e8f880947105f582aa4eab3d3d66d14c95333391ac9',
      receipt:
    
       { transactionHash: '0x2ac645310278d971e3911e8f880947105f582aa4eab3d3d66d14c95333391ac9',
         transactionIndex: 0,
         blockHash: '0x69a6788032c7bef12d6d51bc045548fa9edb0665bb0fbcf9cf55d30f9744cd61',
         blockNumber: 29,
         gasUsed: 21803,
         cumulativeGasUsed: 21803,
         contractAddress: null,
         logs: [] },
      logs: [] }
    { tx: '0x65aa2c4da73ef5a17221c26e74b9b329bdc353856564f8d1f49c07f6dcd055ea',
      receipt:
       { transactionHash: '0x65aa2c4da73ef5a17221c26e74b9b329bdc353856564f8d1f49c07f6dcd055ea',
         transactionIndex: 0,
         blockHash: '0x837ec6a3df2cc4d9a8ccf8d77c14b88a13b0053a5149a74c1a984fe88a70eaa8',
         blockNumber: 30,
         gasUsed: 21825,
         cumulativeGasUsed: 21825,
         contractAddress: null,
         logs: [] },
      logs: [] }
    

    关于作者

    专注基于以太坊的相关区块链技术,了解以太坊,Solidity,Truffle。
    博客:http://me.tryblockchain.org


    1. Truffle contract的github地址及文档: https://github.com/trufflesuite/truffle-contract

    2. 5. 移植详解

    3. 关于invalid address的报错,http://ethereum.stackexchange.com/questions/12957/truffle-invalid-address 报这个错的可能情况: http://www.bullraider.com/ethereum/tutorials/342-understanding-invalid-address-error-in-dapps-or-geth-console

    4. 合约交互详解

    相关文章

      网友评论

      本文标题:Truffle3.0集成NodeJS并完全跑通(附详细实例,可能

      本文链接:https://www.haomeiwen.com/subject/nuwoottx.html