Truffle 4.0、Geth 1.7.2、TestRPC在私有鏈上搭建智慧合約

Lion發表於2017-11-09

目錄

1、什麼是 Truffle?

  Truffle 是最流行的開發框架,能夠在本地編譯、部署智慧合約,使命是讓開發更容易。

  Truffle 需要以太坊客戶端支援,需要支援標準的JSON RPC API。

2、適合 Truffle 開發的客戶端

  有許多的以太坊客戶端可以選擇。我們推薦在開發和部署時使用不同客戶端。

  適用開發的客戶端

  適用正式釋出的客戶端

  當開發基於 Truffle 的應用時,推薦使用EthereumJS TestRPC。它是一個完整的在記憶體中的區塊鏈僅僅存在於你開發的裝置上。相對於 GethTestRPC 它在執行交易時是實時返回,而不等待預設的出塊時間,這樣你可以快速驗證你新寫的程式碼,當出現錯誤時,也能即時反饋給你。它同時還是一個支援自動化測試的功能強大的客戶端。Truffle 充分利用它的特性,能將測試執行時間提速近90%。

  

3、Truffle的原始碼地址

  https://github.com/trufflesuite/truffle

  

4、如何安裝?

  接下來的例子,我們會使用 Truffle 分別連線 GethTestRPC 測試智慧合約的部署,首先我們先分別安裝TruffleGethTestRPC

  

4.1、安裝 Go-Ethereum 1.7.2

  Go-Ethereum 的安裝參考這篇文章:使用 Go-Ethereum 1.7.2搭建以太坊私有鏈

  

4.2、安裝 Truffle 4.0

  依賴環境:

  • NodeJS 5.0+
  • Windows,Linux,或Mac OS X

  安裝很簡單:

npm install -g truffle@4.0.0

  檢視安裝的版本:

➜ /Users/lion >truffle version
Truffle v4.0.0 (core: 4.0.0)
Solidity v0.4.18 (solc-js)

  

4.3、安裝 TestRPC

➜ /Users/lion >npm install -g ethereumjs-testrpc
/usr/local/bin/testrpc -> /usr/local/lib/node_modules/ethereumjs-testrpc/build/cli.node.js
+ ethereumjs-testrpc@6.0.1
added 1 package and updated 2 packages in 10.648s

  

5、使用 Truffle 進行智慧合約的開發

5.1、初始化一個 Truffle 專案

  通過truffle init命令,可以初始化一個預設的以太坊代幣合約專案,後面我們可以通過這個專案來快速學習:

➜ /Users/lion/my_project/_eth >mkdir test_truffle
➜ /Users/lion/my_project/_eth >cd test_truffle
➜ /Users/lion/my_project/_eth/test_truffle >truffle init

Downloading...
Unpacking...
Setting up...
Unbox successful. Sweet!

Commands:

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

  完成後,你將擁有如下目錄:

  • contracts 智慧合約目錄
  • migrations 釋出指令碼目錄
  • test 存放測試檔案
  • truffle.js Truffle的配置檔案

  

5.2、編譯合約

  要編譯合約,使用truffle compile命令,可以將原始程式碼編譯成以太坊認可的位元組碼:

➜ /Users/lion/my_project/_eth/test_truffle >truffle compile
Compiling ./contracts/Migrations.sol...
Writing artifacts to ./build/contracts

  Truffle僅預設編譯自上次編譯後被修改過的檔案,來減少不必要的編譯。如果你想編譯全部檔案,可以使用--compile-all選項

truffle compile --compile-all

  Truffle需要定義的合約名稱和檔名準確匹配,這種匹配是區分大小寫的,也就是說大小寫也要一致。推薦大寫每一個開頭字母。

  檔案之間的相互依賴,可以使用import進行合約間的引用,Truffle將會按正確順序依次編譯合約,並在需要的時候自動關聯庫。例如:

import "./AnotherContract.sol";

  

5.3、建立一個 Hello mshk.top 的合約並編譯

  在contracts目錄中新建一個Hello_mshk_top.sol檔案,程式碼如下:

pragma solidity ^0.4.17;

