如何編寫智慧合約之一:智慧合約編寫、編譯以及部署

NO IMAGE

開發環境配置

  1. 安裝truffle. 在命令列下執行(已經有npm環境)
MacBook-Pro:~  zhi$ npm install -g truffle
/usr/local/bin/truffle -> /usr/local/lib/node_modules/truffle/build/cli.bundled.js
/usr/local/lib
└── [email protected] 

使用truffle命令檢視版本資訊

MacBook-Pro:~  zhi$ truffle version
Truffle v4.0.4 (core: 4.0.4)
Solidity v0.4.18 (solc-js)

使用truffle初始化一個測試專案

MacBook-Pro:~  zhi$ mkdir -p ~/Ethereum/demo1
MacBook-Pro:~  zhi$ cd ~/Ethereum/demo1
MacBook-Pro:~  zhi$ truffle init
Downloading...
Unpacking...
Setting up...
Unbox successful. Sweet!
Commands:
Compile:        truffle compile
Migrate:        truffle migrate
Test contracts: truffle test

初始化之後,所在資料夾下會建立一些資料夾以及檔案:
|—contracts 用於存放合約的資料夾,我們新增的合約都放在這裡
|—migrations 指導合約編譯的檔案
|————-1_initial_migration.js
|————-2_initial_hello.js
|—test 測試目錄
|—truffle-config.js 配置檔案
|—truffle.js

  1. 建立Hello.sol合約檔案,並儲存在truffle初始化後的contracts資料夾中。檔案內容:
pragma solidity ^0.4.18;
contract Hello{
function test() pure public returns (string){
return "It is test!";
}
function test1() pure public returns (string){
return "test1!";
}
function echo(string s) pure public returns (string){
return s;
}
}
  1. 進入命令列編譯以及部署操作
    進入truffle命令列,執行truffle develop命令
MacBook-Pro:~  zhi$ truffle develop
Truffle Develop started at http://localhost:9545/
Accounts:
(0) 0x627306090abab3a6e1400e9345bc60c78a8bef57
(1) 0xf17f52151ebef6c7334fad080c5704d77216b732
(2) 0xc5fdf4076b8f3a5357c5e395ab970b5b54098fef
(3) 0x821aea9a577a9b44299b9c15c88cf3087f3b5544
(4) 0x0d1d4e623d10f9fba5db95830f7d3839406c6af2
(5) 0x2932b7a2355d6fecc4b5c0b6bd44cc31df247a2e
(6) 0x2191ef87e392377ec08e7c08eb105ef5448eced5
(7) 0x0f4f2ac550a1b4e2280d04c21cea7ebd822934b5
(8) 0x6330a553fc93768f612722bb8c2ec78ac90b3bbc
(9) 0x5aeda56215b167893e80b4fe645ba6d5bab767de
Private Keys:
(0) c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3
(1) ae6ae8e5ccbfb04590405997ee2d52d2b330726137b875053c36d94e974d162f
(2) 0dbbe8e4ae425a6d2687f1a7e3ba17bc98c673636790f1b8ad91193c05875ef1
(3) c88b703fb08cbea894b6aeff5a544fb92e78a18e19814cd85da83b71f772aa6c
(4) 388c684f0ba1ef5017716adb5d21a053ea8e90277d0868337519f97bede61418
(5) 659cbb0e2411a44db63778987b1e22153c086a95eb6b18bdf89de078917abc63
(6) 82d052c865f5763aad42add438569276c00d3d88a2d062d36b2bae914d58b8c8
(7) aa3680d5d48a8283413f7a108367c7299ca73f553735860a87b08f39395618b7
(8) 0f62d96d6675f32685bbdb8ac13cda7c23436f63efbb9d07700d8669ff12b7c4
(9) 8d5366123cb560bb606379f90a0bfd4769eecc0557f1b362dcae9012b548b1e5
Mnemonic: candy maple cake sugar pudding cream honey rich smooth crumble sweet treat

