以太坊学习(四)--搭建智能合约测试环境、开发、编译、部署

蔚落 2022-05-30 02:28 426阅读 0赞

原文链接:https://yq.aliyun.com/articles/212944\#3

摘要: 如何编写智能合约(Smart Contract)?(I) 完整视频教程 https://v.qq.com/x/page/h0552ba9k8h.html学习目标 了解智能合约 简单环境搭建 能够利用solidity编写Hello World合约 合约部署 和合约互动 使用solidity语言撰写智能合约 Ethereum上的智能合约需要使用solidity语言来撰写

如何编写智能合约(Smart Contract)?(I)

完整视频教程

  • https://v.qq.com/x/page/h0552ba9k8h.html

学习目标

  1. 了解智能合约
  2. 简单环境搭建
  3. 能够利用solidity编写Hello World合约
  4. 合约部署
  5. 和合约互动

使用solidity语言撰写智能合约

Ethereum上的智能合约需要使用solidity语言来撰写。虽然还有其他能用来撰写智能合约的语言如Serpent(类Python)、lll(类Fortran),但目前看到所有公开的智能合约都是使用solidity撰写。

宣传上说,solidity是一种类似Javascript的语言,而且围绕着solidity的各种开发工具链,都是使用属于Javascript生态系的npm来提供的。但我觉得solidity还是比较像Java或C#。因为和Javascript不同,solidity与Java或C#同属于强类型(Strong Type,在定义变数时需要指定类型)语言、在定义函式(function)时同样需指定回传的类型(type)、同样也需要先编译才能执行。这些特性都是Javascript所不具备的。

开发前的准备

本文将使用当前最活跃的智能合约开发框架truffle为基础来开发。ENS(Ethereum Name Service)也是采用truffle框架。其他选择还有embark等。

就像一般网站或App开发一样,在提供公开服务之前,开发者会在自己用于写程序的电脑(又称作本机)或透过测试网络来测试程序执行的效果,测试完成后,才会部署到公开的网络上提供服务。开发区块链智能合约(程序)的过程也是如此。特别是公开链上所有写入或读取计算结果的操作都需要真金白银(虚拟代币),而且根据网络状况,每个公开链上的操作都需要要一小段反应时间(15秒~数分钟),这些等待颇浪费宝贵的开发时间⏳。因此在开发的过程中,我们将使用testrpc工具在电脑上模拟智能合约所需的以太坊内存块链测试环境。

testrpc中也包含了Javascript版本的Ethereum虚拟机(Ethereum Virtual Machine),因此可以完整地执行智能合约。

此外,开发前还需准备一个合手的编辑器。我目前是使用Atom搭配solidity插件来开发。solidity插件除了支持语法高亮之外,也会透过Solium检查并提示基本的语法错误,相当方便。其他编辑器应该也有类似的插件可选择。

Snip20170919_6.png
Snip20170919_7.png
Snip20170919_8.png

安装所需工具

首先开发机上必须装好Node.js,再使用以下命令安装所需的工具:

  1. $ npm install -g ethereumjs-testrpc truffle
  2. liyuechun:~ yuechunli$ npm install -g ethereumjs-testrpc truffle
  3. /usr/local/bin/testrpc -> /usr/local/lib/node_modules/ethereumjs-testrpc/build/cli.node.js
  4. /usr/local/bin/truffle -> /usr/local/lib/node_modules/truffle/build/cli.bundled.js
  5. + truffle@3.4.9
  6. + ethereumjs-testrpc@4.1.3
  7. added 1 package and updated 7 packages in 76.132s
  8. liyuechun:~ yuechunli$

启动Testrpc

安装好后随时可以使用testrpc命令来启动以太坊测试环境。

  1. liyuechun:~ yuechunli$ testrpc
  2. EthereumJS TestRPC v4.1.3 (ganache-core: 1.1.3)
  3. Available Accounts
  4. ==================
  5. (0) 0xbbd414b340f2255dab9d923428c97f0b65d9df81
  6. (1) 0xe9869e3cf29b6fca81762c314df229c7c4fea25e
  7. (2) 0xc79e72362a4511b9e499d186654332c4d6f569be
  8. (3) 0x9a6f0651907c149d4173c03927144dbbba1473d4
  9. (4) 0x5b13a5d6788752b26dd4e338aae2e01058ee145e
  10. (5) 0xfc7f56d942ad5260be23ecee92a344aba1b7e7d8
  11. (6) 0xc48dc22c6bacd6ade4421ab54f25bc45c1c51142
  12. (7) 0x3fe2b7d4141dd0a456661f77086d055cbaf3b78f
  13. (8) 0x567979fed26ca85e9d1b4ac919c840e3fc9857e2
  14. (9) 0xb2eafe245f098eef1c2c1f466d9a8dcd58764c62
  15. Private Keys
  16. ==================
  17. (0) 947ab78e91133103612ca099d60e6c38cac5bb769f7f097c82d003cf058500bd
  18. (1) 8ffe0ba8dc53e16944a17dddd3378b5fba0379cd84df4e5237b8b46d05b8762f
  19. (2) ffe2e04e43e4106b247407656f5233bcc3e0c49730972d0df9c1d1093375e2ef
  20. (3) a20e453dc44c76aaca6a22efdbb605c2ed9eea64c11317e683461e11bd105ea7
  21. (4) 4748268ff1b828868dc56d07a1b121b427e1bdede5dbb3c14ef1254d9d26b1a5
  22. (5) f9957e68c6d20d38b81604a0509e6c4591478bc754f87d5682564073705fbb46
  23. (6) 34e648b23c0ace6b2b0893651d87f70be8496f97ecf6b7b4607b2acc4e05c9bd
  24. (7) d2477cedec217e3fb19a5981dafbc125ef66ccc9dc7df29301d08a24da843cf5
  25. (8) d319f85ccd80e55b2e707e05f09662632564c297248f8b96f82ea5eeaeef0851
  26. (9) 88c33ac9f1062b82f9e82f86a0ce307e3bd8fcf683b9751232c2f193f5bdc668
  27. HD Wallet
  28. ==================
  29. Mnemonic: hire custom clinic expect fury fantasy try dress source spy viable flag
  30. Base HD Path: m/44'/60'/0'/0/{account_index} Listening on localhost:8545

可以看到testrpc启动后自动建立了10个帐号(Accounts),与每个帐号对应的私钥(Private Key)。每个帐号中都有100个测试用的以太币(Ether)。要注意testrpc仅运行在內存中,因此每次重开时都会回到全新的状态。

一切准备就绪,我们可以开始建立第一份智能合约项目了。

建立项目

开启另一个终端窗口,输入以下命令以建立项目:

  1. liyuechun:Desktop yuechunli$ mkdir SmartContractDemo
  2. liyuechun:Desktop yuechunli$ cd SmartContractDemo/
  3. liyuechun:SmartContractDemo yuechunli$ mkdir HelloWorld
  4. liyuechun:SmartContractDemo yuechunli$ cd HelloWorld/
  5. liyuechun:HelloWorld yuechunli$ truffle init
  6. Downloading project...
  7. Project initialized.
  8. Documentation: http://truffleframework.com/docs
  9. Commands:
  10. Compile: truffle compile
  11. Migrate: truffle migrate
  12. Test: truffle test
  13. liyuechun:HelloWorld yuechunli$ ls
  14. contracts migrations test truffle.js

目录结构:

/contracts:存放智能合约原始代码的地方,可以看到里面已经有三个sol文件,我们开发的HelloWorld.sol文件就存放在这里。

/migrations:这是 Truffle用来部署智能合约的功能,待会儿我们会修改2_deploy_contracts.js来部署 HelloWorld.sol
/test:测试智能合约的代码放在这里,支持jssol 测试。
truffle.js: Truffle 的设置文档。

Snip20170919_12.png