contract Hello_mshk_top {

  //say hello mshk.top
  function say() public pure returns (string) {
    return "Hello mshk.top";
  }

  //print name
  function print(string name) public pure returns (string) {
    return name;
  }
}

  程式碼中有兩個方法:say()方法是輸出一段文字Hello mshk.topprint(string name)方法是輸出傳入的內容。

  編輯migrations/1_initial_migration.js部署指令碼,將我們剛才建立的Hello_mshk_top.sol檔案設定到釋出配置檔案中,內容如下:

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

  將專案使用truffle compile命令進行編譯,編譯後的檔案都放在了./build/contracts目錄下:

➜ /Users/lion/my_project/_eth/test_truffle >truffle compile
Compiling ./contracts/Hello_mshk_top.sol...
Compiling ./contracts/Migrations.sol...
Writing artifacts to ./build/contracts

  Hello_mshk_top.sol編譯後的檔案是./build/contracts/Hello_mshk_top.json中,後面在部署到geth中,我們會用到。

  

6、部署智慧合約

  編輯truffle.js配置檔案,設定我們稍後要部署智慧合約的位置,內容如下:

module.exports = {
    networks: {
        development: {
          host: "localhost",
          port: 8545,
          network_id: "*"
        }
    }
};

  接下來,我們會使用上面的智慧合約,分別在testRPCgeth中進行部署測試。

  truffle的智慧合約專案部署,使用下面的命令:

truffle migrate

  這個命令會執行所有migrations目錄下的js檔案。如果之前執行過truffle migrate命令,再次執行,只會部署新的js檔案,如果沒有新的js檔案,不會起任何作用。如果使用--reset引數,則會重新的執行所有指令碼的部署。

  如果要部署到指定的網路,可以使用--network引數,例如:

truffle migrate --network live

  多個網路的配置格式如下:

networks: {
  development: {
    host: "localhost",
    port: 8545,
    network_id: "*" // match any network
  },
  live: {
    host: "178.25.19.88", // Random IP for example purposes (do not use)
    port: 80,
    network_id: 1,        // Ethereum public network
    // optional config values:
    // gas  Gas limit used for deploys. Default is 4712388
    // gasPrice Gas price used for deploys. Default is 100000000000 (100 Shannon).
    // from - default address to use for any transaction Truffle makes during migrations
    // provider - web3 provider instance Truffle should use to talk to the Ethereum network.
    //          - if specified, host and port are ignored.
  }
}

  

6.1、將智慧合約部署到 TestRPC 中測試

6.1.2、啟動 TestRPC

  直接輸入testrpc命令,就可以呼叫起 TestRPC 客戶端,啟動 testrpc 經後,會預設建立10個帳號,Available Accounts是帳號列表,Private Keys是相對應的帳號金鑰:

➜ /Users/lion >testrpc --gasLimit 0x800000000
EthereumJS TestRPC v6.0.1 (ganache-core: 2.0.0)

Available Accounts
==================
(0) 0x74650142c29e358b8f94a8c5d43345649009a4cd
......

Private Keys
==================
(0) f11fa29910cd639aeb6de6126f2f16e091c1da51956fefccafca0afc476fbc41
......
HD Wallet
==================
Mnemonic:      inquiry sense exit ice craft evoke april gym settle social cat uniform
Base HD Path:  m/44'/60'/0'/0'/{account_index}

Gas Limit
==================
34359738368

Listening on localhost:8545

  

6.1.3、通過 truffle migrate 命令,對合約進行部署

  使用truffle migrate命令,釋出專案:

➜ /Users/lion/my_project/_eth/test_truffle >truffle migrate
Using network 'development'.

Running migration: 1_initial_migration.js
  Deploying Migrations...
  ... 0xd9e5fa242d29362e57e3da7b0bf6f71b72767972fc15240ed3a02d341e814a44
  Migrations: 0x4bedd1bb517ff9a54f6f3df8eba821ff16a4109b
  Deploying Hello_mshk_top...
  ... 0xc22ff050e189c2561d40250077ee4bf628f957899dfa8d0b5fa50e3ab7a896b0
  Hello_mshk_top: 0xa7ef5037ff81d7932e01b68a503ca4587f00b35c
