以太坊交易的生命週期

買賣虛擬貨幣

瞭解以太坊交易是如何生成並在網路中廣播的

交易是以太坊(或任何類似的區塊鏈)的核心。在與以太坊區塊鏈進行互動之時,你是在執行交易並更新其狀態。你有沒有想過要了解當你在以太坊執行交易之時到底發生了什麼?讓我們透過一則交易例子來解答這一問題。本文包括如下內容。

1.以太坊交易的端到端遍歷,即從你的瀏覽器/控制檯出發進入以太坊網路,然後再回到你的瀏覽器/控制

2.瞭解當你使用 Metamask 或 Myetherwallet 等外掛,而非執行自己的節點之時,交易是如何進行的

3.如果你比較偏執多疑,不信任任何外掛,想自己執行交易,該怎麼做?

本文讀者需要對以太坊及其組成部分,如賬戶、gas 和合約等具備基礎性瞭解。關於這些概念的詳細解釋可以參見這篇文章。如果你是一個不熟悉以太坊的開發者,這篇文章或許對你很有幫助。你也可以從這篇文章中學習如何構建簡單的分散式應用。如果你已經有過執行交易的親身經歷,本文對你的意義會更大。例如,可以是將一些以太幣傳送給另一個人或合約的交易。再比如,還可以是在與分散式應用進行互動的情況下,如果你在這個網站上買了一些代幣,這就是一筆交易。如果你為一位候選人投票,這也是一筆交易。


一. 以太坊交易的端到端綜述

讓我們以下列合約呼叫為例,並遍歷該函式呼叫/交易是如何執行及永久儲存在區塊鏈上的整體流程。點選此處可瞭解整個合約。從較高層次來說,這是一個投票合約,其中你可以預置一些候選人在選舉中進行角逐,任何人都能為他們投票。這些投票將會記錄在區塊鏈上。

Voting.deployed().then(function(instance) {
instance.voteForCandidate('Nick', {gas: 140000, from: web3.eth.accounts[0]}).then(function(r) {
console.log("Voted successfully!")
})
})

假設你在自己的計算機上本地執行了一個以太坊客戶端(Geth 或 Parity),你的計算機連線到了某個以太坊網路(測試網路或是主網),你有權訪問該合約地址和 ABI,從而執行該交易。

如果你構建過分散式應用,應該對上述程式碼並不陌生。這是一個名為“Voting(投票)”的合約,已經部署在了區塊鏈上。我們以該合約為例,執行一個叫作 voteForCandidate 的函式,輸入候選人的姓名、該交易的gas上限和執行該交易的賬戶。從名稱中可以看出,該函式能夠用來為候選人投票,選票記錄在區塊鏈上。在下文,我們將嘗試解構該呼叫,瞭解你在執行該 javascript 函式時會發生的一切。

1.構建原始交易物件

如下圖所示,voteForCandidate 函式呼叫首先被轉化成了原始交易(rawTxn)。Web3js庫被用來構建原始交易物件。

txnCount = web3.eth.getTransactionCount(web3.eth.accounts[0])
var rawTxn = {
nonce: web3.toHex(txnCount),
gasPrice: web3.toHex(100000000000),
gasLimit: web3.toHex(140000),
to: '0x633296baebc20f33ac2e1c1b105d7cd1f6a0718b',
value: web3.toHex(0),
data: '0xc7ed014952616d6100000000000000000000000000000000000000000000000000000000'
};

讓我們試著瞭解下該原始交易物件中的所有欄位,以及它們是如何設定的。

nonce(隨機數):每個以太坊賬戶都有一個叫做 nonce 的欄位,來記錄該賬戶已執行的交易總數。Nonce 的值隨著每個新交易的執行不斷增加,這能讓網路瞭解執行交易需要遵循的順序。Nonce 也被用來進行重放保護。

gasPrice(gas價格):即你願為該交易支付的每單位 gas 的價格。如果你正在主網上執行交易,ETH Gas Station上正好有一個網站,你可以參照其建議為你的交易設定 gas 價格,以便交易在一定時間內成功執行。Gas 價格目前以 GWei 為單位,其範圍是0.1->100+Gwei。下文會進一步介紹 gas 價格及其影響。

gasLimit(gas上限:即你願為該交易支付的最高 gas 總額。該上限能確保在出現交易執行問題(比如陷入無限迴圈)之時,你的賬戶不會耗盡所有資金。一旦交易執行完畢,剩餘所有 gas 會返還至你的賬戶。

to:即該函式呼叫被送往的地址。0x633296baebc20f33ac2e1c1b105d7cd1f6a0718b 是我們的案例中投票合約的地址。

Value(值:即你打算髮送的以太幣總量。當我們執行voteForCandidate函式時,我們根本沒有傳送以太幣,因此 value 為零。如果你要執行一個交易,向另一個人或合約傳送以太幣,你會需要設定 value 值。

data(資料):讓我們來看看data欄位是如何計算出來的。

你先從 voteForCandidate(bytes32 candidate)(32位元組的候選人)的 ABI 中獲取函式簽名,並得出它的雜湊值。

> web3.sha3('voteForCandidate(bytes32 candidate)') '

0xc7ed014922ff9493a686391b70ca0e8bb7e80f91c98a5cd3d285778ab2e245b3'

取該雜湊值的前4個位元組,即:0xcc9ab267。
然後將引數‘Nick’轉化為32位元組,得到52616d6100000000000000000000000000000000000000000000000000000000將二者結合,得到資料有效載荷。


2.簽署交易

如果你記得的話,你使用了web3.eth.accounts[0]來執行該交易。以太坊網路需要知道你確實是該賬戶的所有者,從而確保其他人不能以你的名義執行該交易。要向網路證明這點的方法是使用該賬戶的相應私鑰簽署交易。簽署過後的交易如下圖所示:

const privateKey = Buffer.from('e331b6d69882b4ab4ea581s88e0b6s4039a3de5967d88dfdcffdd2270c0fd109', 'hex')

const txn = new EthereumTx(rawTxn)
txn.sign(privateKey)
const serializedTxn = txn.serialize()
3.
交易經由本地驗證簽署過後的交易會提交至你的本地以太坊節點。然後你的本地節點會驗證已簽名的交易,確保它真的是由這個賬戶地址簽署過的。4.交易被廣播至網路已簽署交易經由你的geth/parity節點廣播至其對等節點,這些對等節點再將該交易廣播給它們的對等節點,以此類推。一旦交易被廣播至網路,你的本地節點也會輸出該交易的id,你可以用它來追蹤你的交易的狀態。該交易id就是已簽署交易物件的雜湊值。
transactionId = sha3(serializedTxn)

如果你是在公共的以太坊網路上執行該交易的話,追蹤你的交易狀態的最佳方式是透過etherscan.io。如上圖所示,你是否注意到了有幾個節點被標記為 Etherscan 節點。Etherscan 的團隊執行了幾個節點,並將一個很棒的前端網路應用連線到了 Etherscan上。如果你的交易被他們的節點選中,你可以在他們的網站上檢視自己的待定交易。

還要記住的一點是,並非所有節點都會接受你的交易。其中一些節點可能被設定成了只接受 gas 價格超過某一最低值的交易。如果你設定的 gas 價格低於該下限,則節點會忽略你的交易。

5.礦工節點接受交易

正如圖中所示,以太坊網路同時擁有礦工節點和非礦工節點。可能你也知道,礦工的職責是將你的交易包含到區塊上。礦工是交易池的維護者,你的交易先是被新增進交易池,再由礦工進行開始評估。


從上圖中你會注意到礦工將所有交易儲存在根據 gas 價格分類的池中。gas 價格越高,該交易就越有可能被新增進下一個區塊。這是礦工節點的常見設定(為得到更高的報酬進行最佳化)。不過,礦工可以將自己的節點設定成根據自己的喜好對交易進行分類(例如,他們為了幫助網路只挖掘gas價格低的交易)。

從上圖中,你看出我們的 voteForCandidate 交易是如何沉入礦池底端的嗎?一旦所有gas價格高的交易都被挖出來包含進區塊之後,礦工將挖掘我們的交易。

還有要注意的一點是,礦池可以容納的交易數是有限的。比如,一場眾籌正在火熱進行中或是一個非常流行的分散式應用(如加密貓)橫空出世。人們提交了 gas 價格高的交易,希望礦工能最先選中他們的交易。如果 gas 價格高的交易填滿了礦池,gas 價格低的交易就會被放棄。我們的候選人 Nick 在一段時間內就別想收到任何選票了。在這種情況下,我們甚至得重新廣播我們的交易。

另一個能讓你的交易在礦池裡上升的技巧是重新提交你的交易,提高 gas 價格並維持 nonce 值不變。這樣一來,當礦工接收到新交易時,gas 價格更高的新交易會覆蓋之前的交易。如果改變了 nonce 值,重新提交的交易就會被認為是不同的交易(最後會為Nick舉行兩次投票)。這裡推薦一篇很好的文章(編者注:中譯本見文末《科普 | 釋放阻塞的以太坊交易》超連結),作者Jim McDonald 對此做出了深入的解釋。

6.礦工節點找到一個有效區塊並將它廣播至網路

礦工最後選中了我們的交易,與其他交易一起包含進區塊。礦工只能選擇一定量的交易新增進區塊,因為以太坊已經設定了單個區塊 gas 上限,換言之,交易的所有 gas 上限總數不能超過區塊 gas 上限。你可以在 ethstats.net 上檢視當前 gas 上限。

一旦礦工選擇將交易包含進區塊,這些交易將被驗證幷包含進一個待處理區塊,工作量證明開始。某個礦工節點(透過解決工作量證明難題)最終會找到一個有效的區塊,並將這一區塊新增到區塊鏈上。就像經由你的本地節點廣播的原始交易會被其他節點接收那樣,礦工節點也會將這一有效區塊廣播給其他節點。

7.本地節點接收/同步新區塊

最終,你的本地節點將接收這個新區塊,並同步區塊鏈在本地的副本。一旦接收到這個新區塊,本地節點就會執行區塊裡的所有交易。

如果你使用 truffle 執行你的交易, truffle 會不斷測驗區塊鏈以求確認。一旦它發現交易被確認,就會執行 then() 區塊中的程式碼,並列印(我們每個例子的)控制檯日誌函式。

二. 使用Metamask而非本地節點


如果你安裝了 MetaMask 瀏覽器外掛,你就能在你的瀏覽器中管理你的賬戶。金鑰只會儲存在你的瀏覽器上,因此你是唯一一個有權訪問你的賬戶和私鑰的人。當你在瀏覽器上執行交易之時,外掛會將你的函式呼叫轉化成原始交易,並用你的私鑰簽署交易。 Metamask 執行自己的節點,並且使用這些節點來廣播你的交易(Metamask 使用的是Infura 運營的節點)。如此一來,你就沒必要執行自己的以太坊節點了。

三. 線下簽名

如果你不喜歡用外掛,或者擔心你的本地 geth 節點有可能受損(遭篡改),該怎麼辦呢?要解決這一問題有一個安全之策。

你是否注意到了,前兩個步驟根本不需要聯網。如果你想確保自己的交易絕對不會受到篡改,你可以使用一臺沒有聯網的計算機將這一函式呼叫轉換成原始交易,並使用你的私鑰簽署該交易。之後,你可以複製已簽署交易串,並使用聯網的計算機將其廣播至網路。你可以使用 Etherscan 和 Infura 等服務將你已簽署的交易廣播至網路。

另一個安全之策是使用 Ledger 或 Trezor 等硬體錢包。這類錢包儲存了你的私鑰,而簽署交易的金鑰已經程式設計進了硬體本身。它們需要聯網的原因只是為了釋出你的已簽署交易。

希望本文能讓你更好地理解以太坊交易的工作流程。如果發現文中有任何不當之處,請你留言,我會加以改正。

感謝 Jim McDonald為本文校對。


更多區塊鏈數字貨幣資訊:http://www.qukuaiwang.com.cn/news

免責聲明:

  1. 本文版權歸原作者所有,僅代表作者本人觀點,不代表鏈報觀點或立場。
  2. 如發現文章、圖片等侵權行爲,侵權責任將由作者本人承擔。
  3. 鏈報僅提供相關項目信息,不構成任何投資建議

推荐阅读

;