新建HelloWorld合约

contracts文件夹下新建HelloWorld.sol文件,当然也可以直接在HelloWorld路径下面直接执行truffle create contract HelloWorld命令来创建HelloWorld.sol

Snip20170919_13.png

HelloWorld.sol文件內容如下:

  1. pragma solidity ^0.4.4;
  2. contract HelloWorld {
  3. function sayHello() returns (string) {
  4. return ("Hello World");
  5. }
  6. }

Snip20170919_14.png

讲解

  1. pragma solidity ^0.4.4;

第一行指名目前使用的solidity版本,不同版本的solidity可能会编译出不同的bytecode^代表兼容solidity`0.4.4 ~ 0.4.9`的版本。

  1. contract HelloWorld {
  2. ...
  3. }

contract关键字类似于其他语言中较常见的class。因为solidity是专为智能合约(Contact)设计的语言,声明contract后即内置了开发智能合约所需的功能。也可以把这句理解为class HelloWorld extends Contract

  1. function sayHello() returns (string) {
  2. return ("Hello World");
  3. }

函数的结构与其他程序类似,但如果有传入的参数或回传值,需要指定参数或回传值的类型(type)。

编译

现在执行truffle compile命令,我们可以将HelloWorld.sol原始码编译成Ethereum bytecode

  1. liyuechun:HelloWorld yuechunli$ ls
  2. contracts migrations test truffle.js
  3. liyuechun:HelloWorld yuechunli$ truffle compile
  4. Compiling ./contracts/ConvertLib.sol...
  5. Compiling ./contracts/HelloWorld.sol...
  6. Compiling ./contracts/MetaCoin.sol...
  7. Compiling ./contracts/Migrations.sol...
  8. Writing artifacts to ./build/contracts
  9. liyuechun:HelloWorld yuechunli$ ls
  10. build contracts migrations test truffle.js
  11. liyuechun:HelloWorld yuechunli$ cd build/
  12. liyuechun:build yuechunli$ ls
  13. contracts
  14. liyuechun:build yuechunli$ cd contracts/
  15. liyuechun:contracts yuechunli$ ls
  16. ConvertLib.json HelloWorld.json MetaCoin.json Migrations.json
  17. liyuechun:contracts yuechunli$ cat HelloWorld.json
  18. {
  19. "contract_name": "HelloWorld",
  20. "abi": [
  21. {
  22. "inputs": [],
  23. "payable": false,
  24. "type": "constructor"
  25. }
  26. ],
  27. "unlinked_binary": "0x60606040523415600e57600080fd5b5b5b5b603680601e6000396000f30060606040525b600080fd00a165627a7a723058203ee98a767948e9bc08094df4a46ab0361f068b2a559032cf968df5bbf63e91430029",
  28. "networks": {},
  29. "schema_version": "0.0.5",
  30. "updated_at": 1505805826302
  31. }
  32. liyuechun:contracts yuechunli$

Snip20170919_15.png

编译成功后,会在HelloWorld文件夹下面的build/contracts文件夹下面看见HelloWorld.json文件。

部署

truffle框架中提供了方便部署合约的脚本。打开migrations/2_deploy_contracts.js文件(脚本使用Javascript编写),将内容修改如下:

  1. var HelloWorld = artifacts.require("HelloWorld");
  2. module.exports = function(deployer) {
  3. deployer.deploy(HelloWorld);
  4. };

Snip20170919_17.png

使用artifacts.require语句来取得准备部署的合约。使用deployer.deploy语句将合约部署到区块链上。这边HelloWorldcontract的名称而不是文件名。因此可以用此语法读入任一.sol文件中的任一合约。

现在执行truffle migrate命令:

  1. liyuechun:HelloWorld yuechunli$ ls
  2. build contracts migrations test truffle.js
  3. liyuechun:HelloWorld yuechunli$ truffle migrate
  4. Compiling ./contracts/HelloWorld.sol...
  5. Writing artifacts to ./build/contracts
  6. Using network 'development'.
  7. Running migration: 1_initial_migration.js
  8. Deploying Migrations...
  9. ... 0x218431f16a5cadc6347449808d981887c90b3872898af7cc9dc9b3280c07c184
  10. Migrations: 0x64e9673cf962d21642a08635e6654fb7f2ea9bcd
  11. Saving successful migration to network...
  12. ... 0xd9ec788c106df36b8491c95a0ab02ff1e5ef22c1965c910a2576e8259a00535c
  13. Saving artifacts...
  14. Running migration: 2_deploy_contracts.js
  15. Deploying HelloWorld...
  16. ... 0x17774b4914d7bc7ab2505a53c59bda6a1fce30c9839d19d735290ca9140450ea
  17. HelloWorld: 0x471a22ffe2bddd02e82853059871067e4c07a7f4
  18. Saving successful migration to network...
  19. ... 0xe5e2e11cf5a63ca4517221c68dadb3cae2ca42cbfed93c09c575b6d5f275fc8b
  20. Saving artifacts...
  21. liyuechun:HelloWorld yuechunli$

如此一来合约已经部署到testrpc中。切换到testrpc窗口,可以看到testrpc有反应了。

Snip20170919_18.png

与合约互动