Saving successful migration to network...
  ... 0x49505a54042f5f74146fbfafef63dd408cb0a7a0c66214ebbaa3217e443d792a
Saving artifacts...

  

6.1.4、測試部署成功的智慧合約

  輸入以下命令開啟truffle控制檯,測試剛才我們部署的Hello_mshk_top合約:

truffle(development)> var contract;
undefined
truffle(development)> Hello_mshk_top.deployed().then(function(instance){contract= instance;});
undefined
truffle(development)> contract.say()
'Hello mshk.top'
truffle(development)> contract.print("https://mshk.top")
'https://mshk.top'

  var contractjavascript語法一樣,表示宣告一個contract變數。Hello_mshk_top.deployed().then(function(instance){contract= instance;})表示,將Hello_mshk_top合約主體,傳遞給contract變數。後面我們就可以直接使用變數contract分別呼叫say()方法和print(''),得到我們想要的結果。

  

6.2、將智慧合約部署到 Geth 1.7.2 私有鏈

6.2.1、新建 Geth 的創世區塊檔案,並初始化

  新建一個test_truffle_geth目錄,同時新建我們的創世區塊檔案genesis.json

➜ /Users/lion/my_project/_eth >mkdir test_truffle_geth
➜ /Users/lion/my_project/_eth >cd test_truffle_geth
➜ /Users/lion/my_project/_eth/test_truffle_geth >vi genesis.json

  genesis.json:

{
  "config": {
        "chainId": 10,
        "homesteadBlock": 0,
        "eip155Block": 0,
        "eip158Block": 0
    },
  "coinbase"   : "0x0000000000000000000000000000000000000000",
  "difficulty" : "0x20000",
  "extraData"  : "",
  "gasLimit"   : "0x8000000",
  "nonce"      : "0x0000000000000042",
  "mixhash"    : "0x0000000000000000000000000000000000000000000000000000000000000000",
  "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
  "timestamp"  : "0x00",
  "alloc": {}
}

  初始化創世區塊

➜ /Users/lion/my_project/_eth/test_truffle_geth >geth init ./genesis.json --datadir "./chain"
WARN [11-07|10:17:11] No etherbase set and no accounts found as default
INFO [11-07|10:17:11] Allocated cache and file handles         database=/Users/lion/my_project/_eth/test_truffle_geth/chain/geth/chaindata cache=16 handles=16
INFO [11-07|10:17:11] Writing custom genesis block
INFO [11-07|10:17:11] Successfully wrote genesis state         database=chaindata                                                          hash=ecf271…5269d6
INFO [11-07|10:17:11] Allocated cache and file handles         database=/Users/lion/my_project/_eth/test_truffle_geth/chain/geth/lightchaindata cache=16 handles=16
INFO [11-07|10:17:11] Writing custom genesis block
INFO [11-07|10:17:11] Successfully wrote genesis state         database=lightchaindata                                                          hash=ecf271…5269d6

  

6.2.2、使用 RPC 方式執行 Geth

  使用rpc方式執行geth

➜ /Users/lion/my_project/_eth/test_truffle_geth >geth \
  --identity "mshk.top etherum" \
  --rpcaddr 0.0.0.0 \
  --rpc \
  --rpcport 8545 \
  --maxpeers 2 \
  --rpcapi "db,eth,net,web3,debug" \
  --networkid 100 \
  --datadir "./chain" \
  --nodiscover
