1. 程式人生 > >【以太坊】Ethereum交易過程及ethereumjs-tx的應用

【以太坊】Ethereum交易過程及ethereumjs-tx的應用

關於Ethereum交易是如何從生成並在網路中廣播的,如下總結七個步驟:

一、 構建原始交易物件

如下為原始交易物件欄位,並對各欄位進行展開說明

var rawTx = {
  nonce: '0x00',
  gasPrice: '0x09184e72a000', 
  gasLimit: '0x2710',
  to: '0x0000000000000000000000000000000000000000', 
  value: '0x00', 
  data: '0x7f7465737432000000000000000000000000000000000000000000000000000000600057'
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
nonce: 記錄發起交易的賬戶已執行交易總數。Nonce的值隨著每個新交易的執行不斷增加,這能讓網路瞭解執行交易需要遵循的順序,並且作為交易的重放保護。

gasPrice:該交易每單位gas的價格,Gas價格目前以Gwei為單位(即10^9wei),其範圍是大於0.1Gwei,可進行靈活設定。

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

to:該交易被送往的地址(呼叫的合約地址或轉賬對方的賬戶地址)。
value:交易傳送的以太幣總量。

data: 若該交易是以太幣交易,則data為空;若是部署合約,則data為合約的bytecode;若是合約呼叫,則需要從合約ABI中獲取函式簽名,並取函式簽名hash值前4位元組與所有引數的編碼方式值進行拼接而成,具體參見文章https://github.com/linjie-1/guigulive-operation/wiki/Ethereum%E7%9A%84%E5%90%88%E7%BA%A6ABI%E6%8B%93%E5%B1%95
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

二、簽署交易

需要使用交易賬戶的私鑰對原始交易物件進行簽名,下面介紹使用MetaMask以及硬編碼兩種方式:

MetaMask:私鑰只會儲存在你的瀏覽器上,因此你是唯一有權訪問你的賬戶和私鑰的人。當你在瀏覽器上執行交易之時,外掛會將你的函式呼叫轉化成原始交易,並用你的私鑰簽署交易。 Metamask執行Infura運營的節點,並且使用這些節點來廣播交易。

硬編碼:如下使用了ethereumjs-tx庫對交易進行簽名,當然硬編碼私鑰的方式簽名交易,不實用,但可以使用一臺沒有聯網的計算機簽署該交易。之後,可以複製已簽署交易串,並使用聯網的計算機將其廣播至網路。另一個安全之策是使用 Ledger 或 Trezor 等硬體錢包。這類錢包儲存了私鑰,而簽署交易的私鑰已經程式設計進了硬體本身。它們需要聯網的原因只是為了釋出你的已簽署交易。

var Tx = require('ethereumjs-tx');
var privateKey = "私鑰";

var tx = new Tx(rawTx);
tx.sign(privateKey);

var serializedTx = tx.serialize();

web3.eth.sendRawTransaction(serializedTx.toString('hex'), function(err, hash) {
  doSomething()
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

三、節點驗證

      簽署過後的交易會提交至以太坊節點。然後節點會驗證已簽名的交易,確保它是由交易賬戶簽署過的。

四、交易廣播

      節點驗證通過後,會被廣播至其對等節點,這些對等節點再將該交易廣播給它們的對等節點,以此類推。一旦交易被廣播至網路,會輸出該交易的id,可以用它來追蹤交易的狀態。

五、 礦工節點接受交易

      礦工節點的職責是將交易打包到區塊上。礦工是交易池的維護者,交易先是被新增進交易池,再由礦工進行評估選擇來打包。礦工一般將所有交易儲存在根據gasPrice價格分類的池中。價格越高,該交易就越有可能被新增進下一個區塊。這是礦工節點的常見設定。並且礦池可以容納的交易數是有限的,gasPrice價格低的交易可能會被放棄。

      對於釋放阻塞在礦池中交易的方法是提高其gasPrice價格,並維持nonce值和from值不變,nonce和from可以確定標識一筆交易,並且提高的gasPrice必須大於原來價格的10%才可以。這樣一來,當礦工接收到新交易時,價格更高的新交易會覆蓋之前的交易,使得礦工更容易選擇並挖中。

六、礦工節點挖中有效區塊並將它廣播至網路

      礦工將選中的全部交易一起包含進區塊。礦工只能選擇一定量的交易新增進區塊,受限於以太坊設定的單個區塊gasLimit,換言之,交易的所有gas總數不能超過區塊的gasLimit。

      一旦礦工選擇將交易包含進區塊,這些交易將被驗證幷包含進一個待處理區塊,工作量證明開始。某個礦工節點最終會找到一個有效的區塊,並將這一區塊新增到區塊鏈上。就像上面介紹的節點廣播原始交易一樣,礦工節點也會將這一有效區塊廣播給其他節點。

七、節點接收/同步新區塊

      最終,全網節點將接收這個新區塊,並同步區塊鏈。一旦接收到這個新區塊,節點就會執行區塊裡的所有交易。結合我們使用的truffle呼叫合約程式碼, truffle會不斷測驗連線節點的區塊鏈以求確認。一旦它發現交易被確認,就會執行 then()中的回撥邏輯。

==============================================================

      博主看到很多智慧合約中有引入:ethereumjs-tx這麼個東西,只知道是和簽名相關的,但是在網上卻找不到具體的定義。果然最後還得依靠google才知道,原來它是利用私鑰進行簽名的庫。當我們通過web3.js的sendRawTransaction方法發起交易的時候,必須要用它來簽名。

//安裝
npm install ethereumjs-tx
//引入
var Tx = require('ethereumjs-tx');
  • 1
  • 2
  • 3
  • 4

補充: 第一條構建原始交易物件中的data:

      其中data,若該交易是以太幣交易,則data為空;若是部署合約,則data為合約的bytecode;如果是合約呼叫或者對函式呼叫,即是對函式簽名以及引數編碼的二進位制欄位。

      一個函式呼叫data的前四個位元組資料指定了要呼叫的函式簽名。計算方式是使用函式簽名的keccak256(即sha3)的雜湊,並取4個位元組。寫法bytes4(keccak256(“foo()”))需要注意的是,如果有多個引數使用,隔開,要去掉表示式中的所有空格。

示例:這裡寫圖片描述

      這裡大家就能看到,當在呼叫合約中的函式的時候,必須要取前四個位元組。以前看這段程式碼不太懂這句話是什麼意思,現在才算是懂了。

end

--------------------- 本文來自 李長念 的CSDN 部落格 ,全文地址請點選:https://blog.csdn.net/LJFPHP/article/details/81261050?utm_source=copy