原文:Transactions
交易是由外部擁有的賬戶發(fā)起的簽名消息,由以太坊網(wǎng)絡傳輸,并記錄(挖掘)在以太坊區(qū)塊鏈上。在這個基本定義的背后舵盈,有許多令人驚訝和迷人的細節(jié)陋率。查看交易的另一種方法是,它們是唯一可以觸發(fā)狀態(tài)更改或?qū)е潞霞s在EVM中執(zhí)行的事物秽晚。以太坊是一個全局單例狀態(tài)機瓦糟,交易是唯一可以使狀態(tài)機“tick”,改變其狀態(tài)的東西赴蝇。合約不是自己運行的菩浙。以太坊不會“在后臺”運行。一切都始于交易句伶。
在本節(jié)中劲蜻,我們將剖析交易,展示它們的工作方式考余,并了解細節(jié)先嬉。
交易結構
首先讓我們看一下交易的基本結構,因為它是在以太坊網(wǎng)絡上序列化和傳輸?shù)某獭=邮招蛄谢灰椎拿總€客戶端和應用程序?qū)⑹褂闷渥约旱膬?nèi)部數(shù)據(jù)結構將其存儲在內(nèi)存中疫蔓,可能使用在網(wǎng)絡序列化交易本身中不存在的元數(shù)據(jù)進行修飾。因此身冬,交易的網(wǎng)絡序列化是交易結構的唯一通用標準衅胀。
交易是包含以下數(shù)據(jù)的序列化二進制消息:
- nonce:由發(fā)起人EOA發(fā)出的序列號,用于防止重播消息酥筝。
- gas price:發(fā)起人愿意支付的gas價格(wei)滚躯。
- start gas:發(fā)起人愿意支付的最大gas量。
- to:目的地以太坊地址。
- value:要發(fā)送到目的地的以太數(shù)量哀九。
- data:可變長度二進制數(shù)據(jù)負載剿配。
- v,r,s:發(fā)起人EOA的ECDSA簽名的三個組成部分。
交易消息的結構使用遞歸長度前綴(RLP)編碼方案(參見[rlp])進行序列化阅束,該方案專為在以太坊中準確和字節(jié)完美的數(shù)據(jù)序列化而創(chuàng)建呼胚。以太坊中的所有數(shù)字都被編碼為big-endian,長度為8位的倍數(shù)息裸。
注意蝇更,為了清楚起見,這里示出了字段標簽(“to”呼盆,“start gas”等)年扩,但不是交易序列化數(shù)據(jù)的一部分,其包含RLP編碼的字段值访圃。通常厨幻,RLP不包含任何字段分隔符或標簽。RLP的長度前綴用于標識每個字段的長度。因此费薄,超出定義長度的任何內(nèi)容都屬于結構中的下一個字段友扰。
雖然這是傳輸?shù)膶嶋H交易結構,但大多數(shù)內(nèi)部表示和用戶界面可視化都通過從交易或區(qū)塊鏈派生的附加信息來修飾格了。
例如,您可能會注意到標識發(fā)起者EOA的地址中沒有“from”數(shù)據(jù)徽鼎。EOA的公鑰可以很容易地從ECDSA簽名的v盛末,r,s組件中獲得否淤。反過來悄但,地址可以很容易地從公鑰中導出。當您看到顯示“from”字段的交易時石抡,該交易由用于可視化交易的軟件添加算墨。客戶端軟件經(jīng)常添加到交易中的其他元數(shù)據(jù)包括區(qū)塊號(一旦被挖掘)和交易ID(計算的哈希)汁雷。同樣净嘀,此數(shù)據(jù)源自交易,而不是交易消息本身的一部分侠讯。
交易中的nonce
nonce是交易中最重要和最不理解的組件之一挖藏。黃色紙的定義是:
nonce:一個標量值,等于從這個地址發(fā)送的交易數(shù)厢漩,或者膜眠,對于關聯(lián)code的帳戶,這個帳戶創(chuàng)建合約的數(shù)量。
嚴格的說宵膨,nonce是發(fā)送地址的屬性(它只在發(fā)送地址的上下文中有意義)架谎。但是,nonce不會明確存儲為區(qū)塊鏈中帳戶狀態(tài)的一部分辟躏。相反谷扣,它是通過計算發(fā)送地址的已確認交易的數(shù)量來動態(tài)計算的。
nonce值還用于防止錯誤計算賬戶余額捎琐。例如会涎,假設一個賬戶的余額為10以太,并簽署兩個交易瑞凑,每個交易花費6個以太末秃,分別為nonce 1和nonce 2。這兩項交易中哪一項有效籽御?在像以太坊這樣的分布式系統(tǒng)中练慕,節(jié)點可能不按順序接收交易。nonce強制來自任何地址的交易按順序處理技掏,沒有間隔铃将,無論節(jié)點接收它們的順序如何。這樣零截,所有節(jié)點都計算出相同的余額麸塞。使用nonce 1支付6 ether的交易將成功處理秃臣,將賬戶余額減少到4以太涧衙。用nonce 2支付6 ether的交易將被所有節(jié)點看作無效,無論它何時被接收奥此。
使用nonce確保所有節(jié)點計算相同的余額和正確的序列交易弧哎,等同于用于防止比特幣“雙重支付”的機制。但是稚虎,由于以太坊跟蹤賬戶余額并且不單獨跟蹤貨幣(在比特幣中稱為UTXO)撤嫩,因此只有在錯誤地計算賬戶余額時才會發(fā)生“雙重支付”。nonce機制可以防止這種情況發(fā)生蠢终。
追蹤nonces
實際上序攘,nonce是源自帳戶的已確認(已開采)交易數(shù)量的最新計數(shù)。要找出nonce是什么寻拂,你可以查詢區(qū)塊鏈程奠,例如通過web3接口:
檢索示例地址的交易計數(shù)
web3.eth.getTransactionCount( “0x9e713963a92c02317a681b9bb3065a8249de124f”)
40
Tip | nonce是一個從零開始的計數(shù)器,這意味著第一個交易具有nonce 0.在檢索我們的示例地址的交易計數(shù)時祭钉,我們的交易計數(shù)為40瞄沙,這意味著已經(jīng)看到了nonce 0到39。下一筆交易的nonce將是40。 |
---|
您的錢包將跟蹤其管理的每個地址的nonce距境。這樣做相當簡單申尼,只要您只從一個點發(fā)起交易即可。假設您正在編寫自己的錢包軟件或其他一些發(fā)起交易的應用程序垫桂。你如何跟蹤nonces师幕?
創(chuàng)建新交易時,將在序列中分配下一個nonce伪货。但在確認之前们衙,它不會計入getTransactionCount總計碱呼。
不幸的是,如果我們連續(xù)發(fā)送一些交易忆蚀,getTransactionCount函數(shù)將遇到一些問題馋袜。有一個已知的錯誤舶斧,getTransactionCount沒有正確計算待處理的交易。我們來看一個例子:
web3.eth.getTransactionCount("0x9e713963a92c02317a681b9bb3065a8249de124f", "pending")
40
web3.eth.sendTransaction({from: web3.eth.accounts[0], to: "0xB0920c523d582040f2BCB1bD7FB1c7C1ECEbdB34", value: web3.toWei(0.01, "ether")});
web3.eth.getTransactionCount("0x9e713963a92c02317a681b9bb3065a8249de124f", "pending")
41
web3.eth.sendTransaction({from: web3.eth.accounts[0], to: "0xB0920c523d582040f2BCB1bD7FB1c7C1ECEbdB34", value: web3.toWei(0.01, "ether")});
web3.eth.getTransactionCount("0x9e713963a92c02317a681b9bb3065a8249de124f", "pending")
41
web3.eth.sendTransaction({from: web3.eth.accounts[0], to: "0xB0920c523d582040f2BCB1bD7FB1c7C1ECEbdB34", value: web3.toWei(0.01, "ether")});
web3.eth.getTransactionCount("0x9e713963a92c02317a681b9bb3065a8249de124f", "pending")
41
如您所見泽台,我們發(fā)送的第一筆交易將交易計數(shù)增加到41,顯示待處理的交易矾缓。但是當我們快速連續(xù)發(fā)送3個以上的交易時怀酷,getTransactionCount調(diào)用沒有正確計算它們。它只計算了一個嗜闻,即使在mempool中有3個待處理的交易蜕依。如果我們等待幾秒鐘,一旦區(qū)塊被挖掘琉雳,getTransactionCount調(diào)用將返回正確的數(shù)字样眠。但在此期間,雖然有多個待處理的交易翠肘,但對我們沒有幫助檐束。
實施構建交易的應用程序時,它不能依賴getTransactionCount來處理待處理的交易锯茄。只有當待處理和確認相等(所有未完成的交易都已確認)時厢塘,您才能信任getTransactionCount的輸出以啟動您的nonce計數(shù)器茶没。此后,在每個交易確認之前跟蹤應用程序中的nonce晚碾。
Parity的JSON RPC接口提供了parity_nextNonce函數(shù)抓半,該函數(shù)返回應在交易中使用的下一個nonce。parity_nextNonce函數(shù)正確計算nonce格嘁,即使您快速連續(xù)構造多個交易笛求,也不確認它們探入。
Parity有一個用于訪問JSON RPC接口的Web控制臺,但在這里我們使用命令行HTTP客戶端來訪問它:
curl --data '{"method":"parity_nextNonce","params":["0x9e713963a92c02317a681b9bb3065a8249de124f"],"id":1,"jsonrpc":"2.0"}' -H "Content-Type: application/json" -X POST localhost:8545
{"jsonrpc":"2.0","result":"0x32","id":1}
nonces植旧,重復nonce和確認間隔
如果以編程方式創(chuàng)建交易,則跟蹤nonce非常重要完沪,尤其是如果您同時從多個獨立進程執(zhí)行此操作。
以太坊網(wǎng)絡基于nonce順序處理交易技健。這意味著如果您使用nonce 0傳輸交易,然后使用nonce 2傳輸交易偿短,則不會挖掘第二個交易。它將存儲在mempool中勾怒,而以太坊網(wǎng)絡則等待丟失的nonce出現(xiàn)段只。所有節(jié)點都將假設缺少的nonce已被簡單地延遲赞枕,并且具有nonce 2的交易是無序接收的莱预。
如果您隨后使用缺失的nonce 1傳輸交易依沮,則將挖掘兩個交易(nonce 1和2)肩狂。一旦填補了空白,網(wǎng)絡就可以挖掘它在mempool中保存的無序交易审磁。
這意味著如果您按順序創(chuàng)建多個交易并且其中一個交易沒有被挖掘,則所有后續(xù)交易都將“卡住”钾恢,等待缺少的nonce稿黍。交易可以在nonce序列中產(chǎn)生無意的“間隔”言沐,因為它無效或者氣體不足吴超。為了讓事情再次運轉(zhuǎn)起來鲸阻,您必須使用缺少的nonce傳輸有效的交易。
另一方面细诸,如果您意外復制了一個nonce震贵,例如通過發(fā)送具有相同nonce但具有不同收件人或值的兩個交易,則其中一個將被確認寇甸,一個將被拒絕。確認哪一個將由它們到達接收它們的第一個驗證節(jié)點的順序確定。
正如您所看到的沪铭,跟蹤nonce是必要的火窒,如果您的應用程序無法正確管理該過程已骇,您將遇到問題。不幸的是浪读,如果您嘗試同時執(zhí)行此操作會變得更加困難,我們將在下一節(jié)中看到痘拆。
并發(fā),交易發(fā)起和nonce
并發(fā)性是計算機科學的一個復雜方面桥氏,有時會出乎意料地出現(xiàn)奕坟,尤其是在像以太坊這樣的分散/分布式實時系統(tǒng)中。
簡單來說桨昙,并發(fā)性是指您可以通過多個獨立系統(tǒng)同時進行計算。這些可以在相同的程序(例如線程)中,在相同的CPU上(例如玛痊,多處理),或在不同的計算機上(即,分布式系統(tǒng))官辽。根據(jù)定義俗批,以太坊是一個允許操作(節(jié)點市怎,客戶端岁忘,DApps)并發(fā)的系統(tǒng),但強制執(zhí)行單例狀態(tài)(例如区匠,每個挖掘的區(qū)塊只有一個系統(tǒng)的公共/共享狀態(tài))干像。
現(xiàn)在,假設我們有多個獨立的錢包應用程序驰弄,它們使用相同的地址生成交易戚篙。這種情況的一個例子是熱錢包的交易所處理提款。理想情況下苗踪,您希望有多個計算機處理提款蛹稍,因此它不會成為堵塞或單點故障奉芦。然而,這很快就會成為問題,因為有多臺計算機產(chǎn)生提款將導致一些棘手的并發(fā)問題瑞眼,其中最重要的是選擇nonce徒像。多臺計算機如何協(xié)調(diào)從同一個熱錢包帳戶生成瞳遍,簽名和廣播交易猾蒂?
您可以使用一臺計算機以先到先得的方式將nonce分配給計算機簽名交易奢讨。但是飒泻,這臺計算機現(xiàn)在是一個單點故障髓霞。更糟糕的是,如果分配了幾個nonce并且其中一個永遠不會被使用(由于計算機處理與該nonce的交易的失斔芗濉)当犯,所有后續(xù)的都會被卡住奠支。
您可以生成交易褥民,但不要對它們進行簽名或為它們分配nonce固耘。然后將它們排隊到一個標記它們的節(jié)點路星,并跟蹤nonce溯街。同樣,你有一個單點的失敗洋丐。對nonce的簽名和跟蹤是您的操作的一部分呈昔,可能會在負載下變得擁擠,而無符號交易的生成是您不需要并行化的部分友绝。您有并發(fā)性堤尾,但在流程的任何有用部分都沒有它。
最后九榔,除了在獨立進程中跟蹤帳戶余額和交易確認的難度之外哀峻,這些并發(fā)問題迫使大多數(shù)實現(xiàn)避免并發(fā)和創(chuàng)建瓶頸涡相,例如處理交易所中的所有提款交易的單個流程哲泊。
交易中的gas
我們在[gas]中詳細討論了gas。但是催蝗,讓我們介紹一下有關交易的gasPrice和startGas組件的作用的一些基礎知識切威。
gas是以太坊的燃料。gas不是以太 - 它是一種單獨的虛擬貨幣丙号,匯率與以太成比例先朦。以太坊使用gas來控制交易可以花費的資源量,因為它將在全球數(shù)千臺計算機上處??理犬缨。開放式(圖靈完成)計算模型需要某種形式的計量喳魏,以避免拒絕服務攻擊或無意的資源吞噬交易。
gas和ether分離怀薛,以保護系統(tǒng)免受隨著ether值的快速變化而可能出現(xiàn)的波動刺彩。
交易中的gasPrice字段允許交易發(fā)起人設置每個單位gas的匯率。gas價格以每單位gas計量枝恋。例如创倔,在我們最近為本書中的一個例子創(chuàng)建的交易中,我們的錢包將gasPrice設置為3 Gwei(3 Giga-wei焚碌,30億wei)畦攘。
熱門網(wǎng)站ethgasstation.info提供有關gas當前價格的信息,以及以太坊主網(wǎng)絡的其他相關gas指標:
錢包可以在它們發(fā)起的交易中調(diào)整gasPrice十电,以實現(xiàn)更快的交易確認(挖掘)知押。gasPrice越高叹螟,交易可能越快確認。相反台盯,優(yōu)先級較低的交易可以降低他們愿意為gas支付的價格首妖,從而導致確認速度變慢∫遥可設置的最低gasPrice為零有缆,這意味著免費交易。在區(qū)塊中對空間的低需求期間温亲,此類交易將被挖掘棚壁。
Tip | 最低可接受的gasPrice為零。這意味著錢包可以生成完全免費的交易栈虚。根據(jù)容量袖外,這些可能永遠不會被挖掘,但協(xié)議中沒有禁止自由交易的內(nèi)容魂务。您可以在以太坊區(qū)塊鏈中找到成功挖掘此類交易的幾個示例曼验。 |
---|
web3界面提供了gasPrice建議,通過計算幾個區(qū)塊的中間價格:
truffle(mainnet)> web3.eth.getGasPrice(console.log)
truffle(mainnet)> null BigNumber {s:1粘姜,e:10鬓照,c:[10000000000]}
與gas有關的第二個重要領域是startGas。這在[gas]中有更詳細的解釋孤紧。簡單來說豺裆,startGas定義了交易發(fā)起人愿意花費多少單位的gas來完成交易。對于簡單付款号显,意味著將ether從一個EOA轉(zhuǎn)移到另一個EOA的交易臭猜,所需的燃氣量固定為21,000個燃氣單位。要計算將花費多少以太押蚤,您需要將21,000乘以您愿意支付的gasPrice:
truffle(mainnet)> web3.eth.getGasPrice(function(err, res) {console.log(res*21000)} )
truffle(mainnet)> 210000000000000
如果您的交易的接收地址是合約蔑歌,那么可以估算所需的gas量,但無法準確確定揽碘。這是因為合約可以評估不同的條件次屠,導致不同的執(zhí)行路徑,不同的gas成本钾菊。這意味著合約可能只執(zhí)行一個簡單的計算或更復雜的計算帅矗,這取決于你無法控制和無法預測的條件。為了證明這一點煞烫,讓我們使用一個精心設計的例子:每次調(diào)用一個合約時浑此,它會遞增一個計數(shù)器,并且在第100次(僅)計算一些復雜的東西滞详。如果你調(diào)用合約99次就會發(fā)生一件事凛俱,但是在第100次調(diào)用時會發(fā)生一些完全不同的事情紊馏。您要支付的gas量取決于在開采交易之前有多少其他交易已經(jīng)調(diào)用該函數(shù)。也許您的估算是基于第99次交易蒲犬,就在您的交易被開采之前朱监,其他人第99次調(diào)用了合約。現(xiàn)在你是第100個要調(diào)用的交易原叮,計算工作量(和gas成本)要高得多赫编。
借用以太坊中使用的常用類比,您可以將startGas視為汽車中的油箱(您的汽車就是交易)奋隶。您可以使用您認為旅程所需的氣體(為驗證交易所需的計算)填充油箱擂送。您可以在一定程度上估算金額,但您的旅程可能會出現(xiàn)意外變化唯欣,例如轉(zhuǎn)移(更復雜的執(zhí)行路徑)嘹吨,這會增加燃油消耗。
然而境氢,與油箱的類比有些誤導蟀拷。它更像是一家加油站公司的信用賬戶,根據(jù)您實際使用的燃氣量萍聊,您可以在旅行結束后付款问芬。當您發(fā)起交易時,第一個驗證步驟之一是檢查它發(fā)送的帳戶是否有足夠以支付gasPrice * startGas的費用脐区。但是愈诚,在交易執(zhí)行結束之前,實際上并未從您的帳戶中扣除金額牛隅。您只需支付最終交易實際消耗的gas費用,但在發(fā)送交易之前酌泰,您必須有足夠的余額支付您愿意支付的最高金額媒佣。
交易的接收者
交易接收者在to字段中指定。這包含一個20字節(jié)的以太坊地址陵刹。地址可以是EOA或合約地址默伍。
以太坊沒有進一步驗證該領域。任何20字節(jié)的值都被認為是有效的衰琐。如果20字節(jié)值對應于沒有相應私鑰的地址也糊,或沒有相應的合約,則該交易仍然有效羡宙。以太坊無法知道地址是否是從公鑰(因此來自私鑰)正確派生的狸剃。
Warning | 以太坊不能也不會驗證交易中的接收者地址。您可以發(fā)送到?jīng)]有相應私鑰或合約的地址狗热,從而“銷毀”以太钞馁,使其永遠丟失虑省。驗證應在用戶界面級別完成。 |
---|
將交易發(fā)送到無效地址將銷毀發(fā)送的以太僧凰,使其永遠無法訪問(不可連接)探颈,因為無法生成簽名來使用它。假設地址驗證發(fā)生在用戶界面級別(參見[eip-55]或[icap])训措。事實上伪节,銷毀以太有很多正當理由,包括作為一種博弈論绩鸣,用來抑制在支付渠道和其他智能合同中作弊架馋。
交易的Value和Data
交易的主要“有效負載”包含在兩個字段中:value和data。交易可以同時具有value和data全闷,僅具有value叉寂,僅具有data,或者既不具有value也不具有data总珠。所有四種組合都有效屏鳍。
僅具有value的交易是付款。僅包含data的交易是調(diào)用局服。既沒有value也沒有data的交易钓瞭,這可能只是浪費gas!但它仍然有可能淫奔。
讓我們嘗試以上所有組合:
首先山涡,我們設置錢包中的發(fā)送地址和接收地址,只是為了讓演示更容易閱讀:
設置發(fā)送和接收地址
src = web3.eth.accounts[0];
dst = web3.eth.accounts[1];
僅具有value的交易
web3.eth.sendTransaction({from: src, to: dst, value: web3.toWei(0.01, "ether"), data: ""});
圖1唆迁,Parity錢包顯示一筆有value沒有data的交易
同時具有value和data的交易
web3.eth.sendTransaction({from: src, to: dst, value: web3.toWei(0.01, "ether"), data: "0x1234"});
圖2鸭丛,Parity錢包顯示一筆有value也有data的交易
僅包含data的交易
web3.eth.sendTransaction({from: src, to: dst, value: 0, data: "0x1234"});
圖3,Parity錢包顯示一筆沒有value有data的交易
既沒有value也沒有data的交易
web3.eth.sendTransaction({from: src, to: dst, value: 0, data: ""}));
圖4唐责,Parity錢包顯示一筆沒有value也沒有data的交易
向EOA和合約傳遞value
當您構建包含value的以太坊交易時鳞溉,它相當于付款。根據(jù)接收地址是否為合約鼠哥,這些交易的行為會有所不同熟菲。
對于EOA地址,或者更確切地說朴恳,對于未在區(qū)塊鏈中注冊為合約的任何地址抄罕,以太坊將記錄狀態(tài)更改,并將您發(fā)送的value添加到地址的余額中于颖。如果以前沒有看到該地址呆贿,則會創(chuàng)建該地址并將其余額初始化為您的付款金額。
如果接收地址(to)是合約恍飘,則EVM將執(zhí)行合約并嘗試調(diào)用交易的數(shù)據(jù)有效負載中指定的函數(shù)(請參閱[invocation])榨崩。如果您的交易中沒有數(shù)據(jù)有效負載谴垫,則EVM將調(diào)用目標合約的fallback功能,如果該功能需要支付母蛛,則將執(zhí)行該功能以確定下一步操作翩剪。
合約可以通過在調(diào)用payable函數(shù)時立即拋出異常,或者由payable函數(shù)中編碼的條件確定彩郊,來拒絕收款前弯。如果payable函數(shù)成功終止(沒有例外),則更新合約的狀態(tài)以反映合約的以太余額的增加秫逝。
向EOA和合約傳遞數(shù)據(jù)有效負載
當您的交易包含數(shù)據(jù)有效負載時恕出,它很可能發(fā)送到合同地址。這并不意味著您無法將數(shù)據(jù)有效負載發(fā)送到EOA违帆。事實上浙巫,你可以做到這一點。但是刷后,在這種情況下的畴,數(shù)據(jù)有效負載的解釋取決于您用于訪問EOA的錢包。大多數(shù)錢包會忽略交易中收到的任``何數(shù)據(jù)有效負載尝胆,而不是他們控制的EOA丧裁。將來,有可能出現(xiàn)允許錢包以合約的方式解釋數(shù)據(jù)有效負載編碼的標準含衔,從而允許交易調(diào)用在用戶錢包內(nèi)運行的功能煎娇。關鍵的區(qū)別在于,與合約執(zhí)行不同贪染,EOA對數(shù)據(jù)有效負載的任何解釋都不受以太坊的共識規(guī)則約束缓呛。
現(xiàn)在,我們假設您的交易正在向合約地址提供數(shù)據(jù)有效負載抑进。在這種情況下强经,數(shù)據(jù)有效負載將由EVM解釋為函數(shù)調(diào)用,調(diào)用命名函數(shù)并將任何編碼參數(shù)傳遞給函數(shù)寺渗。
發(fā)送給合約的數(shù)據(jù)有效負載是十六進制序列化編碼:
- 函數(shù)選擇器:函數(shù)原型的Keccak256哈希的前4個字節(jié)。這允許EVM明確地識別您要調(diào)用的函數(shù)兰迫。
- 函數(shù)參數(shù):根據(jù)EVM定義的各種基本類型的規(guī)則進行編碼信殊。
讓我們看一個簡單的例子,它來自我們的[solidity_faucet_example]汁果。在Faucet.sol中涡拘,我們?yōu)樘峥疃x了一個函數(shù):
function withdraw(uint withdraw_amount) public {
withdraw函數(shù)的原型定義為包含函數(shù)名稱的字符串,后跟括號中括起的每個參數(shù)的數(shù)據(jù)類型据德,并用單個逗號分隔鳄乏。函數(shù)名是withdraw跷车,它接受一個uint的參數(shù)(這是uint256的別名)。所以withdraw的原型將是:
withdraw(unit256)
讓我們計算一下這個字符串的Keccak256哈希值(我們可以使用tuffle控制臺或任何JavaScript web3控制臺來做到這一點):
web3.sha3("withdraw(uint256)");
'0x2e1a7d4d13322e7b96f9a57413e1525c250fb7a9021cf91d1540d5b69f16a49f'
哈希的前4個字節(jié)是0x2e1a7d4d橱野。這是我們的“函數(shù)選擇器”值筝尾,它將告訴EVM我們想要調(diào)用哪個函數(shù)噪沙。
接下來,讓我們計算一個值作為withdraw_amount參數(shù)。我們想要提取0.01以太汰蓉。讓我們將其編碼為十六進制序列的大端無符號256位整數(shù),以wei命名:
withdraw_amount = web3.toWei(0.01, "ether");
'10000000000000000'
withdraw_amount_hex = web3.toHex(withdraw_amount);
'0x2386f26fc10000'
現(xiàn)在鹏溯,我們將函數(shù)選擇器添加到金額(填充到32個字節(jié)):
2e1a7d4d000000000000000000000000000000000000000000000000002386f26fc10000
這是我們交易的數(shù)據(jù)有效負載旺罢,調(diào)用withdraw函數(shù)并請求0.01 ether作為withdraw_amount。
特殊交易:合約注冊
有一個具有數(shù)據(jù)有效負載且沒有value的交易的特例奕扣。那就是一個注冊新合約的交易薪鹦。合約注冊交易被發(fā)送到特殊目的地地址,即零地址惯豆。簡單來說池磁,合約注冊交易中的to字段包含地址0x0。該地址既不代表EOA(沒有相應的私鑰/公鑰對)也不代表合約循帐。它永遠不會花費以太或發(fā)起交易框仔。它僅用作目的地,具有特殊含義“注冊此合約”拄养。
雖然零地址僅用于合同注冊离斩,但它有時會收到來自各種地址的付款。對此有兩種解釋:要么是偶然的瘪匿,導致失去以太跛梗;要么是故意銷毀以太。如果您想進行有意的以太銷毀棋弥,您應該明確網(wǎng)絡意圖并使用專門指定的地址:
0x000000000000000000000000000000000000dEaD
Warning | 發(fā)送到合同合約地址0x0或上面指定的地址0x0 ... dEaD的任何以太將變得不可靠并永遠丟失核偿。 |
---|
合約注冊交易不應包含以太值,只包含合約的已編譯字節(jié)碼的數(shù)據(jù)有效負載顽染。此交易的唯一效果是注冊合約漾岳。
例如,我們可以發(fā)布[intro]中使用的Faucet.sol粉寞。合約需要編譯成二進制十六進制表示尼荆。這可以使用Solidity編譯器完成。
> solc --bin Faucet.sol
======= Faucet.sol:Faucet =======
Binary:
6060604052341561000f57600080fd5b60e58061001d6000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632e1a7d4d146041575b005b3415604b57600080fd5b605f60048080359060200190919050506061565b005b67016345785d8a00008111151515607757600080fd5b3373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151560b657600080fd5b505600a165627a7a72305820d276ddd56041f7dc2d2eab69f01dd0a0146446562e25236cf4ba5095d2ee802f0029
也可以從Remix在線編譯器獲得相同的信息∵罂眩現(xiàn)在我們可以創(chuàng)建交易了捅儒。
> src = web3.eth.accounts[0];
> faucet_code = "0x6060604052341561000f57600080fd5b60e58061001d6000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632e1a7d4d146041575b005b3415604b57600080fd5b605f60048080359060200190919050506061565b005b67016345785d8a00008111151515607757600080fd5b3373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151560b657600080fd5b505600a165627a7a72305820d276ddd56041f7dc2d2eab69f01dd0a0146446562e25236cf4ba5095d2ee802f0029"
> web3.eth.sendTransaction({from: src, data: faucet_code, gas: 113558, gasPrice: 200000000000})
"0x7bcc327ae5d369f75b98c0d59037eec41d44dfae75447fd753d9f2db9439124b"
無需指定to參數(shù),將使用默認的零地址。您可以指定gasPrice和gas limit巧还。合約被注冊我們可以在etherscan block explorer上看到它
圖5. Etherscan顯示合約成功
您可以查看交易收據(jù)以獲取有關合約的信息鞭莽。
> eth.getTransactionReceipt("0x7bcc327ae5d369f75b98c0d59037eec41d44dfae75447fd753d9f2db9439124b");
{
blockHash: "0x6fa7d8bf982490de6246875deb2c21e5f3665b4422089c060138fc3907a95bb2",
blockNumber: 3105256,
contractAddress: "0xb226270965b43373e98ffc6e2c7693c17e2cf40b",
cumulativeGasUsed: 113558,
from: "0x2a966a87db5913c1b22a59b0d8a11cc51c167a89",
gasUsed: 113558,
logs: [],
logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
status: "0x1",
to: null,
transactionHash: "0x7bcc327ae5d369f75b98c0d59037eec41d44dfae75447fd753d9f2db9439124b",
transactionIndex: 0
}
在這里我們可以看到合約的地址。我們可以從合約中發(fā)送和接收資金麸祷,如[將數(shù)據(jù)有效負載傳輸?shù)紼OA或合約中所示]澎怒。
> contract_address = "0xb226270965b43373e98ffc6e2c7693c17e2cf40b"
> web3.eth.sendTransaction({from: src, to: contract_address, value: web3.toWei(0.1, "ether"), data: ""});
"0x6ebf2e1fe95cc9c1fe2e1a0dc45678ccd127d374fdf145c5c8e6cd4ea2e6ca9f"
> web3.eth.sendTransaction({from: src, to: contract_address, value: 0, data: "0x2e1a7d4d000000000000000000000000000000000000000000000000002386f26fc10000"});
"0x59836029e7ce43e92daf84313816ca31420a76a9a571b69e31ec4bf4b37cd16e"
過了一會兒,兩個交易都在ethescan上可見摇锋。
圖6. Etherscan顯示發(fā)送和接收資金的交易
數(shù)字簽名
到目前為止丹拯,我們還沒有深入探討有關“數(shù)字簽名”的任何細節(jié)。在本節(jié)中荸恕,我們將了解數(shù)字簽名的工作原理以及如何在不泄露私鑰的情況下提供私鑰的所有權證明乖酬。
橢圓曲線數(shù)字簽名算法(ECDSA)
以太坊中使用的數(shù)字簽名算法是橢圓曲線數(shù)字簽名算法,或ECDSA融求。ECDSA是用于基于橢圓曲線私鑰/公鑰對的數(shù)字簽名的算法咬像,如[elliptic_curve]中所述。
數(shù)字簽名在以太坊中有三個用途(參見下面的側(cè)欄)生宛。首先县昂,簽名證明私鑰的所有者(其暗示是以太坊賬戶的所有者)已授權以太的支出或合約的執(zhí)行。其次陷舅,授權證明是不可否認的(不可否認性)倒彰。第三,簽名證明交易數(shù)據(jù)在交易簽署后沒有也不能被任何人修改莱睁。
維基百科對“數(shù)字簽名”的定義
數(shù)字簽名是用于證明數(shù)字消息或文檔的真實性的數(shù)學方案待讳。有效的數(shù)字簽名使收件人有理由相信該郵件是由已知發(fā)件人(身份驗證)創(chuàng)建的,發(fā)件人不能拒絕發(fā)送郵件(不可否認)仰剿,并且郵件在傳輸過程中未被更改(完整性) 创淡。
資料來源:https://en.wikipedia.org/wiki/Digital_signature
數(shù)字簽名的工作原理
數(shù)字簽名是一種由兩部分組成的數(shù)學方案。第一部分是使用來自消息(交易)的私鑰(簽名密鑰)創(chuàng)建簽名的算法南吮。第二部分是一種算法琳彩,允許任何人僅使用消息和公鑰來驗證簽名。
創(chuàng)建數(shù)字簽名
在以太坊的ECDSA實現(xiàn)中部凑,被簽名的“消息”是交易露乏,或者更準確地說,是來自交易的RLP編碼數(shù)據(jù)的Keccak256散列涂邀。簽名密鑰是EOA的私鑰施无。結果是簽名:
描述:
- k是簽名的私鑰
- m是RLP編碼的交易
-
是Keccak256哈希函數(shù)
-
是簽名算法
- Sig是由此產(chǎn)生的簽名
有關ECDSA數(shù)學的更多細節(jié)可以在[ECDSA數(shù)學中]找到。
函數(shù)產(chǎn)生一個由兩個值組成的簽名Sig必孤,通常稱為R和S:
Sig =(R,S)
驗證簽名
要驗證簽名,必須具有簽名(R和S)敷搪、序列化交易和公鑰(對應于用于創(chuàng)建簽名的私鑰)兴想。實質(zhì)上,驗證簽名意味著“只有生成此公鑰的私鑰的所有者才能在此交易中生成此簽名”赡勘。
簽名驗證算法接收消息(交易的哈仙┍悖或其它部分),簽名者的公鑰和簽名(R和S值)闸与,如果簽名對此消息和公鑰有效毙替,則返回TRUE。
ECDSA數(shù)學
如前所述践樱,簽名由數(shù)學函數(shù)創(chuàng)建厂画,該函數(shù)產(chǎn)生由兩個值R和S組成的簽名。在本節(jié)中拷邢,我們將更詳細地介紹函數(shù)
袱院。
簽名算法首先生成短暫(臨時)私鑰/公鑰對。在涉及簽名私鑰和交易哈希的轉(zhuǎn)換之后瞭稼,該臨時密鑰對用于計算R和S值忽洛。
臨時密鑰對由兩個輸入值生成:
- 隨機數(shù)q,用作臨時私鑰
- 和橢圓曲線發(fā)生器點G.
從q和G环肘,我們生成相應的臨時公鑰Q(計算為Q = q * G欲虚,與導出以太坊公鑰的方式相同;參見[pubkey])。然后悔雹,數(shù)字簽名的R值是短暫公鑰Q的x坐標复哆。
從那里,算法計算簽名的S值荠商,使得:
描述:
- q是臨時的私鑰
- R是臨時公鑰的x坐標
- k是簽名(EOA所有者)的私鑰
- m是交易數(shù)據(jù)
- p是橢圓曲線的素數(shù)階
驗證是簽名生成函數(shù)的反轉(zhuǎn)寂恬,使用R,S值和公鑰來計算值Q莱没,它是橢圓曲線上的一個點(簽名創(chuàng)建中使用的臨時公鑰):
描述:
- R和S是簽名值
- K是簽名(EOA所有者)的公鑰
- m是已簽名的交易數(shù)據(jù)
- G是橢圓曲線發(fā)生器點
- p是橢圓曲線的素數(shù)階
如果計算的點Q的x坐標等于R初肉,則驗證者可以斷定簽名是有效的。
請注意饰躲,在驗證簽名時牙咏,私鑰既不知道也不透露。
Tip | ECDSA必然是一個相當復雜的數(shù)學; 完整的解釋超出了本書的范圍嘹裂。許多優(yōu)秀的在線指南將逐步引導您完成:搜索“ECDSA解釋”或嘗試以下內(nèi)容:http://bit.ly/2r0HhGB妄壶。 |
---|
在實踐中簽署交易
為了產(chǎn)生有效的交易,發(fā)起者必須使用橢圓曲線數(shù)字簽名算法對消息應用數(shù)字簽名寄狼。當我們說“簽署交易”時丁寄,我們實際上是指“簽署RLP序列化交易數(shù)據(jù)的Keccak256哈习碧剩”。簽名應用于交易數(shù)據(jù)的哈希伊磺,而不是交易本身盛正。
Tip | 在#2,675,000塊,以太坊實施了“Spurious Dragon”硬分叉屑埋,除了其他變化之外豪筝,還引入了一個包含交易重放保護的新簽名方案。這種新的簽名方案在EIP-155中規(guī)定(見[eip155])摘能。此更改會影響簽名過程的第一步续崖,在簽名之前向交易添加三個字段(v,r团搞,s)严望。 |
---|
要在以太坊簽署交易,發(fā)起人必須:
- 創(chuàng)建一個包含九個字段的交易數(shù)據(jù)結構:nonce莺丑,gasPrice著蟹,startGas,to梢莽,value萧豆,data,v昏名,r涮雷,s
- 生成RLP編碼的交易序列化消息
- 計算此序列化消息的Keccak256哈希值
- 計算ECDSA簽名,使用發(fā)件人EOA的私鑰對哈希進行簽名
- 在交易中插入ECDSA簽名的計算r和s值
原始交易創(chuàng)建和簽署
讓我們使用ethereumjs-tx庫創(chuàng)建一個原始交易并對其進行簽名轻局。此示例的源代碼位于GitHub存儲庫中的raw_tx_demo.js中:
raw_tx_demo.js:在JavaScript中創(chuàng)建和簽署原始交易
link:code/web3js/raw_tx/raw_tx_demo.js[]
在這里下載:https://github.com/ethereumbook/ethereumbook/blob/develop/code/web3js/raw_tx/raw_tx_demo.js
運行示例代碼:
$ node raw_tx_demo.js
RLP-Encoded Tx: 0xe6808609184e72a0008303000094b0920c523d582040f2bcb1bd7fb1c7c1ecebdb348080
Tx Hash: 0xaa7f03f9f4e52fcf69f836a6d2bbc7706580adce0a068ff6525ba337218e6992
Signed Raw Transaction: 0xf866808609184e72a0008303000094b0920c523d582040f2bcb1bd7fb1c7c1ecebdb3480801ca0ae236e42bd8de1be3e62fea2fafac7ec6a0ac3d699c6156ac4f28356a4c034fda0422e3e6466347ef6e9796df8a3b6b05bed913476dc84bbfca90043e3f65d5224
使用EIP-155創(chuàng)建原始交易
EIP-155“簡單重放攻擊保護”標準規(guī)定了重放攻擊保護的交易編碼洪鸭,其在簽名之前包括交易 數(shù)據(jù)內(nèi)的鏈標識符。這確保了為一個區(qū)塊鏈(例如以太坊主網(wǎng)絡)創(chuàng)建的交易在另一個區(qū)塊鏈(例如以太坊Classic或Ropsten測試網(wǎng)絡)上無效仑扑。因此览爵,在一個網(wǎng)絡上廣播的交易不能在另一個網(wǎng)絡上重播,因此標準的“重放攻擊保護”名稱镇饮。
EIP-155在交易數(shù)據(jù)結構中添加了v蜓竹,r和s三個字段。r和s字段初始化為零储藐。在對交易數(shù)據(jù)進行編碼和哈希之前俱济,會將這三個字段添加到交易數(shù)據(jù)中。因此钙勃,這三個附加字段會更改交易的哈希值蛛碌,稍后將應用簽名。通過在被簽名的數(shù)據(jù)中包含鏈標識符辖源,交易簽名可以防止任何更改蔚携,因為如果鏈標識符被修改希太,則簽名無效。因此浮梢,EIP-155使得交易不可能在另一條鏈上重放跛十,因為簽名的有效性取決于鏈標識符。
v簽名前綴字段初始化為鏈標識符秕硝,其值為:
鏈 | Chain ID |
---|---|
以太坊主網(wǎng) | 1 |
Morden (obsolete), Expanse | 2 |
Ropsten | 3 |
Rinkeby | 4 |
Rootstock主網(wǎng) | 30 |
Rootstock測試網(wǎng)絡 | 31 |
Kovan | 42 |
以太坊經(jīng)典主網(wǎng) | 61 |
以太坊經(jīng)典測試網(wǎng)絡 | 62 |
Geth私有網(wǎng)絡 | 1337 |
生成的交易結構經(jīng)過RLP編碼,散列和簽名洲尊。稍微修改簽名算法以對v前綴中的chainID進行編碼远豺。
有關更多詳細信息,請參閱EIP-155規(guī)范:https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md
簽名前綴值(v)和公鑰恢復
如[交易結構中]所述坞嘀,交易消息不包括任何“from”字段躯护。這是因為發(fā)起人的公鑰可以直接從ECDSA簽名中計算出來。獲得公鑰后丽涩,您可以輕松計算地址棺滞。恢復簽名者公鑰的過程稱為公鑰恢復矢渊。
給定在[ECDSA Math]中計算的值r和s继准,我們可以計算兩個可能的公鑰。
首先矮男,我們從簽名中的x坐標r值計算兩個橢圓曲線點R和R'移必。有兩個點,因為橢圓曲線在x軸上是對稱的毡鉴,因此對于任何值x崔泵,在x軸的任一側(cè)有兩個可能的值匹配曲線。
從r中猪瞬,我們還要計算憎瘸,它是r的乘法倒數(shù)。
最后陈瘦,我們計算z幌甘,它是消息哈希的n個最低位,其中n是橢圓曲線的階數(shù)甘晤。
那么兩個可能的公鑰是:
和
描述:
-
和
是簽名者公鑰的兩種可能性
-
是簽名r值的乘法倒數(shù)
- s是簽名的值
- R和R'是臨時公鑰Q的兩種可能性
- z是消息哈希的n個最低位
- G是橢圓曲線發(fā)生器點
為了提高效率含潘,交易簽名包括前綴值v,它告訴我們兩個可能的R值中的哪一個是臨時的公鑰线婚。如果v是偶數(shù)遏弱,則R是正確的值。如果v是奇數(shù)塞弊,那么R'是正確的值漱逸。這樣泪姨,我們只需要計算R的一個值和K的一個值。
分離簽名和傳輸(離線簽名)
交易簽署后饰抒,即可傳輸?shù)揭蕴痪W(wǎng)絡肮砾。創(chuàng)建、簽名和廣播交易的三個步驟通常發(fā)生在單個函數(shù)中袋坑,例如使用web3.eth.sendTransaction仗处。但是,正如我們在[Raw交易創(chuàng)建和簽名]中看到的那樣枣宫,您可以通過兩個單獨的步驟創(chuàng)建和簽署交易婆誓。獲得簽名交易后,您可以使用web3.eth.sendSignedTransaction傳輸它也颤,該事件采用十六進制編碼和簽名的交易消息并在以太坊網(wǎng)絡上傳輸洋幻。
您為什么要分開交易的簽名和傳輸?最常見的原因是安全性:簽署交易的計算機必須具有加載在內(nèi)存中的未鎖定私鑰翅娶。傳輸?shù)挠嬎銠C必須連接到互聯(lián)網(wǎng)并運行以太坊客戶端文留。如果這兩個功能在一臺計算機上,那么您在在線系統(tǒng)上有私鑰竭沫,這非常危險燥翅。分離簽名和傳輸?shù)墓δ芊Q為離線簽名,是一種常見的安全措施输吏。
根據(jù)您所需的安全級別权旷,您的“離線簽名”計算機可能與在線計算機有不同程度的分離,從孤立和防火墻子網(wǎng)(在線但隔離)到稱為氣隙系統(tǒng)的完全脫機系統(tǒng)贯溅。在氣隙系統(tǒng)中根本沒有網(wǎng)絡連接 - 計算機與在線環(huán)境之間存在“空中”差距拄氯。要對交易進行簽名,您可以使用數(shù)據(jù)存儲介質(zhì)或(更好)網(wǎng)絡攝像頭和QR碼將其傳輸?shù)綒庀队嬎銠C或從氣隙計算機傳輸它浅。當然译柏,這意味著您必須手動傳輸要簽名的每個交易,但這不會擴展姐霍。
雖然沒有多少環(huán)境可以使用完全氣隙系統(tǒng)鄙麦,但即使是很小程度的隔離也具有顯著的安全性優(yōu)勢。例如镊折,具有僅允許消息隊列協(xié)議通過的防火墻的隔離子網(wǎng)可以提供比在線系統(tǒng)上簽名大大減少的攻擊面和更高的安全性胯府。許多公司使用ZeroMQ(0MQ)等協(xié)議,因為它為簽名計算機提供了很小的攻擊面恨胚。通過這樣的設置骂因,交易被序列化并排隊等待簽名。排隊協(xié)議以類似于TCP套接字的方式將序列化消息發(fā)送到簽名計算機赃泡。簽名計算機從隊列中讀取序列化交易(小心)寒波,使用適當?shù)拿荑€應用簽名乘盼,并將它們放在傳出隊列中。
交易廣播
以太坊網(wǎng)絡使用“flood”路由協(xié)議俄烁。每個以太坊客戶端绸栅,充當對等網(wǎng)絡(P2P)的節(jié)點 ,其(理想地)形成網(wǎng)狀網(wǎng)絡页屠。沒有網(wǎng)絡節(jié)點是“特殊的”粹胯,它們都作為平等的對等體。我們將使用術語“節(jié)點”來指代連接并參與P2P網(wǎng)絡的以太坊客戶端卷中。
交易傳播開始于創(chuàng)建以太坊節(jié)點(或從離線接收)簽署的交易矛双。交易被驗證,然后傳輸?shù)街苯舆B接到始發(fā)節(jié)點的所有其他以太坊節(jié)點蟆豫。平均而言,每個以太坊節(jié)點保持與至少13個稱為其鄰居的其他節(jié)點的連接懒闷。每個鄰居節(jié)點在收到交易后立即驗證交易十减。如果他們同意這是有效的,他們會保存一份副本并將其傳播給所有的鄰居(除了它的鄰居)愤估。結果帮辟,交易從源節(jié)點向外傳播擴散,直到網(wǎng)絡中的所有節(jié)點都擁有該交易的副本玩焰。
幾秒鐘內(nèi)由驹,以太坊交易就會傳播到全球所有以太坊節(jié)點。從每個節(jié)點的角度來看昔园,不可能辨別交易的起源蔓榄。發(fā)送給我們節(jié)點的鄰居可能是交易的發(fā)起者,或者可能從其鄰居那里收到它默刚。為了能夠跟蹤交易的起源或干擾傳播甥郑,攻擊者必須控制所有節(jié)點的相當大的百分比。這是P2P網(wǎng)絡安全和隱私設計的一部分荤西,尤其適用于區(qū)塊鏈澜搅。
記錄在鏈上
盡管以太坊中的所有節(jié)點都是同等的對等節(jié)點,但其中一些節(jié)點由礦工負責運營邪锌,并向礦場提供交易和區(qū)塊勉躺,這些礦場是具有高性能圖形處理單元(GPU)的計算機。挖掘計算機將交易添加到候選區(qū)塊觅丰,并嘗試找到使得候選區(qū)塊有效的工作證明饵溅。我們將在[共識]中更詳細地討論這一點。
沒有太多細節(jié)舶胀,有效的交易最終將被包含在一個交易區(qū)塊中概说,并因此記錄在以太坊區(qū)塊鏈中碧注。一旦開采成區(qū)塊,交易還通過修改賬戶余額(在簡單付款的情況下)或通過調(diào)用改變其內(nèi)部狀態(tài)的合約來修改以太坊singleton的狀態(tài)糖赔。這些變更以交易收據(jù)的形式記錄在交易旁邊萍丐,交易收據(jù)也可能包括事件。我們將在[evm]中更詳細地檢查所有這些放典。
我們的交易已經(jīng)完成了從創(chuàng)建到簽署EOA逝变、傳播以及最終采礦的旅程。它改變了singleton的狀態(tài)奋构,并在區(qū)塊鏈上留下了不可磨滅的印記壳影。
多重簽名(multisig)交易
如果您熟悉比特幣的腳本功能,那么您就知道有可能創(chuàng)建一個比特幣多幣種賬戶弥臼,該賬戶只能在多方簽署交易時花費資金(例如2of2 或 3of4簽名)宴咧。以太坊的價值交易沒有多重簽名的規(guī)定,盡管可以部署任意條件的任意合約來處理ether和token的交易径缅。
為了在多重情況下保護你的ether掺栅,將它們轉(zhuǎn)移到多簽合約中。無論何時您想將資金轉(zhuǎn)入其他賬戶纳猪,所有必需的用戶都需要使用常規(guī)錢包軟件將交易發(fā)送至合約氧卧,從而有效授權合約執(zhí)行最終交易。
這些合約還可以設計為在執(zhí)行本地代碼之前需要多個簽名或觸發(fā)其他合約氏堤。該方案的安全性最終由multisig合約代碼決定沙绝。
Discussion 和 Grid +參考實現(xiàn):https://blog.gridplus.io/toward-an-ethereum-multisig-standard-c566c7b7a3f6