WARN [11-07|10:21:56] No etherbase set and no accounts found as default
INFO [11-07|10:21:56] Starting peer-to-peer node               instance="Geth/mshk.top etherum/v1.7.2-stable-1db4ecdc/darwin-amd64/go1.9.1"
INFO [11-07|10:21:56] Allocated cache and file handles         database=/Users/lion/my_project/_eth/test_truffle_geth/chain/geth/chaindata cache=128 handles=1024
WARN [11-07|10:21:56] Upgrading database to use lookup entries
INFO [11-07|10:21:56] Initialised chain configuration          config="{ChainID: 10 Homestead: 0 DAO: <nil> DAOSupport: false EIP150: <nil> EIP155: 0 EIP158: 0 Byzantium: <nil> Engine: unknown}"
INFO [11-07|10:21:56] Disk storage enabled for ethash caches   dir=/Users/lion/my_project/_eth/test_truffle_geth/chain/geth/ethash count=3
INFO [11-07|10:21:56] Disk storage enabled for ethash DAGs     dir=/Users/lion/.ethash                                             count=2
INFO [11-07|10:21:56] Initialising Ethereum protocol           versions="[63 62]" network=100
INFO [11-07|10:21:56] Database deduplication successful        deduped=0
INFO [11-07|10:21:56] Loaded most recent local header          number=0 hash=ecf271…5269d6 td=131072
INFO [11-07|10:21:56] Loaded most recent local full block      number=0 hash=ecf271…5269d6 td=131072
INFO [11-07|10:21:56] Loaded most recent local fast block      number=0 hash=ecf271…5269d6 td=131072
INFO [11-07|10:21:56] Regenerated local transaction journal    transactions=0 accounts=0
INFO [11-07|10:21:56] Starting P2P networking
INFO [11-07|10:21:56] RLPx listener up                         self="enode://eee1025474554baf3d42dc72fb6f13df8246b5ed879ca6a7764d3147c422ca2d10eba1dc6a9e609d3535794668d1e064548550683a8c34cfefbcf879b9cbaf2b@[::]:30303?discport=0"
INFO [11-07|10:21:56] IPC endpoint opened: /Users/lion/my_project/_eth/test_truffle_geth/chain/geth.ipc
INFO [11-07|10:21:56] HTTP endpoint opened: http://0.0.0.0:8545
INFO [11-07|10:21:56] Mapped network port                      proto=tcp extport=30303 intport=30303 interface=NAT-PMP(10.0.0.1)

  
  啟動私有節點需要的引數:
| 引數名稱 | 引數描述 |
| ---------- | --------------------------------- |
| identity | 區塊鏈的標示,隨便填寫,用於標示目前網路的名字 |
| init | 指定創世塊檔案的位置,並建立初始塊 |
| datadir | 設定當前區塊鏈網路資料存放的位置 |
| port | 網路監聽埠 預設是30303 |
| rpc | 啟動rpc通訊,可以進行智慧合約的部署和除錯 |
| maxpeers | 網路節點的最大數量,預設是25 |
| rpcapi | 設定允許連線的rpc的客戶端,一般為db,eth,net,web3 |
| networkid | 設定當前區塊鏈的網路ID,用於區分不同的網路,是一個數字 |
| console | 啟動命令列模式,可以在Geth中執行命令 |
| dev | 開發者模式,帶除錯模式的專有網路 |
| nodiscover | 私有鏈地址,不會被網上看到 |

  
  rpc方式啟動geth以後,會一直停止在那裡,沒有辦法在geth中進行任何輸入。瀏覽一下我們剛才建立區塊鏈資料的資料夾,會發現有一個geth.ipc檔案。

➜ /Users/lion >ll /Users/lion/my_project/_eth/test_truffle_geth/chain
total 0
drwxr-xr-x  7 lion  staff  224 Nov  7 10:21 geth
srw-------  1 lion  staff    0 Nov  7 10:21 geth.ipc
drwx------  2 lion  staff   64 Nov  7 10:17 keystore

  然後用下面這個命令,進入geth控制檯:

➜ /Users/lion >geth attach ipc://Users/lion/my_project/_eth/test_truffle_geth/chain/geth.ipc
Welcome to the Geth JavaScript console!

instance: Geth/mshk.top etherum/v1.7.2-stable-1db4ecdc/darwin-amd64/go1.9.1
 modules: admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0

>

  

6.2.3、在 Geth 中新建帳戶,開始挖礦

  建立一個帳戶,並解鎖使用者一段時間(單位是秒),然後啟動挖礦

> web3.personal.newAccount("123456")
"0x0a67659a161410a4a1e0a5889ff05a1417915172"
> personal.unlockAccount(eth.accounts[0], "123456", 15000)
true
> miner.start(1)
null

  過一會後檢視下帳戶地址的餘額,將帳戶地址賦值給變數acc0,可以看到裡面有了以太幣:

