Truffle3.0集成NodeJS并完全跑通(附詳細(xì)實(shí)例,可能的錯(cuò)誤)

升級(jí)到Truffle3.0

如果之前安裝的是Truffle2.0版本,需要主動(dòng)升級(jí)到Truffle3.0,兩者的語(yǔ)法變化有點(diǎn)大。

由于Truffle是一個(gè)命令行工具,需要更新全局空間安裝的Truffle

$ sudo npm update -g truffle

注意需要root權(quán)限運(yùn)行命令,否則可能會(huì)報(bào)錯(cuò)無(wú)足夠的訪問(wèn)權(quán)限,導(dǎo)致升級(jí)失敗。

安裝成功后,可以通過(guò)版本命令查看當(dāng)前的版本,如出現(xiàn)下述類似字樣說(shuō)明升級(jí)成功:

$ truffle version
Truffle v3.1.2

初始化工程

使用Truffle3.0初始化工程

我們創(chuàng)建一個(gè)新工程目錄,并在truffle3目錄內(nèi)初始化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

我們創(chuàng)建了一個(gè)新工程目錄truffle3,進(jìn)入到這個(gè)目錄,使用truffle init命令,初始化了一個(gè)全新的Truffle 3.0的工程,工程目錄如下:

truffle3-project.jpg

集成NodeJS

truffle console命令會(huì)默認(rèn)集成web3,合約抽象層。如果想要在自已的NodeJS環(huán)境使用Truffle合約,就要手動(dòng)集成這兩個(gè)模塊。在集成前,我們需要?jiǎng)?chuàng)建工程的npm包管理環(huán)境,首先進(jìn)入truffle3工程目錄,使用npm init來(lái)初始化工程的npm包管理環(huán)境:

$ 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

如果不進(jìn)行npm init初始化,就進(jìn)行后續(xù)模塊安裝,會(huì)報(bào)如下錯(cuò)誤:

$ 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.

由于沒(méi)有包管理環(huán)境,所以對(duì)package.json的包依賴寫入會(huì)失敗。報(bào)錯(cuò)npm WARN enoent ENOENT: no such file or directory, open '/Users/TryBlockchain/package.json'。要解決這個(gè)問(wèn)題,需要使用npm init來(lái)初始化當(dāng)前工程的包管理環(huán)境。

安裝NodeJS中用到的Truffle合約抽象層運(yùn)行環(huán)境

這個(gè)工具是Truffle提供的,用于在NodeJS和瀏覽器中集成Truffle的合約抽象運(yùn)行環(huán)境[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運(yùn)行時(shí)需要的web3環(huán)境

$ 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模塊。如果沒(méi)有集成web3環(huán)境,就跑相關(guān)的代碼,可能會(huì)報(bào)下述錯(cuò):

$ 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

創(chuàng)建自己的合約文件

新增加測(cè)試合約

truffle3/contracts目錄下創(chuàng)建測(cè)試合約文件Test.sol

pragma solidity ^0.4.4;

contract Test{
    function f() returns (string){
        return "method f()";
    }
    function g() returns (string){
        return "method g()";
    }
}

在上述代碼中,我們提供兩個(gè)函數(shù),f()g()。分別返回用于說(shuō)明它們是哪個(gè)函數(shù)的返回結(jié)果的字符串說(shuō)明。

增加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");聲明一個(gè)新的合約文件實(shí)例并命名為Test;增加的另一行內(nèi)容deployer.deploy(Test);用于將Test進(jìn)行部署。

編譯合約

下面我們使用truffle migrate --reset來(lái)強(qiáng)制重編譯并發(fā)布所有合約,由于合約移植是懶編譯的,如果發(fā)現(xiàn)已經(jīng)發(fā)布過(guò),且發(fā)布的版本號(hào)沒(méi)有變化就不會(huì)再發(fā)布,所以使用--reset。請(qǐng)務(wù)必弄清楚為何使用--reset再使用這個(gè)命令[2]。運(yùn)行truffle migrate前,需要確認(rèn)節(jié)點(diǎn)處于運(yùn)行狀態(tài)。

$ 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()方法
//請(qǐng)務(wù)必使用你自己編譯的.json文件內(nèi)容
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);

