1. 程式人生 > >【區塊鏈】Truffle 部署 編譯 測試 智慧合約 的 完整實踐操作

【區塊鏈】Truffle 部署 編譯 測試 智慧合約 的 完整實踐操作

Truffle 部署 編譯 測試 智慧合約 的 完整實踐操作

目標

  • 搭建開發環境
  • 建立一個Truffle專案
  • 編寫智慧合約
  • 編譯轉移智慧合約
  • 測試智慧合約
  • 建立使用者介面連線智慧合約
  • 在瀏覽器中訪問Dapp

搭建開發環境

  • Node.js v6+ LTS and npm (comes with Node)
  • Git

這裡配置指令碼略過。。。。

[email protected]➤ node -v
v8.5.0

[email protected]➤ npm -v
5.4.2

[email protected]➤ git --version
git version 2.13
.5 (Apple Git-94)
[email protected]➤ npm install -g ethereumjs-testrpc
/usr/local/bin/testrpc -> /usr/local/lib/node_modules/ethereumjs-testrpc/build/cli.node.js

> fsevents@1.1.2 install /usr/local/lib/node_modules/ethereumjs-testrpc/node_modules/fsevents
> node install

events.js:182
      throw er; // Unhandled 'error'
event ^ Error: spawn node-pre-gyp ENOENT at _errnoException (util.js:1026:11) at Process.ChildProcess._handle.onexit (internal/child_process.js:192:19) at onErrorNT (internal/child_process.js:374:16) at _combinedTickCallback (internal/process/next_tick.js:138:11) at process._tickCallback (internal/process/next_tick.js:180
:9) at Function.Module.runMain (module.js:667:11) at startup (bootstrap_node.js:201:16) at bootstrap_node.js:626:3 > uglifyjs-webpack-plugin@0.4.6 postinstall /usr/local/lib/node_modules/ethereumjs-testrpc/node_modules/uglifyjs-webpack-plugin > node lib/post_install.js npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.1.2 (node_modules/ethereumjs-testrpc/node_modules/fsevents): npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.1.2 install: `node install` npm WARN optional SKIPPING OPTIONAL DEPENDENCY: Exit status 1 + ethereumjs-testrpc@4.1.3 added 2 packages, removed 475 packages, updated 238 packages and moved 1 package in 293.194s ╭─────────────────────────────────────╮ │ │ │ Update available 5.4.25.5.1 │ │ Run npm i -g npm to update │ │ │ ╰─────────────────────────────────────╯ [email protected]➤ npm i -g npm to update /usr/local/bin/npm -> /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npx -> /usr/local/lib/node_modules/npm/bin/npx-cli.js /usr/local/bin/update -> /usr/local/lib/node_modules/update/bin/update.js + update@0.7.4 + npm@5.5.1 + to@0.2.9 added 708 packages, removed 2 packages and updated 29 packages in 434.067s [email protected]sudo npm install -g ethereumjs-testrpc npm WARN checkPermissions Missing write access to /usr/local/lib/node_modules/ethereumjs-testrpc/node_modules/_yargs@3.10.0@yargs/node_modules/cliui npm WARN checkPermissions Missing write access to /usr/local/lib/node_modules/ethereumjs-testrpc/node_modules/_yargs@3.10.0@yargs/node_modules/decamelize npm WARN checkPermissions Missing write access to /usr/local/lib/node_modules/ethereumjs-testrpc/node_modules/_strip-ansi@3.0.1@strip-ansi/node_modules/ansi-regex npm ERR! path /usr/local/lib/node_modules/ethereumjs-testrpc/node_modules/_yargs@3.10.0@yargs/node_modules/cliui npm ERR! code ENOENT npm ERR! errno -2 npm ERR! syscall access npm ERR! enoent ENOENT: no such file or directory, access '/usr/local/lib/node_modules/ethereumjs-testrpc/node_modules/[email protected]@yargs/node_modules/cliui' npm ERR! enoent This is related to npm not being able to find a file. npm ERR! enoent npm ERR! A complete log of this run can be found in: npm ERR! /Users/xiaoyu/.npm/_logs/2017-10-26T08_09_48_018Z-debug.log [email protected]➤ npm install -g truffle /usr/local/bin/truffle -> /usr/local/lib/node_modules/truffle/build/cli.bundled.js + truffle@3.4.11 removed 105 packages and updated 91 packages in 89.658s

用Truffle Box建立一個Truffle專案

❖  ~/solidity [16:15:01]
[email protected]➤ mkdir pet-shop-tutorial
❖  ~/solidity [16:15:06]
[email protected]cd pet-shop-tutorial

[email protected]➤ truffle unbox pet-shop
Downloading...
Unpacking...
Setting up...

目錄結構