> acc0 = web3.eth.accounts[0]
"0xc90747b99362c41fa89d2e7dea1b5b8d9567b741"
> web3.eth.getBalance(acc0)
415000000000000000000

  

6.2.4、在 Geth 中部署合約

  這時,我們就要用到剛剛編譯後的Hello_mshk_top.json檔案了,開啟https://www.bejson.com網址,把abi部分取出並轉義。然後在geth中輸入以下內容,將json轉義後的內容,賦值給mshk_abi變數:

mshk_abi=JSON.parse('[{\"constant\":true,\"inputs\":[{\"name\":\"name\",\"type\":\"string\"}],\"name\":\"print\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"pure\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"say\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"pure\",\"type\":\"function\"}]')

  會得到下面的返回值:

[{
    constant: true,
    inputs: [{
        name: "name",
        type: "string"
    }],
    name: "print",
    outputs: [{
        name: "",
        type: "string"
    }],
    payable: false,
    stateMutability: "pure",
    type: "function"
}, {
    constant: true,
    inputs: [],
    name: "say",
    outputs: [{
        name: "",
        type: "string"
    }],
    payable: false,
    stateMutability: "pure",
    type: "function"
}]

  找到Hello_mshk_top.json檔案中的bytecode部分,然後在geth中,將值賦值給mshk_bytecode變數,在geth中輸入以下內容:

mshk_bytecode="0x6060604052341561000f57600080fd5b6102488061001e6000396000f30060606040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806311114af114610051578063954ab4b214610127575b600080fd5b341561005c57600080fd5b6100ac600480803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919050506101b5565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100ec5780820151818401526020810190506100d1565b50505050905090810190601f1680156101195780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561013257600080fd5b61013a6101c5565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561017a57808201518184015260208101905061015f565b50505050905090810190601f1680156101a75780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101bd610208565b819050919050565b6101cd610208565b6040805190810160405280600e81526020017f48656c6c6f206d73686b2e746f70000000000000000000000000000000000000815250905090565b6020604051908101604052806000815250905600a165627a7a72305820aa448d81e0f4bf12f805920c9cefd0d3cc6f053d87dd8547663721256179ebcd0029"

  評估下建立合約需要的手續費是207296gas

> web3.eth.estimateGas({data: mshk_bytecode})
207296

  部署合約,並將合約傳遞給mshk變數,在geth中輸入以下內容:

mshk_Contract = web3.eth.contract(abi);
mshk_hello = mshk_Contract.new({from:acc0, data:mshk_bytecode, gas:300000}, function(e, contract){
    if(!e) {

      if(!contract.address) {
        console.log("Contract transaction send: TransactionHash: " + contract.transactionHash + " waiting to be mined...");

      } else {
        console.log("Contract mined! Address: " + contract.address);
        console.log(contract);
      }

    }
});

  輸入成功後,會看到下面的資訊,0x1d055281899007cbe6865a48d0a79239dac8e486是合約建立成功的地址:

> Contract mined! Address: 0x1d055281899007cbe6865a48d0a79239dac8e486
[object Object]

  

6.2.5、測試部署成功的智慧合約

  恭喜你,如果能看到上面的資訊,說明智慧合約已經部署成功了。接下來,我們可以使用下面的命令在geth中呼叫,剛剛部署成功的合約:

> mshk_hello.say()
"Hello mshk.top"
> mshk_hello.print("Hello https://mshk.top")
"Hello https://mshk.top"

  通過這些章節的練習,你可以將之前章節中的代幣合約、眾籌合約進行部署。

  

7、代幣合約、高階代幣合約、眾籌合約專案地址

  文章中使用的完整程式碼,存放在了github上面:https://github.com/idoall/truffle_solidity_contractsExample

  

8、擴充套件閱讀

upgrading-from-truffle-2-to-3

Full Stack Hello World Voting Ethereum Dapp Tutorial

Truffle Documentation

Building a smart contract using the command line

truffle3.0-integrate-nodejs


博文作者:迦壹
部落格地址:Truffle 4.0、Geth 1.7.2、TestRPC在私有鏈上搭建智慧合約
轉載宣告:可以轉載, 但必須以超連結形式標明文章原始出處和作者資訊及版權宣告,謝謝合作!


相關文章