編譯,執行命令compile

truffle(develop)> compile
Compiling ./contracts/Hello.sol...
Compiling ./contracts/Migrations.sol...
Writing artifacts to ./build/contracts

部署,執行命令migrate

truffle(develop)> migrate
Using network 'develop'.
Running migration: 1_initial_migration.js
Deploying Migrations...
... 0x058f644af8801388e6a6116ea00c163645dfc1c8636e096e6ed11cdd0d2e8c54
Migrations: 0x8cdaf0cd259887258bc13a92c0a6da92698644c0
Saving successful migration to network...
... 0xd7bc86d31bee32fa3988f1c1eabce403a1b5d570340a3a9cdba53a472ee8c956
Saving artifacts...
Running migration: 2_initial_migration.js
Deploying Hello...
... 0x93b1578047b7db49016168b1d0e480218d552fa7e5b53f1d81cc0e00f567239b
Hello: 0x345ca3e014aaf5dca488057592ee47305d9b3e10
Saving successful migration to network...
... 0xf36163615f41ef7ed8f4a8f192149a0bf633fe1a2398ce001bf44c43dc7bdda0
Saving artifacts...

如果之前部署過,在執行命令後,可能不是出現上面的資訊,而是出現

Using network 'develop'.
Network up to date.

表示的是,合約沒有過期,這次部署沒有成功。此時需要在部署命令後新增一個reset引數即可部署成功。完整命令migrate --reset

  1. 獲取合約例項。將合約例項賦值給contract變數,執行命令Hello.deployed().then(instance => contract = instance)