truffle提供命令行工具,执行truffle console命令后,可用Javascript来和刚刚部署的合约互动。

  1. liyuechun:HelloWorld yuechunli$ ls
  2. build contracts migrations test truffle.js
  3. liyuechun:HelloWorld yuechunli$ truffle console
  4. truffle(development)> HelloWorld.deployed().then(instance => contract = instance)
  5. TruffleContract {
  6. constructor:
  7. { [Function: TruffleContract]
  8. _static_methods:
  9. { setProvider: [Function: setProvider],
  10. new: [Function: new],
  11. at: [Function: at],
  12. deployed: [Function: deployed],
  13. defaults: [Function: defaults],
  14. hasNetwork: [Function: hasNetwork],
  15. isDeployed: [Function: isDeployed],
  16. detectNetwork: [Function: detectNetwork],
  17. setNetwork: [Function: setNetwork],
  18. resetAddress: [Function: resetAddress],
  19. link: [Function: link],
  20. clone: [Function: clone],
  21. addProp: [Function: addProp],
  22. toJSON: [Function: toJSON] },
  23. _properties:
  24. { contract_name: [Object],
  25. abi: [Object],
  26. network: [Function: network],
  27. networks: [Function: networks],
  28. address: [Object],
  29. links: [Function: links],
  30. events: [Function: events],
  31. binary: [Function: binary],
  32. unlinked_binary: [Object],
  33. schema_version: [Function: schema_version],
  34. updated_at: [Function: updated_at] },
  35. _property_values: {},
  36. _json:
  37. { contract_name: 'HelloWorld',
  38. default_network: undefined,
  39. abi: [Array],
  40. unlinked_binary: '0x6060604052341561000f57600080fd5b5b6101488061001f6000396000f300606060405263ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663ef5fb05b811461003d575b600080fd5b341561004857600080fd5b6100506100c8565b60405160208082528190810183818151815260200191508051906020019080838360005b8381101561008d5780820151818401525b602001610074565b50505050905090810190601f1680156100ba5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6100d061010a565b60408051908101604052600b81527f48656c6c6f20576f726c64000000000000000000000000000000000000000000602082015290505b90565b602060405190810160405260008152905600a165627a7a723058202b9d4dd8e7739264271524ea58db573fa09a0b634d1d5b78502e6dd01d76ba330029',
  41. networks: [Object],
  42. schema_version: '0.0.5',
  43. updated_at: 1505806918535 },
  44. setProvider: [Function: bound setProvider],
  45. new: [Function: bound new],
  46. at: [Function: bound at],
  47. deployed: [Function: bound deployed],
  48. defaults: [Function: bound defaults],
  49. hasNetwork: [Function: bound hasNetwork],
  50. isDeployed: [Function: bound isDeployed],
  51. detectNetwork: [Function: bound detectNetwork],
  52. setNetwork: [Function: bound setNetwork],
  53. resetAddress: [Function: bound resetAddress],
  54. link: [Function: bound link],
  55. clone: [Function: bound clone],
  56. addProp: [Function: bound addProp],
  57. toJSON: [Function: bound toJSON],
  58. web3:
  59. Web3 {
  60. _requestManager: [Object],
  61. currentProvider: [Object],
  62. eth: [Object],
  63. db: [Object],
  64. shh: [Object],
  65. net: [Object],
  66. personal: [Object],
  67. bzz: [Object],
  68. settings: [Object],
  69. version: [Object],
  70. providers: [Object],
  71. _extend: [Object] },
  72. class_defaults:
  73. { from: '0xbbd414b340f2255dab9d923428c97f0b65d9df81',
  74. gas: 4712388,
  75. gasPrice: 100000000000 },
  76. currentProvider:
  77. HttpProvider {
  78. host: 'http://localhost:8545',
  79. timeout: 0,
  80. send: [Function],
  81. sendAsync: [Function],
  82. _alreadyWrapped: true },
  83. network_id: '1505794143155' },
  84. abi:
  85. [ { constant: false,
  86. inputs: [],
  87. name: 'sayHello',
  88. outputs: [Array],
  89. payable: false,
  90. type: 'function' } ],
  91. contract:
  92. Contract {
  93. _eth:
  94. Eth {
  95. _requestManager: [Object],
  96. getBalance: [Object],
  97. getStorageAt: [Object],
  98. getCode: [Object],
  99. getBlock: [Object],
  100. getUncle: [Object],
  101. getCompilers: [Object],
  102. getBlockTransactionCount: [Object],
  103. getBlockUncleCount: [Object],
  104. getTransaction: [Object],
  105. getTransactionFromBlock: [Object],
  106. getTransactionReceipt: [Object],
  107. getTransactionCount: [Object],
  108. call: [Object],
  109. estimateGas: [Object],
  110. sendRawTransaction: [Object],
  111. signTransaction: [Object],
  112. sendTransaction: [Object],
  113. sign: [Object],
  114. compile: [Object],
  115. submitWork: [Object],
  116. getWork: [Object],
  117. coinbase: [Getter],
  118. getCoinbase: [Object],
  119. mining: [Getter],
  120. getMining: [Object],
  121. hashrate: [Getter],
  122. getHashrate: [Object],
  123. syncing: [Getter],
  124. getSyncing: [Object],
  125. gasPrice: [Getter],
  126. getGasPrice: [Object],
  127. accounts: [Getter],
  128. getAccounts: [Object],
  129. blockNumber: [Getter],
  130. getBlockNumber: [Object],
  131. protocolVersion: [Getter],
  132. getProtocolVersion: [Object],
  133. iban: [Object],
  134. sendIBANTransaction: [Function: bound transfer] },
  135. transactionHash: null,
  136. address: '0x471a22ffe2bddd02e82853059871067e4c07a7f4',
  137. abi: [ [Object] ],
  138. sayHello:
  139. { [Function: bound ]
  140. request: [Function: bound ],
  141. call: [Function: bound ],
  142. sendTransaction: [Function: bound ],
  143. estimateGas: [Function: bound ],
  144. getData: [Function: bound ],
  145. '': [Circular] },
  146. allEvents: [Function: bound ] },
  147. sayHello:
  148. { [Function]
  149. call: [Function],
  150. sendTransaction: [Function],
  151. request: [Function: bound ],
  152. estimateGas: [Function] },
  153. sendTransaction: [Function],
  154. send: [Function],
  155. allEvents: [Function: bound ],
  156. address: '0x471a22ffe2bddd02e82853059871067e4c07a7f4',
  157. transactionHash: null }
  158. truffle(development)> contract.sayHello.call()
  159. 'Hello World'
  160. truffle(development)>