/contracts 智慧合約
/migrations 遷移系統來處理智慧合約部署
/test 測試
truffle.js 配置檔案

其他部分是nodejs的配置檔案以及資料夾

編寫智慧合約

contracts中建立Adoption.sol檔案

pragma solidity ^0.4.4;

contract Adoption {

    address[16] public adopters; //儲存地址

    //採用一個寵物
    function adopt(uint petId) public returns (uint) {
        require(petId >= 0 && petId <= 15);

        adopters[petId] = msg.sender;

        return petId;
    }

    //返回採用者
    function getAdopters() public returns (address[16]) {
        return adopters;
    }
}

編譯轉移智慧合約

EVM的測試環境

開啟另一個視窗

[email protected]➤ testrpc -p 8588
EthereumJS TestRPC v4.1.3 (ganache-core: 1.1.3)

Available Accounts
==================
(0) 0xd2a54e8087d88889e1857698ceb228493b67bab6
(1) 0x44d32639c3803b9daa7392ff2ea50644153d7721
(2) 0x32d951e2f319edb079764b1c75864497a3132446
(3) 0x82244a630d6031be85ca298376cfa2bd6c7389a6
(4) 0xd3b556b69eb670a250bbc3f15ebefb081d4c7108
(5) 0x9f50cf1b425c6ca97de0128e46a21abd7bda3258
(6) 0x8e0545a4fe9eac1bb2f4683f0c6b36cd4a364a40
(7) 0x200b052f6eaeaa1dc11abcc3101b7a8aca293e70
(8) 0xcbd4c8b9d264367d385d4938c3b390a2eb0f2a62
(9) 0xa769a296f0bbab07e48ca62da5ad5aea4c920580

Private Keys
==================
(0) a4f66a0654bbd1338a0cc9264624ad9f710f5cd65bbd4aed6f0b20706335e573
(1) cab64a11662597c79a9e866865efbec4b2e1701ed21783f68a61162937baaf8a
(2) 9f52f1c63923b390b438212bdd4594d3b479b22024bd193b8a3a600572f697af
(3) 452b11e8ea19803b44b474d86c13d7325a387459abe634ad1c64b13eb26d0745
(4) a663ff82b20002942c491e393951e5e366d8cceeff89732690f974f709243260
(5) 7410aba40135ee4fea322a13403b081939d245e7ed534e016090657cbdb6183c
(6) 269e44a7c17d591d23a694539a8d6feee3d9894182d4bc663a2f51fc33a3f540
(7) 4f70e8c8f25a1ef2e9057a1b25053d6bceca46b68dfc0548e0c96b16fa9af5eb
(8) 6114321e07ba8248509c17f4f0318aaf0edd972986f43ec652a2030b6cfe18bd
(9) 37cacf13d9833bb3c63c657b42fed5f87f3806cca4d1cd400cbc5f7c8c2a3cc1

HD Wallet
==================
Mnemonic:      better become piano october library quarter festival ability arrow patch fringe practice
Base HD Path:  m/44'/60'/0'/0/{account_index}

Listening on localhost:8588

這裡注意,我的測試demo指定了埠,那麼也要修改對應的配置檔案。

truffle.js

module.exports = {
  networks: {
    development: {
      host: "localhost",
      port: 8588,
      network_id: "*" // Match any network id
    }
  }
};

編譯智慧合約

❖  ~/solidity/pet-shop-tutorial [16:27:59]
[email protected]➤ truffle compile
Compiling ./contracts/Adoption.sol...
Compiling ./contracts/Migrations.sol...
Writing artifacts to ./build/contracts

遷移智慧合約

檢視專案目錄,會發現migrations目錄中已經存在了一個檔案1_initial_migration.js

我們開始建立第二個檔案2_deploy_contracts.js

var Adoption = artifacts.require("./Adoption.sol");

module.exports = function(deployer) {
  deployer.deploy(Adoption);
};

執行遷移

❖  ~/solidity/pet-shop-tutorial [16:53:30]
[email protected]➤ truffle migrate
Using network 'development'.

Running migration: 1_initial_migration.js
  Deploying Migrations...
  ... 0x09db8962f99c5e5bdb316882c9f3aff69244df68664c6d90dda7e8c9f5249809
  Migrations: 0xf7345735ec00a0b797e5469a49b5deaf9131659f
Saving successful migration to network...
  ... 0xb6f330b833176db1e94d24c84bab618b6c9205585e9803f7c6fe21f14fec179a
Saving artifacts...
Running migration: 2_deploy_contracts.js
  Deploying Adoption...
  ... 0xb93b24287ebba0dfd091e62fb9d55e188a76412097fdae4a7caf1520b9aaabb9
  Adoption: 0x424bc3aeeeb6d0a0e0ed8271ce7764b6ad336c7a
Saving successful migration to network...
  ... 0x26f08c9da8a6ec12f4edece8a6344a9030bb7fbd97f3b1a4592b93f4aec2dc39
Saving artifacts...

同時,你在testrpc上還能看到下面的輸出

Listening on localhost:8588
net_version
eth_accounts
eth_accounts
net_version
net_version
eth_sendTransaction

  Transaction: 0x09db8962f99c5e5bdb316882c9f3aff69244df68664c6d90dda7e8c9f5249809
  Contract created: 0xf7345735ec00a0b797e5469a49b5deaf9131659f
  Gas usage: 201556
  Block Number: 1
  Block Time: Thu Oct 26 2017 16:58:31 GMT+0800 (CST)

eth_newBlockFilter
eth_getFilterChanges
eth_getTransactionReceipt
eth_getCode
eth_uninstallFilter
eth_sendTransaction

  Transaction: 0xb6f330b833176db1e94d24c84bab618b6c9205585e9803f7c6fe21f14fec179a
  Gas usage: 41965
  Block Number: 2
  Block Time: Thu Oct 26 2017 16:58:31 GMT+0800 (CST)

eth_getTransactionReceipt
eth_accounts
net_version
net_version
eth_sendTransaction

  Transaction: 0xb93b24287ebba0dfd091e62fb9d55e188a76412097fdae4a7caf1520b9aaabb9
  Contract created: 0x424bc3aeeeb6d0a0e0ed8271ce7764b6ad336c7a
  Gas usage: 213057
  Block Number: 3
  Block Time: Thu Oct 26 2017 16:58:31 GMT+0800 (CST)

eth_newBlockFilter
eth_getFilterChanges
eth_getTransactionReceipt
eth_getCode
eth_uninstallFilter
eth_sendTransaction

  Transaction: 0x26f08c9da8a6ec12f4edece8a6344a9030bb7fbd97f3b1a4592b93f4aec2dc39
  Gas usage: 26965
  Block Number: 4
  Block Time: Thu Oct 26 2017 16:58:31 GMT+0800 (CST)

eth_getTransactionReceipt

測試智慧合約

test資料夾中建立檔案TestAdoption.sol

pragma solidity ^0.4.11;

import "truffle/Assert.sol"; //truffle公共的庫
import "truffle/DeployedAddresses.sol"; //truffle公共的庫
import "../contracts/Adoption.sol";

contract TestAdoption {
    Adoption adoption = Adoption(DeployedAddresses.Adoption());

    // 測試 adopt()
    function testUserCanAdoptPet() {
        uint returnedId = adoption.adopt(8); //呼叫輸入引數

        uint expected = 8; //期望的結果

        Assert.equal(returnedId, expected, "Adoption of pet ID 8 should be recorded."); //判斷如果沒有就丟擲異常
    }

    // 單個測試
    function testGetAdopterAddressByPetId() {

        address expected = this;

        address adopter = adoption.adopters(8);

        Assert.equal(adopter, expected, "Owner of pet ID 8 should be recorded.");
    }

    // 所有的測試
    function testGetAdopterAddressByPetIdInArray() {

        address expected = this;

        address[16] memory adopters = adoption.getAdopters();

        Assert.equal(adopters[8], expected, "Owner of pet ID 8 should be recorded.");
    }


}

執行測試命令

[email protected]➤ truffle test
Using network 'development'.

Compiling ./contracts/Adoption.sol...
Compiling ./test/TestAdoption.sol...
Compiling truffle/Assert.sol...
Compiling truffle/DeployedAddresses.sol...

Compilation warnings encountered:

