Truffle 4.0、Geth 1.7.2、TestRPC在私有链上搭建智能合约
1、什么是 Truffle?
Truffle?是最流行的開發(fā)框架,能夠在本地編譯、部署智能合約,使命是讓開發(fā)更容易。
Truffle?需要以太坊客戶端支持,需要支持標(biāo)準(zhǔn)的JSON RPC API。
2、適合 Truffle 開發(fā)的客戶端
有許多的以太坊客戶端可以選擇。我們推薦在開發(fā)和部署時(shí)使用不同客戶端。
適用開發(fā)的客戶端
- EtherumJS TestRPC
適用正式發(fā)布的客戶端
- Geth (go-ethereum)
當(dāng)開發(fā)基于?Truffle?的應(yīng)用時(shí),推薦使用EthereumJS TestRPC。它是一個(gè)完整的在內(nèi)存中的區(qū)塊鏈僅僅存在于你開發(fā)的設(shè)備上。相對(duì)于?Geth,TestRPC?它在執(zhí)行交易時(shí)是實(shí)時(shí)返回,而不等待默認(rèn)的出塊時(shí)間,這樣你可以快速驗(yàn)證你新寫的代碼,當(dāng)出現(xiàn)錯(cuò)誤時(shí),也能即時(shí)反饋給你。它同時(shí)還是一個(gè)支持自動(dòng)化測試的功能強(qiáng)大的客戶端。Truffle?充分利用它的特性,能將測試運(yùn)行時(shí)間提速近90%。
3、Truffle的源代碼地址
https://github.com/trufflesuite/truffle
4、如何安裝?
接下來的例子,我們會(huì)使用?Truffle?分別連接?Geth?和?TestRPC?測試智能合約的部署,首先我們先分別安裝Truffle、Geth、TestRPC。
4.1、安裝 Go-Ethereum 1.7.2
Go-Ethereum?的安裝參考這篇文章:使用 Go-Ethereum 1.7.2搭建以太坊私有鏈
4.2、安裝 Truffle 4.0
依賴環(huán)境:
* 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 進(jìn)行智能合約的開發(fā)
5.1、初始化一個(gè) Truffle 項(xiàng)目
通過truffle init命令,可以初始化一個(gè)默認(rèn)的以太坊代幣合約項(xiàng)目,后面我們可以通過這個(gè)項(xiàng)目來快速學(xué)習(xí):
? /Users/lion/my_project/_eth >mkdir test_truffle ? /Users/lion/my_project/_eth >cd test_truffle ? /Users/lion/my_project/_eth/test_truffle >truffle initDownloading... Unpacking... Setting up... Unbox successful. Sweet!Commands:Compile: truffle compileMigrate: truffle migrateTest contracts: truffle test 完成后,你將擁有如下目錄:
*?contracts?智能合約目錄
*?migrations?發(fā)布腳本目錄
*?test?存放測試文件
*?truffle.js?Truffle的配置文件
5.2、編譯合約
要編譯合約,使用truffle compile命令,可以將原始代碼編譯成以太坊認(rèn)可的字節(jié)碼:
? /Users/lion/my_project/_eth/test_truffle >truffle compile Compiling ./contracts/Migrations.sol... Writing artifacts to ./build/contractsTruffle僅默認(rèn)編譯自上次編譯后被修改過的文件,來減少不必要的編譯。如果你想編譯全部文件,可以使用--compile-all選項(xiàng)
truffle compile --compile-allTruffle需要定義的合約名稱和文件名準(zhǔn)確匹配,這種匹配是區(qū)分大小寫的,也就是說大小寫也要一致。推薦大寫每一個(gè)開頭字母。
文件之間的相互依賴,可以使用import進(jìn)行合約間的引用,Truffle將會(huì)按正確順序依次編譯合約,并在需要的時(shí)候自動(dòng)關(guān)聯(lián)庫。例如:
import "./AnotherContract.sol";
5.3、創(chuàng)建一個(gè) Hello mshk.top 的合約并編譯
在contracts目錄中新建一個(gè)Hello_mshk_top.sol文件,代碼如下:
pragma solidity ^0.4.17;contract Hello_mshk_top {//say hello mshk.topfunction say() public pure returns (string) {return "Hello mshk.top";}//print namefunction print(string name) public pure returns (string) {return name;} }代碼中有兩個(gè)方法:say()方法是輸出一段文字Hello mshk.top;print(string name)方法是輸出傳入的內(nèi)容。
編輯migrations/1_initial_migration.js部署腳本,將我們剛才創(chuàng)建的Hello_mshk_top.sol文件設(shè)置到發(fā)布配置文件中,內(nèi)容如下:
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); };將項(xiàng)目使用truffle compile命令進(jìn)行編譯,編譯后的文件都放在了./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/contractsHello_mshk_top.sol編譯后的文件是./build/contracts/Hello_mshk_top.json中,后面在部署到geth中,我們會(huì)用到。
6、部署智能合約
編輯truffle.js配置文件,設(shè)置我們稍后要部署智能合約的位置,內(nèi)容如下:
module.exports = {networks: {development: {host: "localhost",port: 8545,network_id: "*"}} };接下來,我們會(huì)使用上面的智能合約,分別在testRPC和geth中進(jìn)行部署測試。
truffle的智能合約項(xiàng)目部署,使用下面的命令:
truffle migrate這個(gè)命令會(huì)執(zhí)行所有migrations目錄下的js文件。如果之前執(zhí)行過truffle migrate命令,再次執(zhí)行,只會(huì)部署新的js文件,如果沒有新的js文件,不會(huì)起任何作用。如果使用--reset參數(shù),則會(huì)重新的執(zhí)行所有腳本的部署。
如果要部署到指定的網(wǎng)絡(luò),可以使用--network參數(shù),例如:
truffle migrate --network live多個(gè)網(wǎng)絡(luò)的配置格式如下:
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、啟動(dòng) TestRPC
直接輸入testrpc命令,就可以調(diào)用起 TestRPC 客戶端,啟動(dòng)?testrpc?經(jīng)后,會(huì)默認(rèn)創(chuàng)建10個(gè)帳號(hào),Available Accounts是帳號(hào)列表,Private Keys是相對(duì)應(yīng)的帳號(hào)密鑰:
? /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 ================== 34359738368Listening on localhost:8545
6.1.3、通過 truffle migrate 命令,對(duì)合約進(jìn)行部署
使用truffle migrate命令,發(fā)布項(xiàng)目:
? /Users/lion/my_project/_eth/test_truffle >truffle migrate Using network 'development'.Running migration: 1_initial_migration.jsDeploying Migrations...... 0xd9e5fa242d29362e57e3da7b0bf6f71b72767972fc15240ed3a02d341e814a44Migrations: 0x4bedd1bb517ff9a54f6f3df8eba821ff16a4109bDeploying Hello_mshk_top...... 0xc22ff050e189c2561d40250077ee4bf628f957899dfa8d0b5fa50e3ab7a896b0Hello_mshk_top: 0xa7ef5037ff81d7932e01b68a503ca4587f00b35c Saving successful migration to network...... 0x49505a54042f5f74146fbfafef63dd408cb0a7a0c66214ebbaa3217e443d792a Saving artifacts...
6.1.4、測試部署成功的智能合約
輸入以下命令打開truffle控制臺(tái),測試剛才我們部署的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 contract和javascript語法一樣,表示聲明一個(gè)contract變量。Hello_mshk_top.deployed().then(function(instance){contract= instance;})表示,將Hello_mshk_top合約主體,傳遞給contract變量。后面我們就可以直接使用變量contract分別調(diào)用say()方法和print(''),得到我們想要的結(jié)果。
6.2、將智能合約部署到 Geth 1.7.2 私有鏈
6.2.1、新建 Geth 的創(chuàng)世區(qū)塊文件,并初始化
新建一個(gè)test_truffle_geth目錄,同時(shí)新建我們的創(chuàng)世區(qū)塊文件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.jsongenesis.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": {} }初始化創(chuàng)世區(qū)塊
? /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 方式運(yùn)行 Geth
使用rpc方式運(yùn)行g(shù)eth
? /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)
啟動(dòng)私有節(jié)點(diǎn)需要的參數(shù):
| identity | 區(qū)塊鏈的標(biāo)示,隨便填寫,用于標(biāo)示目前網(wǎng)絡(luò)的名字 |
| init | 指定創(chuàng)世塊文件的位置,并創(chuàng)建初始?jí)K |
| datadir | 設(shè)置當(dāng)前區(qū)塊鏈網(wǎng)絡(luò)數(shù)據(jù)存放的位置 |
| port | 網(wǎng)絡(luò)監(jiān)聽端口 默認(rèn)是30303 |
| rpc | 啟動(dòng)rpc通信,可以進(jìn)行智能合約的部署和調(diào)試 |
| maxpeers | 網(wǎng)絡(luò)節(jié)點(diǎn)的最大數(shù)量,默認(rèn)是25 |
| rpcapi | 設(shè)置允許連接的rpc的客戶端,一般為db,eth,net,web3 |
| networkid | 設(shè)置當(dāng)前區(qū)塊鏈的網(wǎng)絡(luò)ID,用于區(qū)分不同的網(wǎng)絡(luò),是一個(gè)數(shù)字 |
| console | 啟動(dòng)命令行模式,可以在Geth中執(zhí)行命令 |
| dev | 開發(fā)者模式,帶調(diào)試模式的專有網(wǎng)絡(luò) |
| nodiscover | 私有鏈地址,不會(huì)被網(wǎng)上看到 |
rpc方式啟動(dòng)geth以后,會(huì)一直停止在那里,沒有辦法在geth中進(jìn)行任何輸入。瀏覽一下我們剛才創(chuàng)建區(qū)塊鏈數(shù)據(jù)的文件夾,會(huì)發(fā)現(xiàn)有一個(gè)geth.ipc文件。
然后用下面這個(gè)命令,進(jìn)入geth控制臺(tái):
? /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.1modules: 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 中新建帳戶,開始挖礦
創(chuàng)建一個(gè)帳戶,并解鎖用戶一段時(shí)間(單位是秒),然后啟動(dòng)挖礦
> web3.personal.newAccount("123456") "0x0a67659a161410a4a1e0a5889ff05a1417915172" > personal.unlockAccount(eth.accounts[0], "123456", 15000) true > miner.start(1) null過一會(huì)后查看下帳戶地址的余額,將帳戶地址賦值給變量acc0,可以看到里面有了以太幣:
> acc0 = web3.eth.accounts[0] "0xc90747b99362c41fa89d2e7dea1b5b8d9567b741" > web3.eth.getBalance(acc0) 415000000000000000000
6.2.4、在 Geth 中部署合約
這時(shí),我們就要用到剛剛編譯后的Hello_mshk_top.json文件了,打開https://www.bejson.com網(wǎng)址,把a(bǔ)bi部分取出并進(jìn)行json轉(zhuǎn)義。然后在geth中輸入以下內(nèi)容,將json轉(zhuǎn)義后的內(nèi)容,賦值給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\"}]')會(huì)得到下面的返回值:
[{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中輸入以下內(nèi)容:
mshk_bytecode="0x6060604052341561000f57600080fd5b6102488061001e6000396000f30060606040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806311114af114610051578063954ab4b214610127575b600080fd5b341561005c57600080fd5b6100ac600480803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919050506101b5565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100ec5780820151818401526020810190506100d1565b50505050905090810190601f1680156101195780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561013257600080fd5b61013a6101c5565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561017a57808201518184015260208101905061015f565b50505050905090810190601f1680156101a75780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101bd610208565b819050919050565b6101cd610208565b6040805190810160405280600e81526020017f48656c6c6f206d73686b2e746f70000000000000000000000000000000000000815250905090565b6020604051908101604052806000815250905600a165627a7a72305820aa448d81e0f4bf12f805920c9cefd0d3cc6f053d87dd8547663721256179ebcd0029"評(píng)估下創(chuàng)建合約需要的手續(xù)費(fèi)是207296gas:
> web3.eth.estimateGas({data: mshk_bytecode}) 207296部署合約,并將合約傳遞給mshk變量,在geth中輸入以下內(nèi)容:
mshk_Contract = web3.eth.contract(mshk_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);}} });輸入成功后,會(huì)看到下面的信息,0x1d055281899007cbe6865a48d0a79239dac8e486是合約創(chuàng)建成功的地址:
> Contract mined! Address: 0x1d055281899007cbe6865a48d0a79239dac8e486 [object Object]
6.2.5、測試部署成功的智能合約
恭喜你,如果能看到上面的信息,說明智能合約已經(jīng)部署成功了。接下來,我們可以使用下面的命令在geth中調(diào)用,剛剛部署成功的合約:
> mshk_hello.say() "Hello mshk.top" > mshk_hello.print("Hello https://mshk.top") "Hello https://mshk.top"通過這些章節(jié)的練習(xí),你可以將之前章節(jié)中的代幣合約、眾籌合約進(jìn)行部署。
7、代幣合約、高級(jí)代幣合約、眾籌合約項(xiàng)目地址
文章中使用的完整代碼,存放在了github上面:https://github.com/idoall/truffle_solidity_contractsExample
8、擴(kuò)展閱讀
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在私有鏈上搭建智能合約
轉(zhuǎn)載聲明:可以轉(zhuǎn)載, 但必須以超鏈接形式標(biāo)明文章原始出處和作者信息及版權(quán)聲明,謝謝合作!
總結(jié)
以上是生活随笔為你收集整理的Truffle 4.0、Geth 1.7.2、TestRPC在私有链上搭建智能合约的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 手把手教创建你的第一个以太智能合约:ET
- 下一篇: 使用Node.js部署智能合約(Smar