讲解

  1. HelloWorld.deployed().then(instance => contract = instance)

truffle console中预载了truffle-contract函数库,以方便操作部署到区块链上的合约。

这边使用HelloWorld.deployed().then语句来取得HelloWorld合约的Instance(实例),并存到contract变量中,以方便后续的调用。

上面用的是Javascript ES6+的语法,这句也可以写成:

  1. HelloWorld.deployed().then(instance => {
  2. contract = instance
  3. });

还可以用ES5的写法:

  1. HelloWorld.deployed().then(function(instance) {
  2. hello = instance;
  3. });
  4. truffle(development)> contract.sayHello.call()
  5. 'Hello World'

这里直接呼叫contract.sayHello()也会得到一样的结果。truffle-contract提供使用call()来读取只读(read only)的数据,这样就不需提供gas。因此如果遇到的操作需要向区块链写入数据,我们就不能用call语句了。

如此一来,我们已写好并部署完成了第一个智能合约,也验证了合约确实可以运作。

加入新方法

我们在HelloWorld.sol中再加入一个echo方法,echo方法接受输入一个参数,并回传传送的参数。

  1. function echo(string name) constant returns (string) {
  2. return name;
  3. }

新的echo方法中传入了一个name参数。我们也为echo方法加入一个constant声明,表示调用这个方法并不会改变区块链的状态。如此一来,透过truffle-contract来调用此方法时,会自动选用call来呼叫,也不需要额外提供gas。