truffle/Assert.sol:114:20: Warning: This declaration shadows an existing declaration.
    function equal(string A, string B, string message) constant returns (bool result) {
                   ^------^
truffle/Assert.sol:64:5: The shadowed declaration is here:
    uint8 constant A = uint8(byte('a'));
    ^---------------------------------^

,truffle/Assert.sol:137:23: Warning: This declaration shadows an existing declaration.
    function notEqual(string A, string B, string message) constant returns (bool result) {
                      ^------^
truffle/Assert.sol:64:5: The shadowed declaration is here:
    uint8 constant A = uint8(byte('a'));
    ^---------------------------------^

,truffle/Assert.sol:206:20: Warning: This declaration shadows an existing declaration.
    function equal(bytes32 A, bytes32 B, string message) constant returns (bool result) {
                   ^-------^
truffle/Assert.sol:64:5: The shadowed declaration is here:
    uint8 constant A = uint8(byte('a'));
    ^---------------------------------^

,truffle/Assert.sol:226:23: Warning: This declaration shadows an existing declaration.
    function notEqual(bytes32 A, bytes32 B, string message) constant returns (bool result) {
                      ^-------^
truffle/Assert.sol:64:5: The shadowed declaration is here:
    uint8 constant A = uint8(byte('a'));
    ^---------------------------------^

,truffle/Assert.sol:286:20: Warning: This declaration shadows an existing declaration.
    function equal(address A, address B, string message) constant returns (bool result) {
                   ^-------^
truffle/Assert.sol:64:5: The shadowed declaration is here:
    uint8 constant A = uint8(byte('a'));
    ^---------------------------------^

,truffle/Assert.sol:305:23: Warning: This declaration shadows an existing declaration.
    function notEqual(address A, address B, string message) constant returns (bool result) {
                      ^-------^
truffle/Assert.sol:64:5: The shadowed declaration is here:
    uint8 constant A = uint8(byte('a'));
    ^---------------------------------^

,truffle/Assert.sol:403:20: Warning: This declaration shadows an existing declaration.
    function equal(bool A, bool B, string message) constant returns (bool result) {
                   ^----^
truffle/Assert.sol:64:5: The shadowed declaration is here:
    uint8 constant A = uint8(byte('a'));
    ^---------------------------------^

,truffle/Assert.sol:426:23: Warning: This declaration shadows an existing declaration.
    function notEqual(bool A, bool B, string message) constant returns (bool result) {
                      ^----^
truffle/Assert.sol:64:5: The shadowed declaration is here:
    uint8 constant A = uint8(byte('a'));
    ^---------------------------------^

,truffle/Assert.sol:451:20: Warning: This declaration shadows an existing declaration.
    function equal(uint A, uint B, string message) constant returns (bool result) {
                   ^----^
truffle/Assert.sol:64:5: The shadowed declaration is here:
    uint8 constant A = uint8(byte('a'));
    ^---------------------------------^

,truffle/Assert.sol:474:23: Warning: This declaration shadows an existing declaration.
    function notEqual(uint A, uint B, string message) constant returns (bool result) {
                      ^----^
truffle/Assert.sol:64:5: The shadowed declaration is here:
    uint8 constant A = uint8(byte('a'));
    ^---------------------------------^

,truffle/Assert.sol:497:22: Warning: This declaration shadows an existing declaration.
    function isAbove(uint A, uint B, string message) constant returns (bool result) {
                     ^----^
truffle/Assert.sol:64:5: The shadowed declaration is here:
    uint8 constant A = uint8(byte('a'));
    ^---------------------------------^

,truffle/Assert.sol:520:24: Warning: This declaration shadows an existing declaration.
    function isAtLeast(uint A, uint B, string message) constant returns (bool result) {
                       ^----^
truffle/Assert.sol:64:5: The shadowed declaration is here:
    uint8 constant A = uint8(byte('a'));
    ^---------------------------------^

,truffle/Assert.sol:543:22: Warning: This declaration shadows an existing declaration.
    function isBelow(uint A, uint B, string message) constant returns (bool result) {
                     ^----^
truffle/Assert.sol:64:5: The shadowed declaration is here:
    uint8 constant A = uint8(byte('a'));
    ^---------------------------------^

,truffle/Assert.sol:566:23: Warning: This declaration shadows an existing declaration.
    function isAtMost(uint A, uint B, string message) constant returns (bool result) {
                      ^----^
truffle/Assert.sol:64:5: The shadowed declaration is here:
    uint8 constant A = uint8(byte('a'));
    ^---------------------------------^

,truffle/Assert.sol:635:20: Warning: This declaration shadows an existing declaration.
    function equal(int A, int B, string message) constant returns (bool result) {
                   ^---^
truffle/Assert.sol:64:5: The shadowed declaration is here:
    uint8 constant A = uint8(byte('a'));
    ^---------------------------------^

,truffle/Assert.sol:658:23: Warning: This declaration shadows an existing declaration.
    function notEqual(int A, int B, string message) constant returns (bool result) {
                      ^---^
truffle/Assert.sol:64:5: The shadowed declaration is here:
    uint8 constant A = uint8(byte('a'));
    ^---------------------------------^

,truffle/Assert.sol:681:22: Warning: This declaration shadows an existing declaration.
    function isAbove(int A, int B, string message) constant returns (bool result) {
                     ^---^
truffle/Assert.sol:64:5: The shadowed declaration is here:
    uint8 constant A = uint8(byte('a'));
    ^---------------------------------^

,truffle/Assert.sol:704:24: Warning: This declaration shadows an existing declaration.
    function isAtLeast(int A, int B, string message) constant returns (bool result) {
                       ^---^
truffle/Assert.sol:64:5: The shadowed declaration is here:
    uint8 constant A = uint8(byte('a'));
    ^---------------------------------^

,truffle/Assert.sol:727:22: Warning: This declaration shadows an existing declaration.
    function isBelow(int A, int B, string message) constant returns (bool result) {
                     ^---^
truffle/Assert.sol:64:5: The shadowed declaration is here:
    uint8 constant A = uint8(byte('a'));
    ^---------------------------------^

,truffle/Assert.sol:750:23: Warning: This declaration shadows an existing declaration.
    function isAtMost(int A, int B, string message) constant returns (bool result) {
                      ^---^
truffle/Assert.sol:64:5: The shadowed declaration is here:
    uint8 constant A = uint8(byte('a'));
    ^---------------------------------^

,truffle/Assert.sol:1267:27: Warning: This declaration shadows an existing declaration.
    function balanceEqual(address A, uint b, string message) constant returns (bool result) {
                          ^-------^
truffle/Assert.sol:64:5: The shadowed declaration is here:
    uint8 constant A = uint8(byte('a'));
    ^---------------------------------^

,truffle/Assert.sol:1287:30: Warning: This declaration shadows an existing declaration.
    function balanceNotEqual(address A, uint b, string message) constant returns (bool result) {
                             ^-------^
truffle/Assert.sol:64:5: The shadowed declaration is here:
    uint8 constant A = uint8(byte('a'));
    ^---------------------------------^

,truffle/Assert.sol:1306:28: Warning: This declaration shadows an existing declaration.
    function balanceIsZero(address A, string message) constant returns (bool result) {
                           ^-------^
truffle/Assert.sol:64:5: The shadowed declaration is here:
    uint8 constant A = uint8(byte('a'));
    ^---------------------------------^

,truffle/Assert.sol:1325:31: Warning: This declaration shadows an existing declaration.
    function balanceIsNotZero(address A, string message) constant returns (bool result) {
                              ^-------^
truffle/Assert.sol:64:5: The shadowed declaration is here:
    uint8 constant A = uint8(byte('a'));
    ^---------------------------------^




  TestAdoption
    ✓ testUserCanAdoptPet (100ms)
    ✓ testGetAdopterAddressByPetId (106ms)
    ✓ testGetAdopterAddressByPetIdInArray (119ms)


  3 passing (912ms)

同時,在testrpc視窗中,輸出如下內容

net_version
eth_accounts
eth_accounts
eth_accounts
eth_sendTransaction

  Transaction: 0x0248e4f5b8ed0130b6c04fb0628747948c4430b2db32ae4b4aecc5837c95a7a9
  Contract created: 0x44d5b51c7a790edf595f36f647d8782ab95d2043
  Gas usage: 201556
  Block Number: 5
  Block Time: Thu Oct 26 2017 17:29:40 GMT+0800 (CST)

eth_newBlockFilter
eth_getFilterChanges
eth_getTransactionReceipt
eth_getCode
eth_uninstallFilter
eth_sendTransaction

  Transaction: 0xf25d861fa237ca89ece917d3bfcae990b00253a213e3dfe977c808727bb41621
  Gas usage: 41965
  Block Number: 6
  Block Time: Thu Oct 26 2017 17:29:40 GMT+0800 (CST)

eth_getTransactionReceipt
eth_accounts
eth_sendTransaction

  Transaction: 0x3bc4a4f9a6a29e336135a0617b9dcda72af62f8ed6ba8cdcb52e2c13b9c0b9c1
  Contract created: 0x7e434775cefce86de3c944aeb840b80ffa397e6f
  Gas usage: 213057
  Block Number: 7
  Block Time: Thu Oct 26 2017 17:29:40 GMT+0800 (CST)

eth_newBlockFilter
eth_getFilterChanges
eth_getTransactionReceipt
eth_getCode
eth_uninstallFilter
eth_sendTransaction

  Transaction: 0x8e9a560c91b97f4fe1020f9e4154b063391d4e1b6da522a80e78d572e18e3864
  Gas usage: 26965
  Block Number: 8
  Block Time: Thu Oct 26 2017 17:29:40 GMT+0800 (CST)

eth_getTransactionReceipt
evm_snapshot
Saved snapshot #1
net_version
eth_sendTransaction
net_version
eth_sendTransaction

  Transaction: 0xbcca837fc7693ae43eef2210f88f5b59ada90c2c56250558bdee776417c6ce8d
  Contract created: 0x16e910a876a0ef1ad4fceb7b15b0ed1e34212a3f
  Gas usage: 141661
  Block Number: 9
  Block Time: Thu Oct 26 2017 17:29:40 GMT+0800 (CST)

eth_newBlockFilter

  Transaction: 0x8ad5172333283066102aada539d0b17f14a3a13b5bc996b8baca49296d625045
  Contract created: 0x7d49d66afb1fa72446cbbeb2dc7f43237a2895d9
  Gas usage: 4630196
  Block Number: 10
  Block Time: Thu Oct 26 2017 17:29:40 GMT+0800 (CST)

eth_newBlockFilter
eth_getFilterChanges
eth_getFilterChanges
eth_getTransactionReceipt
eth_getTransactionReceipt
eth_getCode
eth_getCode
eth_uninstallFilter
eth_uninstallFilter
eth_sendTransaction

  Transaction: 0x4a9374f9c1da7266c44b9c3f191572a79938bf446e9261a910904fbd86b019ef
  Contract created: 0x2411f93ad68e7a071ad6b116614d4a45049a2e36
  Gas usage: 425816
  Block Number: 11
  Block Time: Thu Oct 26 2017 17:29:41 GMT+0800 (CST)

eth_newBlockFilter
eth_getFilterChanges
eth_getTransactionReceipt
eth_getCode
eth_uninstallFilter
eth_blockNumber
eth_sendTransaction

  Transaction: 0xc77b4f897c7ebcd27022c0b677589b6a3611384f5734660ec422cde74f0bec24
  Gas usage: 48908
  Block Number: 12
  Block Time: Thu Oct 26 2017 17:29:41 GMT+0800 (CST)

eth_getTransactionReceipt
eth_blockNumber
eth_sendTransaction

  Transaction: 0xbc11d4af9475b481271d824c3ba492d7eb23a204608c3da790b77cd8509d518e
  Gas usage: 29062
  Block Number: 13
  Block Time: Thu Oct 26 2017 17:29:41 GMT+0800 (CST)

eth_getTransactionReceipt
eth_blockNumber
eth_sendTransaction

  Transaction: 0x64e35489fcad832bfce85d305726922c2c2a97dcb897ffbfc4a69b0649fc7244
  Gas usage: 36064
  Block Number: 14
  Block Time: Thu Oct 26 2017 17:29:41 GMT+0800 (CST)

eth_getTransactionReceipt

建立使用者介面連線智慧合約

安裝web3

[email protected]➤ npm install -g web3
npm WARN deprecated fs-promise@2.0.3: Use mz or fs-extra^3.0 with Promise Support
npm WARN deprecated tar.gz@1.0.7: ⚠️  WARNING ⚠️ tar.gz module has been deprecated and your application is vulnerable. Please use tar module instead: https://npmjs.com/tar
npm WARN deprecated minimatch@0.3.0: Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue

> scrypt@6.0.3 preinstall /usr/local/lib/node_modules/web3/node_modules/scrypt
> node node-scrypt-preinstall.js


> scrypt@6.0.3 install /usr/local/lib/node_modules/web3/node_modules/scrypt
> node-gyp rebuild

  SOLINK_MODULE(target) Release/copied_files.node
  CC(target) Release/obj.target/scrypt_wrapper/src/util/memlimit.o
  CC(target) Release/obj.target/scrypt_wrapper/src/scryptwrapper/keyderivation.o
  CC(target) Release/obj.target/scrypt_wrapper/src/scryptwrapper/pickparams.o
  CC(target) Release/obj.target/scrypt_wrapper/src/scryptwrapper/hash.o
  LIBTOOL-STATIC Release/scrypt_wrapper.a
  CC(target) Release/obj.target/scrypt_lib/scrypt/scrypt-1.2.0/lib/crypto/crypto_scrypt.o
  CC(target) Release/obj.target/scrypt_lib/scrypt/scrypt-1.2.0/lib/crypto/crypto_scrypt_smix.o
  CC(target) Release/obj.target/scrypt_lib/scrypt/scrypt-1.2.0/libcperciva/util/warnp.o
  CC(target) Release/obj.target/scrypt_lib/scrypt/scrypt-1.2.0/libcperciva/alg/sha256.o
  CC(target) Release/obj.target/scrypt_lib/scrypt/scrypt-1.2.0/libcperciva/util/insecure_memzero.o
  CC(target) Release/obj.target/scrypt_lib/scrypt/scrypt-1.2.0/lib/scryptenc/scryptenc_cpuperf.o
  LIBTOOL-STATIC Release/scrypt_lib.a
  CXX(target) Release/obj.target/scrypt/src/node-boilerplate/scrypt_common.o
  CXX(target) Release/obj.target/scrypt/src/node-boilerplate/scrypt_params_async.o
  CXX(target) Release/obj.target/scrypt/src/node-boilerplate/scrypt_params_sync.o
  CXX(target) Release/obj.target/scrypt/src/node-boilerplate/scrypt_kdf_async.o
  CXX(target) Release/obj.target/scrypt/src/node-boilerplate/scrypt_kdf_sync.o
  CXX(target) Release/obj.target/scrypt/src/node-boilerplate/scrypt_kdf-verify_sync.o
  CXX(target) Release/obj.target/scrypt/src/node-boilerplate/scrypt_kdf-verify_async.o
  CXX(target) Release/obj.target/scrypt/src/node-boilerplate/scrypt_hash_sync.o
  CXX(target) Release/obj.target/scrypt/src/node-boilerplate/scrypt_hash_async.o
  CXX(target) Release/obj.target/scrypt/scrypt_node.o
  SOLINK_MODULE(target) Release/scrypt.node

> sha3@1.2.0 install /usr/local/lib/node_modules/web3/node_modules/sha3
> node-gyp rebuild

  CXX(target) Release/obj.target/sha3/src/addon.o
../src/addon.cpp:59:36: warning: 'NewInstance' is deprecated [-Wdeprecated-declarations]
                        info.GetReturnValue().Set(cons->NewInstance(argc, argv));
                                                        ^
/Users/xiaoyu/.node-gyp/8.5.0/include/node/v8.h:3787:3: note: 'NewInstance' has been explicitly marked deprecated here
  V8_DEPRECATED("Use maybe version",
  ^
/Users/xiaoyu/.node-gyp/8.5.0/include/node/v8config.h:332:29: note: expanded from macro 'V8_DEPRECATED'
  declarator __attribute__((deprecated))
                            ^
1 warning generated.
  CXX(target) Release/obj.target/sha3/src/displayIntermediateValues.o
  CXX(target) Release/obj.target/sha3/src/KeccakF-1600-reference.o
  CXX(target) Release/obj.target/sha3/src/KeccakNISTInterface.o
  CXX(target) Release/obj.target/sha3/src/KeccakSponge.o
  SOLINK_MODULE(target) Release/sha3.node

> websocket@1.0.24 install /usr/local/lib/node_modules/web3/node_modules/websocket
> (node-gyp rebuild 2> builderror.log) || (exit 0)

  CXX(target) Release/obj.target/bufferutil/src/bufferutil.o
  SOLINK_MODULE(target) Release/bufferutil.node
  CXX(target) Release/obj.target/validation/src/validation.o
  SOLINK_MODULE(target) Release/validation.node
+ web3@1.0.0-beta.24
added 289 packages in 68.85s

開啟檔案/src/js/app.js

下面的程式碼展示瞭如何呼叫web3,呼叫合約的方法,以及繫結資料到UI

App = {
  web3Provider: null,
  contracts: {},

  init: function() {
    // Load pets.
    $.getJSON('../pets.json', function(data) {
      var petsRow = $('#petsRow');
      var petTemplate = $('#petTemplate');

      for (i = 0; i < data.length; i ++) {
        petTemplate.find('.panel-title').text(data[i].name);
        petTemplate.find('img').attr('src', data[i].picture);
        petTemplate.find('.pet-breed').text(data[i].breed);
        petTemplate.find('.pet-age').text(data[i].age);
        petTemplate.find('.pet-location').text(data[i].location);
        petTemplate.find('.btn-adopt').attr('data-id', data[i].id);

        petsRow.append(petTemplate.html());
      }
    });

    return App.initWeb3();
  },

  initWeb3: function() {

      // web3入口
      if (typeof web3 !== 'undefined') {
          App.web3Provider = web3.currentProvider;
      } else {
          // 測試網路
          App.web3Provider = new Web3.providers.HttpProvider('http://localhost:8588'); //這裡是我指定的埠88
      }
      web3 = new Web3(App.web3Provider);

    return App.initContract();
  },

  initContract: function() {
      //載入Adoption.json
      $.getJSON('Adoption.json', function(data) {
          // 智慧合約例項化
          var AdoptionArtifact = data;
          App.contracts.Adoption = TruffleContract(AdoptionArtifact);

          // 設定合約提供者
          App.contracts.Adoption.setProvider(App.web3Provider);

          // 檢索操作
          return App.markAdopted();
      });

    return App.bindEvents();
  },

  bindEvents: function() {
    $(document).on('click', '.btn-adopt', App.handleAdopt);
  },

  markAdopted: function(adopters, account) {
      //例項
      var adoptionInstance;


      App.contracts.Adoption.deployed().then(function(instance) {
          adoptionInstance = instance;

          return adoptionInstance.getAdopters.call();
      }).then(function(adopters) {
          for (i = 0; i < adopters.length; i++) {
              if (adopters[i] !== '0x0000000000000000000000000000000000000000') {
                  $('.panel-pet').eq(i).find('button').text('Success').attr('disabled', true);
              }
          }
      }).catch(function(err) {
          console.log(err.message);
      });
  },

  handleAdopt: function() {
    event.preventDefault();

    var petId = parseInt($(event.target).data('id'));

      var adoptionInstance;

      web3.eth.getAccounts(function(error, accounts) {
          if (error) {
              console.log(error);
          }

          var account = accounts[0];

          App.contracts.Adoption.deployed().then(function(instance) {
              adoptionInstance = instance;

              // Execute adopt as a transaction by sending account
              return adoptionInstance.adopt(petId, {from: account});
          }).then(function(result) {
              return App.markAdopted();
          }).catch(function(err) {
              console.log(err.message);
          });
      });
  }

};

$(function() {
  $(window).load(function() {
    App.init();
  });
});

在瀏覽器中執行dapp

安裝MetaMask到瀏覽器

  • 安裝擴充套件程式
  • 建立測試網路賬戶
  • 從其他測試網路錢包轉移eth

建立一個賬戶並匯入eth

安裝和配置lite-server

開啟bs-config.json檔案

{
  "server": {
    "baseDir": ["./src", "./build/contracts"]
  }
}

開啟package.json檔案,下面配置了lite-server的部分

"scripts": {
  "dev": "lite-server",
  "test": "echo \"Error: no test specified\" && exit 1"
},

當執行npm run dev的時候,就會啟動lite-server

執行Dapp

❖  ~/solidity/pet-shop-tutorial [17:35:33]
[email protected]➤ npm run dev

> pet-shop@1.0.0 dev /Users/xiaoyu/solidity/pet-shop-tutorial
> lite-server

sh: lite-server: command not found
npm ERR! file sh
npm ERR! code ELIFECYCLE
npm ERR! errno ENOENT
npm ERR! syscall spawn
npm ERR! pet-shop@1.0.0 dev: `lite-server`
npm ERR! spawn ENOENT
npm ERR! 
npm ERR! Failed at the pet-shop@1.0.0 dev script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/xiaoyu/.npm/_logs/2017-10-26T10_20_42_191Z-debug.log

報錯了。。。。

[email protected]➤ npm install -g lite-server
npm WARN deprecated express@2.5.11: express 2.x series is deprecated
npm WARN deprecated connect@1.9.2: connect 1.x series is deprecated
/usr/local/bin/lite-server -> /usr/local/lib/node_modules/lite-server/bin/lite-server

> fsevents@1.1.2 install /usr/local/lib/node_modules/lite-server/node_modules/fsevents
> node install

[fsevents] Success: "/usr/local/lib/node_modules/lite-server/node_modules/fsevents/lib/binding/Release/node-v57-darwin-x64/fse.node" already installed
Pass --update-binary to reinstall or --build-from-source to recompile
+ lite-server@2.3.0
added 417 packages in 499.895s
❖  ~/solidity/pet-shop-tutorial [18:30:10]
[email protected]➤ npm run dev               

> pet-shop@1.0.0 dev /Users/xiaoyu/solidity/pet-shop-tutorial
> lite-server

** browser-sync config **
{ injectChanges: false,
  files: [ './**/*.{html,htm,css,js}' ],
  watchOptions: { ignored: 'node_modules' },
  server: 
   { baseDir: [ './src', './build/contracts' ],
     middleware: [ [Function], [Function] ] } }
[Browsersync] Access URLs:
 -------------------------------------
       Local: http://localhost:3000
    External: http://10.0.178.198:3000
 -------------------------------------
          UI: http://localhost:3001
 UI External: http://10.0.178.198:3001
 -------------------------------------
[Browsersync] Serving files from: ./src
[Browsersync] Serving files from: ./build/contracts
[Browsersync] Watching files...
17.10.26 18:31:20 200 GET /index.html
17.10.26 18:31:20 200 GET /css/bootstrap.min.css
17.10.26 18:31:21 200 GET /js/bootstrap.min.js
17.10.26 18:31:21 200 GET /js/web3.min.js
17.10.26 18:31:21 200 GET /js/app.js
17.10.26 18:31:21 200 GET /js/truffle-contract.js
17.10.26 18:31:24 200 GET /pets.json
17.10.26 18:31:24 200 GET /Adoption.json
17.10.26 18:31:24 200 GET /images/french-bulldog.jpeg
17.10.26 18:31:24 200 GET /images/boxer.jpeg
17.10.26 18:31:24 200 GET /images/scottish-terrier.jpeg
17.10.26 18:31:24 200 GET /images/golden-retriever.jpeg
17.10.26 18:31:24 404 GET /favicon.ico

然後會自動開啟瀏覽器,http://localhost:3000/

示例網站

點選adopt按鈕,會跳出提示,支付合約費用,完成呼叫。

總結

Truffle能完成智慧合約的整套流程。

Truffle Box 提供了現成的專案,可以快速上手。

Truffle官網文件夠詳細,點個贊。

參考資料