【以太坊開發】如何開發一個編譯以太坊智能合約並且發布的平臺(二)
接上一章的內容,這篇介紹 deploy相關和結果演示。
deploy一個合約的過程中,需要計算發布的消耗和nonce值。
當進行每筆交易時,發送人設定Gas Limit 和Gas Price,將 Gas Limit*Gas Price ,就得到了ETH交易傭金的成本。
nonce:以太坊要求一個賬戶的每筆交易有一個連續的計數。每個節點將根據計數順序嚴格執行來自一個用戶的交易。
app.js中有下面兩個函數:
var web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); function etherSpentInPendingTransactions(address, callback) { web3.currentProvider.sendAsync({ method:"txpool_content", params: [], jsonrpc: "2.0", id: new Date().getTime() }, function (error, result) { console.log(result) if(typeof(result.result.pending)!="undefined" && result.result.pending) { if(result.result.pending[address]) {var txns = result.result.pending[address]; var cost = new BigNumber(0); for(var txn in txns) { cost = cost.add((new BigNumber(parseInt(txns[txn].value))).add((new BigNumber(parseInt(txns[txn].gas))).mul(new BigNumber(parseInt(txns[txn].gasPrice))))); } callback(null, web3.fromWei(cost, "ether")); } else { callback(null, "0"); } } else { callback(null, "0"); } }) }
上面函數的流程:
1 使用sendAsync異步調用JSON PRC,調用的方法是 :txpool_content,這個方法用於查詢交易池中待處理的交易,返回的結果屬性有pending和queqed。想了解這個函數可以查看:https://github.com/ethereum/go-ethereum/wiki/Management-APIs#txpool_content
2 通過返回結果的屬性 pending和賬戶的地址獲取所以交易:
var txns = result.result.pending[address];對交易的結果進行循環,累加每個交易的value和gas消耗,就是所有將要打包到下個塊的交易的總消耗。
在介紹一下getNonce函數:
function getNonce(address, callback) { web3.eth.getTransactionCount(address, function(error, result){ var txnsCount = result; web3.currentProvider.sendAsync({ method: "txpool_content", params: [], jsonrpc: "2.0", id: new Date().getTime() }, function (error, result) { if(result.result.pending) { if(result.result.pending[address]) { txnsCount = txnsCount + Object.keys(result.result.pending[address]).length; callback(null, txnsCount); } else { callback(null, txnsCount); } } else { callback(null, txnsCount); } }) }) }
eth中每個交易的nonce是累加的,它是把挖出的交易總數和待定的交易總數加起來得到的。
所以對於deploy函數來說,只需要利用上面兩個函數構造交易的消耗cost和nonce值然後調用sendRawTranstaction,當然還需要對交易簽署,需要提供秘鑰,所以界面設計也會需要賬戶秘鑰。代碼如下:
app.get("/deploy", function(req, res){ var code = req.query.code; var arguments = JSON.parse(req.query.arguments); var address = req.query.address; var output = solc.compile(code, 1); var contracts = output.contracts; for(var contractName in contracts) { var abi = JSON.parse(contracts[contractName].interface); var byteCode = contracts[contractName].bytecode; var contract = web3.eth.contract(abi); var data = contract.new.getData.call(null, ...arguments, { data: byteCode }); console.log(data); console.log(web3.eth.defaultAccount) var gasRequired = web3.eth.estimateGas({ from:address, data: "0x" + data }); web3.eth.getBalance(address, function(error, balance){ var etherAvailable = web3.fromWei(balance, "ether"); etherSpentInPendingTransactions(address, function(error, balance){ etherAvailable = etherAvailable.sub(balance) if(etherAvailable.gte(web3.fromWei(new BigNumber(web3.eth.gasPrice).mul(gasRequired), "ether"))) { getNonce(address, function(error, nonce){ var rawTx = { gasPrice: web3.toHex(web3.eth.gasPrice), gasLimit: web3.toHex(gasRequired), from: address, nonce: web3.toHex(nonce), data: "0x" + data }; var privateKey = ethereumjsUtil.toBuffer(req.query.key, ‘hex‘); var tx = new ethereumjsTx(rawTx); tx.sign(privateKey); web3.eth.sendRawTransaction("0x" + tx.serialize().toString(‘hex‘), function(err, hash) { res.send({result: { hash: hash, }}); }); }) } else { res.send({error: "Insufficient Balance"}); } }) }) break; } })
到這裏基本流程已經很清晰了。具體的代碼可以到git上下載:https://github.com/figo050518/deployContract
配置app.js的web3地址。
進入項目根目錄 執行 npm install
node app.js 啟動前端服務。
我定義的端口是7070。下面是筆者執行的截圖:
到這裏就完成了一個編譯 部署合約的平臺,前端頁面沒有過多介紹,讀者可以看下源碼。
【以太坊開發】如何開發一個編譯以太坊智能合約並且發布的平臺(二)