由于更新了合约内容,我们需要先重新新编译一次,将编译结果部署到testrpc上,再透过truffle console执行看看结果。

  1. liyuechun:HelloWorld yuechunli$ ls
  2. build contracts migrations test truffle.js
  3. liyuechun:HelloWorld yuechunli$ truffle compile
  4. Compiling ./contracts/HelloWorld.sol...
  5. Writing artifacts to ./build/contracts
  6. liyuechun:HelloWorld yuechunli$ truffle migrate --reset
  7. Using network 'development'.
  8. Running migration: 1_initial_migration.js
  9. Replacing Migrations...
  10. ... 0x64cdc42e08a7e3f8070c46d4877ba246d95cbbccbfe1b9abd2450cfc02b48eda
  11. Migrations: 0x42843f6a470b84e2669f19686a223c1bdefb6f4d
  12. Saving successful migration to network...
  13. ... 0x57042b767c0f40a4f88ce855e39549010d6d5ae5f880771a45c1f7f36ea0e5b3
  14. Saving artifacts...
  15. Running migration: 2_deploy_contracts.js
  16. Replacing HelloWorld...
  17. ... 0x2330e3264aae9d6be3744d8fc71d235fc6dc2934d33ff5159ae209df4cf8f12b
  18. HelloWorld: 0xbf68789cdd6be1577339e8c739abfa1190c31b6c
  19. Saving successful migration to network...
  20. ... 0xb4b706d7004654215067ea5954a32f0562b32724d1c646dc43b688b466b10159
  21. Saving artifacts...
  22. liyuechun:HelloWorld yuechunli$ truffle console
  23. truffle(development)> let contract
  24. undefined
  25. truffle(development)> HelloWorld.deployed().then(instance => contract = instance)
  26. TruffleContract {
  27. constructor:
  28. { [Function: TruffleContract]
  29. _static_methods:
  30. { setProvider: [Function: setProvider],
  31. new: [Function: new],
  32. at: [Function: at],
  33. deployed: [Function: deployed],
  34. defaults: [Function: defaults],
  35. hasNetwork: [Function: hasNetwork],
  36. isDeployed: [Function: isDeployed],
  37. detectNetwork: [Function: detectNetwork],
  38. setNetwork: [Function: setNetwork],
  39. resetAddress: [Function: resetAddress],
  40. link: [Function: link],
  41. clone: [Function: clone],
  42. addProp: [Function: addProp],
  43. toJSON: [Function: toJSON] },
  44. _properties:
  45. { contract_name: [Object],
  46. abi: [Object],
  47. network: [Function: network],
  48. networks: [Function: networks],
  49. address: [Object],
  50. links: [Function: links],
  51. events: [Function: events],
  52. binary: [Function: binary],
  53. unlinked_binary: [Object],
  54. schema_version: [Function: schema_version],
  55. updated_at: [Function: updated_at] },
  56. _property_values: {},
  57. _json:
  58. { contract_name: 'HelloWorld',
  59. default_network: undefined,
  60. abi: [Array],
  61. unlinked_binary: '0x6060604052341561000f57600080fd5b5b61022c8061001f6000396000f300606060405263ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663ef5fb05b8114610048578063f15da729146100d3575b600080fd5b341561005357600080fd5b61005b61019c565b60405160208082528190810183818151815260200191508051906020019080838360005b838110156100985780820151818401525b60200161007f565b50505050905090810190601f1680156100c55780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34156100de57600080fd5b61005b60046024813581810190830135806020601f820181900481020160405190810160405281815292919060208401838380828437509496506101de95505050505050565b60405160208082528190810183818151815260200191508051906020019080838360005b838110156100985780820151818401525b60200161007f565b50505050905090810190601f1680156100c55780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101a46101ee565b60408051908101604052600b81527f48656c6c6f20576f726c64000000000000000000000000000000000000000000602082015290505b90565b6101e66101ee565b50805b919050565b602060405190810160405260008152905600a165627a7a723058208fec8695bd430eed53d1591d841c6e80b1a32a91caab996bb270d54425ebd7140029',
  62. networks: [Object],
  63. schema_version: '0.0.5',
  64. updated_at: 1505809278810 },
  65. setProvider: [Function: bound setProvider],
  66. new: [Function: bound new],
  67. at: [Function: bound at],
  68. deployed: [Function: bound deployed],
  69. defaults: [Function: bound defaults],
  70. hasNetwork: [Function: bound hasNetwork],
  71. isDeployed: [Function: bound isDeployed],
  72. detectNetwork: [Function: bound detectNetwork],
  73. setNetwork: [Function: bound setNetwork],
  74. resetAddress: [Function: bound resetAddress],
  75. link: [Function: bound link],
  76. clone: [Function: bound clone],
  77. addProp: [Function: bound addProp],
  78. toJSON: [Function: bound toJSON],
  79. web3:
  80. Web3 {
  81. _requestManager: [Object],
  82. currentProvider: [Object],
  83. eth: [Object],
  84. db: [Object],
  85. shh: [Object],
  86. net: [Object],
  87. personal: [Object],
  88. bzz: [Object],
  89. settings: [Object],
  90. version: [Object],
  91. providers: [Object],
  92. _extend: [Object] },
  93. class_defaults:
  94. { from: '0xbbd414b340f2255dab9d923428c97f0b65d9df81',
  95. gas: 4712388,
  96. gasPrice: 100000000000 },
  97. currentProvider:
  98. HttpProvider {
  99. host: 'http://localhost:8545',
  100. timeout: 0,
  101. send: [Function],
  102. sendAsync: [Function],
  103. _alreadyWrapped: true },
  104. network_id: '1505794143155' },
  105. abi:
  106. [ { constant: false,
  107. inputs: [],
  108. name: 'sayHello',
  109. outputs: [Array],
  110. payable: false,
  111. type: 'function' },
  112. { constant: true,
  113. inputs: [Array],
  114. name: 'echo',
  115. outputs: [Array],
  116. payable: false,
  117. type: 'function' } ],
  118. contract:
  119. Contract {
  120. _eth:
  121. Eth {
  122. _requestManager: [Object],
  123. getBalance: [Object],
  124. getStorageAt: [Object],
  125. getCode: [Object],
  126. getBlock: [Object],
  127. getUncle: [Object],
  128. getCompilers: [Object],
  129. getBlockTransactionCount: [Object],
  130. getBlockUncleCount: [Object],
  131. getTransaction: [Object],
  132. getTransactionFromBlock: [Object],
  133. getTransactionReceipt: [Object],
  134. getTransactionCount: [Object],
  135. call: [Object],
  136. estimateGas: [Object],
  137. sendRawTransaction: [Object],
  138. signTransaction: [Object],
  139. sendTransaction: [Object],
  140. sign: [Object],
  141. compile: [Object],
  142. submitWork: [Object],
  143. getWork: [Object],
  144. coinbase: [Getter],
  145. getCoinbase: [Object],
  146. mining: [Getter],
  147. getMining: [Object],
  148. hashrate: [Getter],
  149. getHashrate: [Object],
  150. syncing: [Getter],
  151. getSyncing: [Object],
  152. gasPrice: [Getter],
  153. getGasPrice: [Object],
  154. accounts: [Getter],
  155. getAccounts: [Object],
  156. blockNumber: [Getter],
  157. getBlockNumber: [Object],
  158. protocolVersion: [Getter],
  159. getProtocolVersion: [Object],
  160. iban: [Object],
  161. sendIBANTransaction: [Function: bound transfer] },
  162. transactionHash: null,
  163. address: '0xbf68789cdd6be1577339e8c739abfa1190c31b6c',
  164. abi: [ [Object], [Object] ],
  165. sayHello:
  166. { [Function: bound ]
  167. request: [Function: bound ],
  168. call: [Function: bound ],
  169. sendTransaction: [Function: bound ],
  170. estimateGas: [Function: bound ],
  171. getData: [Function: bound ],
  172. '': [Circular] },
  173. echo:
  174. { [Function: bound ]
  175. request: [Function: bound ],
  176. call: [Function: bound ],
  177. sendTransaction: [Function: bound ],
  178. estimateGas: [Function: bound ],
  179. getData: [Function: bound ],
  180. string: [Circular] },
  181. allEvents: [Function: bound ] },
  182. sayHello:
  183. { [Function]
  184. call: [Function],
  185. sendTransaction: [Function],
  186. request: [Function: bound ],
  187. estimateGas: [Function] },
  188. echo:
  189. { [Function]
  190. call: [Function],
  191. sendTransaction: [Function],
  192. request: [Function: bound ],
  193. estimateGas: [Function] },
  194. sendTransaction: [Function],
  195. send: [Function],
  196. allEvents: [Function: bound ],
  197. address: '0xbf68789cdd6be1577339e8c739abfa1190c31b6c',
  198. transactionHash: null }
  199. truffle(development)> contract.echo("春哥微信:liyc1215")
  200. '春哥微信:liyc1215'
  201. truffle(development)>

echo方法确实将我们输入的内容回传了。同时因为声明了constant,我们不需要直接调用call()方法,truffle会自动选用call来呼叫。

另一点需要注意的,是这次如果还是用truffle migrate命令,我们会得到如下信息:

  1. $ truffle migrate
  2. Using network 'development'.
  3. Network up to date.

Truffle会告诉你现在网络上的合约都已是最新的,但事实上刚刚程序中新增的方法并没有更新到内存块链上。要更新内存块链上已部署的程序,需要改写migrations中的脚本,但现在还不到介绍migration的时候。还好我们开发用的内存块链是怎么修改都没关系的testrpc,可以使用truffle migrate --reset命令直接重新在testrpc上部署一次。

总结

这篇文章非常简单,通过这篇文章,你将掌握如何配置开发环境、如何创建新项目、如何编译、如何部署合约以及了解整个智能合约开发的流程。

发表评论

表情:
评论列表 (有 0 条评论,426人围观)

还没有评论,来说两句吧...

相关阅读

    相关 智能合约 简介

    以太坊是一个分布式的计算平台。它会生成一个名为Ether的加密货币。程序员可以在以太坊区块链上写下“智能合约”,这些以太坊智能合约会根据代码自动执行。 以太坊是什么?