【轉】以太坊合約部署總結


一、基本說明
以太坊目前還處於頻繁更新的階段,后續相關接口可能會有變化。當前本文對應以太坊的0.2x.x版本。

二、合約編譯
編寫好合約代碼之后,需要將合約編譯為字節碼,並為了后續調用以及供其他人調用,還需要保存下ABI(Application Binary Interface)。不管是本地安裝了solidify使用solc編譯,還是在線編譯(https://remix.ethereum.org),都會得到兩個數據,abi和bin,bin即為按16進制輸出的二進制代碼。

關於包含library庫的合約的編譯說明:
如果你的合約使用了libraries,按正常方式編譯后會發現字節碼中會包含類似“__LibraryName________”的字符串。這是因為,在編譯的時候編譯器還不知道你所使用的庫的地址,所以這里提供了占位字符串。對於這種情況,需要我們人工指定庫部署在鏈上的地址。
也就是:
1、部署合約前,需要先部署好需要用到的庫(其實每個庫也都是一個合約,只是它比較特殊而已),獲取庫地址。
2、編譯合約時,可以通過指定 --libraries “LibraryName:libraryaddress” 參數來提供庫地址,多個“庫名:庫地址”對之間可以用逗號或空格分隔,如
--libraries "IterableMapping:0xf912c00b0c9ec43c0171a42c276e445f7a186f69”;庫地址的前導0x可有可無。
3、當然編譯時不指定--libraries參數也可以,這樣可以在編譯完成后,人工將占位字符串替換為庫地址。這種操作下,庫地址就是不包含0x的了,如用“f912c00b0c9ec43c0171a42c276e445f7a186f69”完整替換占位字符串。
三、合約部署
合約部署有兩種方式,通過web3控制台部署編程通過RPC部署。
(一)web3控制台部署合約
注意:部署前需要解鎖賬戶。以下假定賬戶已經解鎖
1、指定abi
形式:
abi = web3.eth.contract(abijson)
例如:
abi = web3.eth.contract([{"constant":false,"inputs":[{"name":"x","type":"uint256"}],"name":"set","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function”}])


2、使用new方法部署合約
形式:
abi.new([constructorParam1] [, constructorParam2], {data: '0x12345...', from: myAccount, gas: 1000000},callback);

合約構造函數參數,依序寫在new方法的前面部分,若沒有構造函數參數,就不用傳。之后大括號{}括起來的是合約數據,data即為編譯好的bin,from為創建合約的賬戶,其他相關字段與發送Transaction的字段相同,但是創建合約不能帶to字段;最后部分為部署合約的回調函數,可在回調函數中做部署完成后的處理。

示例:
co = abi.new(
{
from: web3.eth.accounts[0],
data: '0x6060604052341561000f57600080fd5b60d38061001d6000396000f3006060604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c14606e575b600080fd5b3415605857600080fd5b606c60048080359060200190919050506094565b005b3415607857600080fd5b607e609e565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a723058203f073b26521b71d3298f38d48d6d13cea0331654cc49f4754094cdb870e20e5b0029',
gas: '4700000'
}, function (e, contract){
console.log(e, contract);
if (typeof contract.address !== 'undefined') {
console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
}
})


部署成功並被打包到區塊中之后,將會看到類似如下輸出:
Contract mined! address: 0x3e789ab8b916317ee64f33d2b03b44e2d41ade4b transactionHash: 0xc70ac1d1afeb622abda6215e767123a1c38edeba5ec6c635b02266879fabc185

同時,該合約被賦值給了變量co,可以使用co查看合約的信息、調用合約的函數。

若沒有提供回調函數,可以通過自行查看合約的transactionHash和address屬性來查看狀態
co.transactionHash // 創建合約的交易哈希
co.address // 合約賬戶地址,一開始是未定義的,但后續(部署成功后)會被自動填充。

3、與合約交互
對已部署在鏈上的合約,可以與之進行交互。
在上述步驟部署好合約后,可以直接通過變量co進行交互。
若是重啟了節點或與其他人部署的合約進行交互,可以使用 at方法獲取已部署在鏈上的合約,如下:
abi = web3.eth.contract([{"constant":false,"inputs":[{"name":"x","type":"uint256"}],"name":"set","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function”}])
co = abi.at("0x3e789ab8b916317ee64f33d2b03b44e2d41ade4b”)

合約函數調用,有兩種方式:sendTransaction和call,其中前者是真正發起交易更改合約存儲狀態的,結果會持久反映到區塊鏈中call只在本地執行。詳見 http://ethdoc.cn/contracts-and-transactions/contracts.html#id17 的“合約交互”部分
當使用 call 時,函數會在本地的虛擬機(EVM)上執行,調用的返回值就是函數的返回值。這種方式的調用不會被紀錄在區塊鏈中,因此也不會改變合約的內部狀態,這種方式被稱為常量函數調用。這種調用方式不需要手續費。

形式:
co.functionName.Call(arg0,arg1,{from:account})
co.functionName.SendTransaction(arg0,arg1,{from:account})
對於不需要參數的call調用,可以簡化為
co.functionName()

示例:
co.set.call(100,{from:"0x55b3f3f1ec65973d1f5cdb515fb9c761d3122179"})

co.set.sendTransaction(100,{from:"0x55b3f3f1ec65973d1f5cdb515fb9c761d3122179"});

co.get.call()
co.get()

說明:合約的public狀態變量,會自動提供getter方法,例如如下的合約:
contract Token {
    /// total amount of tokens
    uint256 public totalSupply;
……
}
會自動提供一個名為totalSupply的無參數function。

(二)以RPC方式編程部署合約及於合約交互
1、使用RPC方式編程部署合約,主要使用的RPC接口是sendTransaction。
對於部署合約,可以使用 personal_sendTransaction或eth_sendTransaction,前者可以提供密碼參數,從而不需要賬戶先解鎖,后者需要賬戶先解鎖。
注意:對於與合約交互,只能使用eth_sendTransaction,對於需要改變合約狀態的調用,需要先解鎖賬戶。

合約部署時,transaction對象的data字段為編譯好的合約字節碼,to字段留空,其他字段含義與發送普通交易相同。(to字段留空表示創建合約,data字段有內容就會啟動虛擬機執行)。

基本說明參考:https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sendtransaction
需要注意的是:
對於構造函數需要傳入參數的合約部署,需要將參數進行編碼,將編碼后的數據直接跟在合約代碼(編譯后的16進制表示的字節碼)后面。合約參數編碼方式,參考:https://solidity-cn.readthedocs.io/zh/develop/abi-spec.html#abi
但是不需要構造函數的函數簽名哈希的前四個字節。也就是直接考慮參數編碼即可。

2、與合約交互
使用eth_sendTransaction與合約進行交互,transaction的to字段為合約地址,data字段為函數簽名及參數的編碼結果。
編碼方式參考:https://solidity-cn.readthedocs.io/zh/develop/abi-spec.html#

注意:計算函數簽名的哈希時,參數類型如果涉及到類型別名,則需要使用其權威類型代替。
例如以下函數
function insert(uint k, uint v) public returns (uint)
{
    ……
}
待計算哈希的函數簽名應該為"insert(uint256,uint256)”
別名與權威表示列表如下:

別名 權威表示
byte
bytes1
uint
uint256
int
int256
ufixed
ufixed128x19
fixed
fixed128x19
另:address和uint160表現相同,但是在計算函數簽名時直接使用address,如”balanceOf(address)”。編碼時是左邊補0。
var addr common.Address = common.HexToAddress("0x71af77518da8ee1e152068ea4727d1041d71b813”)
addrBytes := addr.Hash().Bytes()
---------------------
作者:Darlzan
來源:CSDN
原文:https://blog.csdn.net/notjusttech/article/details/79979330
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM