科普 | 解讀以太坊黃皮書(1/7)

科普 | 解讀以太坊黃皮書(2/7)

科普 | 解讀以太坊黃皮書(3/7)


這次我們要聊的話題是——以太坊上的交易是如何執行的。在本文中,我們會學到交易驗證規則,以及它們存在的原因;接着深入理解交易的執行過程,和節點在驗證交易時採取的每個步驟。

本文是解讀以太坊黃皮書系列的第四篇文章, 該系列文章的宗旨是爲了讓大家對以太坊黃皮書有更清晰的認識,讓更多的人瞭解以太坊。

(免責聲明:__本文基於 2019 年 10 月 20 號拜占庭 7e819ec 版本的黃皮書進行介紹)

_
_

介紹

**
**

在本系列文章中,我們已經討論過作爲分佈式計算機,以太坊是如何運作的,以及使用者如何通過向系統發送交易與以太坊進行交互(還談到交易手續費的概念)。

在第一篇博文裏,我們瞭解了以太坊的狀態轉換函數,還有以太坊如何通過連續的狀態轉換實現計算機的功能。

簡單來說,狀態轉換函數使用當前的狀態及交易作爲輸入,計算出下一個狀態。

科普 | 解讀以太坊黃皮書(4/7)-以太坊狀態轉換函數-

在深入瞭解以太坊中的節點如何執行交易之前,我們先聊聊一筆交易是如何被驗證的。

交易驗證

**
**

在執行交易之前,節點會先驗證該交易是否滿足一些基本(固有)規則。如果連這些基本規則都通過不了,節點就不會執行該交易。

這些交易的固有規則如下:

  1. 滿足 RLP 編碼格式
  2. 具備合法簽名
  3. 具備合法 nonce (與交易發送方的當前 nonce 值相同)
  4. 執行交易的固有成本(intrinsic cost)小於該交易設置的 gas 上限交易
  5. 發送方的賬戶餘額大於等於交易所需的預付款

還有一條規則,它不屬於交易固有規則——如果一系列已準備好打包到區塊中的交易,加上這條交易之後,會使得所有交易的總 Gas Limit 超過區塊的 Gas 上限,那麼該筆交易就不能和那些交易一起打包到一個區塊中。讓我們展開每一條規則,來解釋這些規則如何運作及爲何存在。

交易必須符合合規的 RLP 編碼

這條規則可能最好直觀理解。RLP (Recursive Length Prefix,又稱爲遞歸長度前綴編碼)是一種用於序列化以太坊中的對象的編碼方法;和其他方法相同,如果你不按照 RLP 對物件編碼,則無法對該物件進行解碼,你也就無法通過數據編碼得到原始對象的信息。該規則的目的是確保以太坊客戶端收到交易後,能夠成功解碼並執行。

交易必須具備合法簽名

假設你的以太坊賬戶中有很多以太幣,現在有人試圖發起一筆交易,從你的帳戶把錢轉走以據爲己有,你怎麼看?你絕對不想看到有人冒充你,並偷走你的錢,這就是爲什麼我們需要交易簽名。以太坊採用非對稱加密,確保只有實際控制者能夠從賬戶發起交易。與此同時,這種密碼學工具還能讓其他人驗證該交易的確是由賬戶的實際控制者發起。我不會展開討論 ECDSA (以太坊選擇的非對稱密碼算法)的細節,因爲我們只需要知道最基礎的概念就行。在非對稱密碼學中,公鑰和私鑰是成對存在的。私鑰應該完全保密,而公鑰可以分享給任何人;私鑰可以用來進行簽名,這個簽名可以用對應的公鑰加以驗證。在以太坊上籤署一筆由你發起的交易,就相當於爲在一封你寫的信上簽名,不同之處在於密碼學簽名比手寫簽名還要難僞造得多!在以太坊上,賬戶地址根據個人的公鑰來生成。當發送一筆交易時,私鑰被用來簽署交易(還記得 v 、r 、s 這幾個包含在交易裏的值嗎?),接着所有節點就能確定這筆交易是不是真的由關聯賬戶的私鑰所有者簽署的。不具備合法簽名的交易沒有任何執行的意義,因此必須有合法簽名就成了交易的固有規則之一。

交易 nonce 和賬戶 nonce 必須匹配

在以太坊中,賬戶 nonce 值代表該賬戶發送的交易數量(如果是合約賬戶,則 nonce 值指的是賬戶所創建的合約數量)。如果沒有 nonce ,同一筆交易可能被錯誤地執行多次(也就是所謂的 “重放攻擊”)。考慮到以太坊的分佈式特性,不同的節點可能會試圖把同一筆交易打包進不同的區塊,將重複的交易上鍊。假設一筆你把錢轉給某人的交易被誤打包了兩次,導致你重複轉了兩次錢,你心裏一定很不是滋味。每當用戶創建一筆新的交易,他們必須設置能匹配當前賬戶 nonce 值的交易 nonce 值,當執行交易時,節點會檢查交易 nonce 是否匹配賬戶 nonce 。如果因爲某些原因,導致同一筆交易被重複提交給節點,此時,因爲賬戶 nonce 值已經增加,所以重複提交的交易會被視爲不合法。以太坊強制要求交易 nonce 值與賬戶 nonce 值匹配,這麼做除了能避免重放攻擊,還能確保一筆交易只會執行及改變狀態一次。

交易的固有成本必須小於該交易設置的 gas 上限

在前一篇博文中,我們說明了_爲什麼使用以太坊需要付費_,以及 gas 的概念。總的來說,每一筆交易都有與之關聯的 gas ——發送一筆交易的成本包含兩部分:固有成本執行成本執行成本根據該交易需要使用多少以太坊虛擬機(EVM)的資源來運算而定,執行一筆交易所需的操作越多,則它的執行成本就越高。固有成本由交易的負載( payload )決定,交易負載分爲以下三種負載:

  • 如果該交易是爲了創建智能合約,則負載就是創建智能合約的 EVM 代碼
  • 如果該交易是爲了調用智能合約的函數,則負載就是執行消息的輸入數據
  • 如果該交易只是單純在兩個賬戶間轉賬,則負載爲空

假設 Nzeros 代表交易負載中,字節爲 0 的字節總數;Nnonzeros 代表交易負載中,字節不爲 0 的字節總數。可以通過下列公式計算出該交易的固有成本(黃皮書 6.2 章,方程式 54、55 和 56):固有成本 = _Gtransaction + Gtxdatazero * Nzeros + Gtxdatanonzero * Nnonzeros + Gtxcreate_在黃皮書的附錄 G 中,可以看到一份創建和執行交易的相關成本的費用表。與固有成本相關的內容如下:

  • Gtransaction = 21,000 Wei
  • Gtxcreate = 32,000 Wei
  • Gtxdatazero = 4 Wei
  • Gtxdatanonzero = 68 Wei (在伊斯坦布爾升級時會改爲 16 wei)

當我們瞭解固有成本是什麼,就能理解爲什麼一旦交易的固有成本高於 Gas 限制,則該交易就會被視爲非法。Gas Limit 規定了一筆交易在執行時,能夠消耗掉的 Gas 上限;如果還沒開始執行該交易前,我們就知道它的固有成本高於 Gas 上限,那我們就沒有理由執行這筆交易。

交易發送方的賬戶餘額必須大於等於交易所需的預付款

交易預付款指的是在交易執行前,從交易發送方賬戶,預先扣除的 Gas 數量。我們可以通過下面的公式算出交易預付款:_預付款 = gasLimit * gasPrice + value_一筆交易的 Gas Limit,指的是交易發送方願意花在執行該交易上的 Gas 最大值;Gas Price 指的是每一單位 Gas 的單價;交易 Value 指的是發給消息接收者的 Wei 的數量(例如轉賬金額),或是投入要創建的合約中的準備金。如果要進一步瞭解什麼是 Gas ,以及爲什麼執行交易要耗費 Gas,可以看我們前一篇博文。因爲交易預付款在交易執行前就會先扣除,所以一旦交易發送方的賬戶餘額少於預扣額,這筆交易就沒有執行的必要了。

交易的 Gas Limit 必須小於等於區塊的 Gas 上限

這條規則不屬於固有規則,不過這是節點在選擇要打包的交易時,需要遵守的基本要求。區塊 Gas 上限是能夠 “裝在” 該區塊中的交易所用總 Gas 數的上限。當節點在選擇要打包的交易時,節點必須確保加入這筆交易後,區塊裏的交易所用總 Gas 數不會超過區塊 Gas 上限。對於要被打包的交易來說,其 Gas Limit 加上其他交易的 Gas Limit 總和,必須小於等於區塊 Gas 上限。當然,如果有一筆交易不能被打包進入當前區塊,它還是有機會被後面的區塊打包的。

執行交易

**
**

驗證完交易之後,是時候執行它了。在以太坊中,執行交易會改變狀態——好幾筆交易被打包進一個區塊,每個區塊就相當一個交易列表;當交易被順序執行後,會輸出新的合法狀態。 交易按照以下步驟執行:

  1. 將發送者賬戶 nonce 值加 1
  2. 從發送者賬戶扣除交易預付額( gasLimit * gasPrice )
  3. 確定該交易能夠用於執行的 gas 值(gasLimit – intrinsic cost)
  4. 執行該交易包含的操作(轉賬、調用或創建智能合約)
  5. 通過 SELFDESTRUCT 和 SSTORE 函數對發送者退款
  6. 退還交易發送者任何未使用的 gas
  7. 向受益人賬戶(通常屬於挖出包含該交易的區塊的礦工)轉入挖礦收益

增加發送者賬戶的 nonce 值

每當發送一筆交易,發送者賬戶 nonce 就會增加。這個操作在交易執行之初就會完成,如果交易執行失敗,則賬戶 nonce 值回滾。

從發送者賬戶扣除交易預付額

我們會從發送者賬戶餘額里扣除交易預付額,這個機制很簡單——由發送者爲自願付出的執行交易成本(gasLimit * gasPrice)付費。

計算可用於執行交易的 gas

交易的 gas 總額(gas limit)扣掉固有成本後,剩下的就是可用於執行交易的 gas 。

執行該交易所包含的操作

執行交易還涉及 EVM 的操作列表,其中唯一完全不需要 EVM 操作的交易——就是普通轉賬。每一項 EVM 操作都有對應的 gas 成本;在交易執行過程中,每做了一項 EVM 操作,就會從可用 gas 中扣掉對應的 gas 成本。直到下列兩種情況中的一種出現才停止:

  • 可用 gas 被耗盡,執行失敗
  • 執行結束後可用 gas 還有剩,或是剛好爲零

**

**

通過 SELFDESTRUCT 和 SSTORE 函數對發送者退款

在以太坊中,SELFDESTRUCT 操作碼用於銷燬不再需要的智能合約。每銷燬一個合約,執行者能夠收取 24,000 Wei 。同樣的,當使用 SSTORE 操作碼寫入 0 (有效刪除值)的時候,操作者每寫入一個 0 ,就能收取 1500 Wei 。關於退款,有件有趣的事情是,退款也有上限。該上限確保礦工可以算出執行交易所需的計算時間的上界。(更多關於 gas 費用和退款的詳細說明,可以在以太坊的設計合理性一文中找到)。還有一個重點是,必須在交易所包含的操作都執行結束後,纔會進行退款。因此任何應該返還的 gas 都不會被交易執行過程所消耗,從而避免了可能出現的_永遠不會耗盡 gas 的交易_。

退還交易發送者任何未使用的 gas

如果用於交易的預付款超過交易所使用的 gas,則發送方有權在執行交易後收回剩餘的 gas。

**

**

向受益人賬戶支付礦工費用

執行交易所使用的所有 Gas 被視爲交易手續費,由礦工獲得。這種機制激勵礦工持續出塊,並在網絡安全層面永續合作。

結語

**
**

在本文中,我們詳細討論了交易的驗證及執行(黃皮書第 6 章內容)。在第 7 、8 章會介紹更多類型的交易(合約創建及調用),我後會繼續更新關於這幾個章節的博文。 我相信,想要徹底瞭解交易驗證及執行的細節,最好的方法就是閱讀隨便一個實現協議的以太坊客戶端源碼。作爲 Besu 的貢獻者,我很熟悉它的實現,所以我建議即使你不是非常精通 Java ,你還是可以看看它的源碼。可以從這兩個部分開始讀起:MainnetTransactionValidation.java 和 MainnetTransactionProcessor.java 。再強調一下,如果你發現文中任何錯誤或是值得改進的地方,或是有疑問,請如往常在評論中告訴我。下期見!

(完)

(文內提供了許多超鏈接,請點擊閱讀原文到 EthFans 網站上獲取)


原文鏈接 :

https://www.lucassaldanha.com/transaction-execution-ethereum-yellow-paper-walkthrough-4-7/

作者 : Lucas Saldanha

翻譯 & 校對 :IAN LIU & 阿劍


你可能還喜歡:引介 | 以太坊交易的生命週期

科普 | 以太坊智能合約的生命週期

乾貨 | 以太坊上發送交易的九種辦法