//沒(méi)有默認(rèn)地址,會(huì)報(bào)錯(cuò)
//UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 3): Error: invalid address
//務(wù)必設(shè)置為自己的錢包地址,如果不知道,查看自己的客戶端啟動(dòng)時(shí),觀察打印到控制臺(tái)的地址
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");

//省略了無(wú)關(guān)代碼
//合約初始化
var Test = contract(/*合約JSON*/);

//設(shè)置連接
Test.setProvider(provider);

在上例中,我們先通過(guò)var Web3 = require('web3');引入依賴,并初始化一個(gè)實(shí)例Web3,并為實(shí)例設(shè)置了HttpProvider。

truffle-contractcontract()方法

要在NodeJS初始化Truffle編譯好的合約,要使用contract()方法。請(qǐng)將Truffle3.0編譯后的.json文件,一般在build/contracts/Test.json。請(qǐng)將此文件的內(nèi)容放入contract()的括號(hào)內(nèi)。

var contract = require("truffle-contract");

//請(qǐng)使用使用Truffle3.0編譯的.json文件內(nèi)容
var Test = contract(/*參數(shù)是`JSON`對(duì)象,放入Truffle3.0生成的.json文件內(nèi)容*/)

然后使用.deployed()at(/*某個(gè)地址*/)來(lái)進(jìn)行調(diào)用[1]

contract()引入的JSON定義有問(wèn)題

如果引入的JSON數(shù)據(jù)有問(wèn)題,你可能會(huì)看到下面的錯(cuò)誤:

$ 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)

如果你出現(xiàn)了上述報(bào)錯(cuò),請(qǐng)?jiān)俅未_認(rèn)是否原封不動(dòng)的把合約編譯后的.json文件的內(nèi)容,復(fù)制進(jìn)contract()的括號(hào)內(nèi)的,不要加任何東西,因?yàn)?code>.json文件內(nèi)就是一個(gè)JSON對(duì)象。

默認(rèn)帳戶地址

truffle-contract框架默認(rèn)沒(méi)有讀取coinbase的默認(rèn)地址,所以需要按如下方式主動(dòng)設(shè)置:

//沒(méi)有默認(rèn)地址,會(huì)報(bào)錯(cuò)
//UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 3): Error: invalid address
Test.defaults({
  from : "0x299127d72e28cb92d09f856aaedeb139d1e7e74a"
});

否則會(huì)報(bào)錯(cuò)UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 3): Error: invalid address[3]。

語(yǔ)法注意

對(duì)于新的Truffle3.0語(yǔ)法,需要注意的是函數(shù)調(diào)用方式要遵循調(diào)用規(guī)則[4]。對(duì)于一個(gè)不會(huì)改寫區(qū)塊鏈狀態(tài)的f()函數(shù),使用instance.f.call();;而對(duì)于一個(gè)會(huì)改寫區(qū)塊鏈狀態(tài)的函數(shù)f(),使用instance.f()。底層在實(shí)現(xiàn)調(diào)用上,會(huì)使用不同gas計(jì)算方式。

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);
});

如果對(duì)于一個(gè)不會(huì)改寫狀態(tài)f(),使用instance.f()會(huì)返回對(duì)應(yīng)的交易狀態(tài)結(jié)果。

$ 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: [] }

關(guān)于作者

專注基于以太坊的相關(guān)區(qū)塊鏈技術(shù),了解以太坊,Solidity,Truffle。
博客:http://me.tryblockchain.org


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

  2. 5. 移植詳解 ?

  3. 關(guān)于invalid address的報(bào)錯(cuò),http://ethereum.stackexchange.com/questions/12957/truffle-invalid-address 報(bào)這個(gè)錯(cuò)的可能情況: http://www.bullraider.com/ethereum/tutorials/342-understanding-invalid-address-error-in-dapps-or-geth-console ?

  4. 合約交互詳解 ?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容