智慧合約,Nthereum,truffle
在上一篇文章中,ofollow,noindex" target="_blank">以太坊區塊鏈與Nethereum的互動 中我已經在dotnet客戶端內硬編碼了合約程式碼和ABI。它看起來很一般,我不太喜歡它!
此外,我沒有使用truffle測試功能,因為我遇到了ganache-cli沒有傳播事件的問題。
首先,我建立了一個空資料夾,並執行:
truffle init
之後,我在合約資料夾中添加了合約。我不喜歡原始結構,因此我刪除了建構函式引數並將事件更改為具有被乘數,乘數和乘積引數名稱。
pragma solidity ^0.4.21; contract Multiplier { event Multiplied(uint256 indexed multiplicand, uint256 indexed multiplier, address indexed sender, uint256 product); function multiply(uint256 a, uint256 b) public returns(uint r) { // looks like an overflow waiting to happen r = a * b; emit Multiplied(a, b, msg.sender, r); return r; } }
新增測試
接下來,我在合約中添加了簡單的健全性檢查。合約工件首先需要:
var Multiplier = artifacts.require("./Multiplier.sol");
然後,可以通過呼叫deployed()
方法來建立此合約的例項:
contract = await Multiplier.deployed();
之後你可以寫測試了!Truffle js
測試帶有非同步/等待支援,這意味著更短,更易於理解的程式碼!
it("should multiply", async function () { let res = await contract.multiply.call(4, 5); assert.equal(res, 20); })
起初,測試將失敗並出現神祕錯誤。
1) Contract: Multiplier with deployment "before each" hook: deploy contract for "deploy": Error: Multiplier has not been deployed to detected network (network/artifact mismatch) at /usr/local/lib/node_modules/truffle/build/webpack:/~/truffle-contract/contract.js:454:1 at <anonymous> at process._tickCallback (internal/process/next_tick.js:188:7)
事實證明我忘記在遷移資料夾中新增2_deploy_contract.js
遷移檔案:
var Multiplier = artifacts.require("./Multiplier.sol"); module.exports = function(deployer) { deployer.deploy(Multiplier); };
以下是完整的測試程式碼。當然,在生產程式碼中可以預期需要更多的測試。這是一個我保持簡潔的樣本。
var Multiplier = artifacts.require("./Multiplier.sol"); ccontract('Multiplier', function () { let contract = null; beforeEach('deploy', async function() { contract = await Multiplier.deployed(); }) describe("multiply", function() { it("should multiply", async function () { var res = await contract.multiply.call(2, 2)); assert.equal(res, 4); }); }); });
編制合約
執行truffle compile
命令將在json檔案中生成位元組碼和ABI。 預設情況下,此檔案位於合約專案的build/contracts
資料夾中。這可以在truffle.js
檔案中更改。
module.exports = { // See <http://truffleframework.com/docs/advanced/configuration> // to customize your Truffle configuration! contracts_build_directory: "./../../Client/NethClient/Contracts/Multiplier" };
載入合約
要將合約複製到輸出資料夾,請通過新增以下內容來更改csproj檔案:
<ItemGroup> <None Include="Contracts/**" CopyToOutputDirectory="Always" /> </ItemGroup>
既然合約存在於dotnet專案中,它也可以使用JObject載入。
var json = JObject.Load(new JsonTextReader(new StreamReader(File.OpenRead("Contracts/Multiplier/Multiplier.json")))); var abi = json["abi"].ToString(); var bytecode = json["bytecode"].ToString();
我藉此機會稍微重構程式碼以進一步分離另一個類中的合約操作。這可能對以後與其他合約一起使用很有用。
事件和gas
執行程式碼後,一切都很順利,除了沒有返回任何事件。
client_1| Multiply 8 by 9 using 24082 gas geth_1| INFO [05-15|20:01:08] Submitted transactionfullhash=0xdfde494ea6d244f927066bf877862b400e0b358bfba33bb790a907736a4d1a1c recipient=0x98245fba911B71ECAe3490ba9D324a2C7038ffbB geth_1| INFO [05-15|20:01:13] Successfully sealed new blocknumber=361 hash=377574…fffd4f geth_1| INFO [05-15|20:01:13] :link: block reached canonical chainnumber=356 hash=281662…94a4fd geth_1| INFO [05-15|20:01:13] :hammer: mined potential blocknumber=361 hash=377574…fffd4f geth_1| INFO [05-15|20:01:13] Commit new mining worknumber=362 txs=1 uncles=0 elapsed=15.164ms geth_1| INFO [05-15|20:01:18] Successfully sealed new blocknumber=362 hash=460dc2…306b71 geth_1| INFO [05-15|20:01:18] :link: block reached canonical chainnumber=357 hash=cd3d35…0435c3 geth_1| INFO [05-15|20:01:18] :hammer: mined potential blocknumber=362 hash=460dc2…306b71 geth_1| INFO [05-15|20:01:18] Commit new mining worknumber=363 txs=0 uncles=0 elapsed=1.468ms client_1| -> Done at block 362 using 24082 gas client_1| Get all events for filter 317348022035050220953892121001492572177 client_1| -> Got 0
結果我忘記了氣體計算功能中的一個引數。
// wrong var gas = await _multiply.EstimateGasAsync(multiplicand).ConfigureAwait(false); // correct var gas = await _multiply.EstimateGasAsync(multiplicand, multiplier).ConfigureAwait(false);
gas低於要求,沒有發生任何事件。這很奇怪,因為如果gas不足,應該提出錯誤?修復程式碼後:
client_1| Multiply 8 by 9 using 24274 gas geth_1| INFO [05-15|20:15:28] Submitted transactionfullhash=0x1454c7801c61fe19f9950976418a6af1b0e696317f77cfbf5ab65cbbd124c653 recipient=0x68281a51523A439260Ca30c7121D6Ed9B39A95e6 geth_1| INFO [05-15|20:15:33] Successfully sealed new blocknumber=379 hash=dd9754…a4e240 geth_1| INFO [05-15|20:15:33] :link: block reached canonical chainnumber=374 hash=5d3b4b…f477a3 geth_1| INFO [05-15|20:15:33] :hammer: mined potential blocknumber=379 hash=dd9754…a4e240 geth_1| INFO [05-15|20:15:33] Commit new mining worknumber=380 txs=1 uncles=0 elapsed=4.295ms geth_1| INFO [05-15|20:15:38] Successfully sealed new blocknumber=380 hash=64b91a…0bc39b geth_1| INFO [05-15|20:15:38] :link: block reached canonical chainnumber=375 hash=300263…5cc25a geth_1| INFO [05-15|20:15:38] :hammer: mined potential blocknumber=380 hash=64b91a…0bc39b geth_1| INFO [05-15|20:15:38] Commit new mining worknumber=381 txs=0 uncles=0 elapsed=3.007ms client_1| -> Done at block 380 using 24274 gas client_1| Get all events for filter 189326955700024171316112267564238036559 client_1| -> Got 2 client_1| -> Block 378 : 7 * 7 = 49 client_1| -> Block 380 : 8 * 9 = 72
新增更多測試
我要加上chai ,chai-as-promise 和chai-bignumber 。
require('chai') .use(require('chai-as-promised')) .use(require('chai-bignumber')(web3.BigNumber)) .should(); var Multiplier = artifacts.require("./Multiplier.sol"); contract('Multiplier', function () { let contract = null; beforeEach('deploy', async function() { contract = await Multiplier.deployed(); }) describe("multiply", function() { it("should multiply", async function () { (await contract.multiply.call(2, 2)).should.bignumber.equal(4); }); it("should not overflow", async function () { // uint256 max value const max = new web3.BigNumber(2, 10).pow(256).sub(1); await contract.multiply.call(max, 2).should.eventually.be.rejected; }); }); });
由於溢位錯誤,執行測試應該失敗:
$ truffle test Compiling ./contracts/Migrations.sol... Compiling ./contracts/Multiplier.sol... Compiling openzeppelin-solidity/contracts/math/SafeMath.sol... Contract: Multiplier multiply ✓ should multiply simple numbers (66ms) ✓ should multiply BigNumbers (57ms) 1) should not overflow > No events were emitted 2 passing (286ms) 1 failing 1) Contract: Multiplier multiply should not overflow: AssertionError: expected promise to be rejected but it was fulfilled with { Object (s, e, ...) }
引用openzeppelin
接下來,我添加了openzeppelin:
yarn add openzeppelin-solidity --save-dev
現在,我可以通過在合約程式碼檔案中匯入所需的合約來引用此庫。在這裡,我使用了SafeMath庫:
import "openzeppelin-solidity/contracts/math/SafeMath.sol"; contract Multiplier { event Multiplied(uint256 indexed multiplicand, uint256 indexed multiplier, address indexed sender, uint256 product); function multiply(uint256 a, uint256 b) public returns(uint r) { r = SafeMath.mul(a, b); emit Multiplied(a, b, msg.sender, r); return r; } }
現在,再次執行測試應該通過:
$ truffle test Compiling ./contracts/Migrations.sol... Compiling ./contracts/Multiplier.sol... Compiling openzeppelin-solidity/contracts/math/SafeMath.sol... Contract: Multiplier multiply ✓ should multiply simple numbers (52ms) ✓ should multiply BigNumbers (41ms) ✓ should not overflow 3 passing (234ms)
現在一切都很好看。
本文的原始碼庫位於Github 上。
如果希望快速進行以太坊開發,那請看我們精心打造的教程:
C#以太坊,主要講解如何使用C#開發基於.Net的以太坊應用,包括賬戶管理、狀態與交易、智慧合約開發與互動、過濾器和事件等。
其他區塊鏈教程如下:
- 以太坊開發進階教程,主要是介紹使用node.js、mongodb、區塊鏈、ipfs實現去中心化電商DApp實戰,適合進階。
- java以太坊開發教程,主要是針對java和android程式員進行區塊鏈以太坊開發的web3j詳解。
- python以太坊,主要是針對python工程師使用web3.py進行區塊鏈以太坊開發的詳解。
- php以太坊,主要是介紹使用php進行智慧合約開發互動,進行賬號建立、交易、轉賬、代幣開發以及過濾器和事件等內容。
- 以太坊入門教程,主要介紹智慧合約與dapp應用開發,適合入門。
- php比特幣開發教程,本課程面向初學者,內容即涵蓋比特幣的核心概念,例如區塊鏈儲存、去中心化共識機制、金鑰與指令碼、交易與UTXO等,同時也詳細講解如何在Php程式碼中整合比特幣支援功能,例如建立地址、管理錢包、構造裸交易等,是Php工程師不可多得的比特幣開發學習課程。
- java比特幣開發教程,本課程面向初學者,內容即涵蓋比特幣的核心概念,例如區塊鏈儲存、去中心化共識機制、金鑰與指令碼、交易與UTXO等,同時也詳細講解如何在Java程式碼中整合比特幣支援功能,例如建立地址、管理錢包、構造裸交易等,是Java工程師不可多得的比特幣開發學習課程。
- EOS入門教程,本課程幫助你快速入門EOS區塊鏈去中心化應用的開發,內容涵蓋EOS工具鏈、賬戶與錢包、發行代幣、智慧合約開發與部署、使用程式碼與智慧合約互動等核心知識點,最後綜合運用各知識點完成一個便籤DApp的開發。
匯智網原創翻譯,轉載請標明出處。這裡是原文