truffle(develop)> let contract;
undefined
truffle(develop)> Hello.deployed().then(instance => contract = instance)
TruffleContract {
constructor: 
{ [Function: TruffleContract]
_static_methods: 
{ setProvider: [Function: setProvider],
new: [Function: new],
at: [Function: at],
deployed: [Function: deployed],
defaults: [Function: defaults],
hasNetwork: [Function: hasNetwork],
isDeployed: [Function: isDeployed],
detectNetwork: [Function: detectNetwork],
setNetwork: [Function: setNetwork],
resetAddress: [Function: resetAddress],
link: [Function: link],
clone: [Function: clone],
addProp: [Function: addProp],
toJSON: [Function: toJSON] },
_properties: 
{ contract_name: [Object],
contractName: [Object],
abi: [Object],
network: [Function: network],
networks: [Function: networks],
address: [Object],
links: [Function: links],
events: [Function: events],
binary: [Function: binary],
deployedBinary: [Function: deployedBinary],
unlinked_binary: [Object],
bytecode: [Object],
deployedBytecode: [Object],
sourceMap: [Object],
deployedSourceMap: [Object],
source: [Object],
sourcePath: [Object],
ast: [Object],
compiler: [Object],
schema_version: [Function: schema_version],
schemaVersion: [Function: schemaVersion],
updated_at: [Function: updated_at],
updatedAt: [Function: updatedAt] },
_property_values: {},
_json: 
{ contractName: 'Hello',
abi: [Object],
bytecode: '0x6060604052341561000f57600080fd5b6103248061001e6000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680636b59084d1461005c578063f15da729146100ea578063f8a8fd6d146101c0575b600080fd5b341561006757600080fd5b61006f61024e565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100af578082015181840152602081019050610094565b50505050905090810190601f1680156100dc5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34156100f557600080fd5b610145600480803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091905050610291565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561018557808201518184015260208101905061016a565b50505050905090810190601f1680156101b25780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34156101cb57600080fd5b6101d36102a1565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156102135780820151818401526020810190506101f8565b50505050905090810190601f1680156102405780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102566102e4565b6040805190810160405280600881526020017f4e6f207075726521000000000000000000000000000000000000000000000000815250905090565b6102996102e4565b819050919050565b6102a96102e4565b6040805190810160405280600b81526020017f4974206973207465737421000000000000000000000000000000000000000000815250905090565b6020604051908101604052806000815250905600a165627a7a72305820f8b8cb5819d0882b82e8e56db58138459357c31c23dbb9760f17111a8011b9490029',
deployedBytecode: '0x606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680636b59084d1461005c578063f15da729146100ea578063f8a8fd6d146101c0575b600080fd5b341561006757600080fd5b61006f61024e565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100af578082015181840152602081019050610094565b50505050905090810190601f1680156100dc5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34156100f557600080fd5b610145600480803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091905050610291565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561018557808201518184015260208101905061016a565b50505050905090810190601f1680156101b25780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34156101cb57600080fd5b6101d36102a1565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156102135780820151818401526020810190506101f8565b50505050905090810190601f1680156102405780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102566102e4565b6040805190810160405280600881526020017f4e6f207075726521000000000000000000000000000000000000000000000000815250905090565b6102996102e4565b819050919050565b6102a96102e4565b6040805190810160405280600b81526020017f4974206973207465737421000000000000000000000000000000000000000000815250905090565b6020604051908101604052806000815250905600a165627a7a72305820f8b8cb5819d0882b82e8e56db58138459357c31c23dbb9760f17111a8011b9490029',
sourceMap: '26:249:0:-;;;;;;;;;;;;;;;;;',
deployedSourceMap: '26:249:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;124:73;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:2;8:100;;;99:1;94:3;90;84:5;80:1;75:3;71;64:6;52:2;49:1;45:3;40:15;;8:100;;;12:14;3:109;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;201:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:2;8:100;;;99:1;94:3;90;84:5;80:1;75:3;71;64:6;52:2;49:1;45:3;40:15;;8:100;;;12:14;3:109;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;45:75:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:2;8:100;;;99:1;94:3;90;84:5;80:1;75:3;71;64:6;52:2;49:1;45:3;40:15;;8:100;;;12:14;3:109;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;124:73:0;162:6;;:::i;:::-;175:17;;;;;;;;;;;;;;;;;;;;124:73;:::o;201:71::-;246:6;;:::i;:::-;266:1;259:8;;201:71;;;:::o;45:75::-;82:6;;:::i;:::-;95:20;;;;;;;;;;;;;;;;;;;;45:75;:::o;26:249::-;;;;;;;;;;;;;;;:::o',
source: 'pragma solidity ^0.4.18;\n\ncontract Hello{\n\n  function test() pure public returns (string){\n    return "It is test!";\n  }\n\n  function test1() pure public returns (string){\n    return "No pure!";\n  }\n\n  function echo(string s) pure public returns (string){\n    return s;\n  }\n\n}\n',
sourcePath: '/Users/ zhi/Ethereum/demo1/contracts/Hello.sol',
ast: [Object],
compiler: [Object],
networks: [Object],
schemaVersion: '1.0.1',
updatedAt: '2018-01-11T08:33:44.367Z' },
setProvider: [Function: bound setProvider],
new: [Function: bound new],
at: [Function: bound at],
deployed: [Function: bound deployed],
defaults: [Function: bound defaults],
hasNetwork: [Function: bound hasNetwork],
isDeployed: [Function: bound isDeployed],
detectNetwork: [Function: bound detectNetwork],
setNetwork: [Function: bound setNetwork],
resetAddress: [Function: bound resetAddress],
link: [Function: bound link],
clone: [Function: bound clone],
addProp: [Function: bound addProp],
toJSON: [Function: bound toJSON],
web3: 
Web3 {
_requestManager: [Object],
currentProvider: [Object],
eth: [Object],
db: [Object],
shh: [Object],
net: [Object],
personal: [Object],
bzz: [Object],
settings: [Object],
version: [Object],
providers: [Object],
_extend: [Object] },
class_defaults: 
{ from: '0x627306090abab3a6e1400e9345bc60c78a8bef57',
gas: 6721975,
gasPrice: 100000000000 },
currentProvider: 
HttpProvider {
host: 'http://localhost:9545/',
timeout: 0,
user: undefined,
password: undefined,
send: [Function],
sendAsync: [Function],
_alreadyWrapped: true },
network_id: '4447' },
abi: 
[ { constant: true,
inputs: [],
name: 'test1',
outputs: [Object],
payable: false,
stateMutability: 'pure',
type: 'function' },
{ constant: true,
inputs: [Object],
name: 'echo',
outputs: [Object],
payable: false,
stateMutability: 'pure',
type: 'function' },
{ constant: true,
inputs: [],
name: 'test',
outputs: [Object],
payable: false,
stateMutability: 'pure',
type: 'function' } ],
contract: 
Contract {
_eth: 
Eth {
_requestManager: [Object],
getBalance: [Object],
getStorageAt: [Object],
getCode: [Object],
getBlock: [Object],
getUncle: [Object],
getCompilers: [Object],
getBlockTransactionCount: [Object],
getBlockUncleCount: [Object],
getTransaction: [Object],
getTransactionFromBlock: [Object],
getTransactionReceipt: [Object],
getTransactionCount: [Object],
call: [Object],
estimateGas: [Object],
sendRawTransaction: [Object],
signTransaction: [Object],
sendTransaction: [Object],
sign: [Object],
compile: [Object],
submitWork: [Object],
getWork: [Object],
coinbase: [Getter],
getCoinbase: [Object],
mining: [Getter],
getMining: [Object],
hashrate: [Getter],
getHashrate: [Object],
syncing: [Getter],
getSyncing: [Object],
gasPrice: [Getter],
getGasPrice: [Object],
accounts: [Getter],
getAccounts: [Object],
blockNumber: [Getter],
getBlockNumber: [Object],
protocolVersion: [Getter],
getProtocolVersion: [Object],
iban: [Object],
sendIBANTransaction: [Function: bound transfer] },
transactionHash: null,
address: '0x345ca3e014aaf5dca488057592ee47305d9b3e10',
abi: [ [Object], [Object], [Object] ],
test1: 
{ [Function: bound ]
request: [Function: bound ],
call: [Function: bound ],
sendTransaction: [Function: bound ],
estimateGas: [Function: bound ],
getData: [Function: bound ],
'': [Circular] },
echo: 
{ [Function: bound ]
request: [Function: bound ],
call: [Function: bound ],
sendTransaction: [Function: bound ],
estimateGas: [Function: bound ],
getData: [Function: bound ],
string: [Circular] },
test: 
{ [Function: bound ]
request: [Function: bound ],
call: [Function: bound ],
sendTransaction: [Function: bound ],
estimateGas: [Function: bound ],
getData: [Function: bound ],
'': [Circular] },
allEvents: [Function: bound ] },
test1: 
{ [Function]
call: [Function],
sendTransaction: [Function],
request: [Function: bound ],
estimateGas: [Function] },
echo: 
{ [Function]
call: [Function],
sendTransaction: [Function],
request: [Function: bound ],
estimateGas: [Function] },
test: 
{ [Function]
call: [Function],
sendTransaction: [Function],
request: [Function: bound ],
estimateGas: [Function] },
sendTransaction: [Function],
send: [Function],
allEvents: [Function: bound ],
address: '0x345ca3e014aaf5dca488057592ee47305d9b3e10',
transactionHash: null }

執行了上面命令後,就可以通過contract變數來呼叫合約。要呼叫合約中的方法只需要contract.method(),比如要呼叫Hello合約中的test方法,執行:

truffle(develop)> contract.test();
'It is test!'

PS:這裡呼叫的test方法使用pure進行了修飾,所以可以直接呼叫。如果沒有使用pure進行修飾,那麼呼叫這個test方法,就只能通過call來呼叫:contract.test.call()

到這裡,這個只能合約就編寫、編譯並部署完成了!

參考:
黎躍春 —— 如何編寫智慧合約(Smart Contract)