以太坊: ETH 傳送交易 sendRawTransaction 方法資料的簽名 和 驗證過程

林冠巨集發表於2018-09-07

作者:林冠巨集 / 指尖下的幽靈

掘金:juejin.im/user/587f0d…

部落格:www.cnblogs.com/linguanh/

GitHub : github.com/af913337456…

騰訊雲專欄: cloud.tencent.com/developer/u…


目錄

  • 前序
  • 資料簽名
    • 整體流程
    • 非對稱加密
    • RLP 序列化
  • 資料驗證
  • 資料篡改

前序

最近的工作一直是基於 以太坊公鏈 做 DApp 開發,雖然對其各 API 的呼叫都已經很瞭解了,但是原始碼部分一直還沒深入去看過。工欲善其事,必先利其器,故計劃閱讀完 以太坊go 版原始碼,後續會更新系列文章。本文主要簡談 sendRawTransaction 是如何保證我們交易安全的。

1.資料簽名

方法:sendRawTransaction

整體流程:

  1. 傳入各引數 ---->
  1. 使用from 對應的 privateKeysecp256k1 演算法對 各入參 簽名得出三個量:V,R,S ---->
  1. RLP (遞迴長度字首) 方式序列比簽名的資料 與 原入引數據 ---->
  1. 傳送到 ETH 節點

sendRawTransaction 函式的各個入參:

  • from 傳送者錢包地址
  • value 數值,為與 decimal 的乘積
  • gas 油費,非最終真實使用值,真實為 gasUsed
  • gasPrice 油費單價
  • data 附屬的資料,可做智慧合約函式入參
  • nonce 交易系列號,類似id

它們都將會被 from 所對應的金鑰 進行簽名而得出三個量:V,R,S。同時,各個入參依然以原來的可見的形式進入序列化步驟。

注意:

還有另外一個叫做 sendTransaction 的方法,通過分析原始碼,可以發現 sendTransaction 內部其實會幫助我們根據我們傳參的 from 欄位到節點的 accountManager 賬號管理器中獲取from 的金鑰,來幫我們進行資料簽名,所以,sendTransaction 一般不會用於遠端呼叫,而用於本地呼叫,因為只有在本地啟動節點的時候,才能配置我們解鎖的錢包。

所用的簽名加密方式是:非對稱加密 中的 secp256k1 橢圓曲線演算法

非對稱加密:

它是一類加密方式的統稱。具體到某種能實現它的演算法有下面幾種:

  • RSA
  • secp256k1 (橢圓曲線)
  • ElGamal
  • ...

sendRawTransaction 用到的就是 secp256k1

RLP 序列化

RLP (遞迴長度字首)提供了一種適用於任意二進位制資料陣列的編碼,RLP已經成為以太坊中對物件進行序列化的主要編碼方式。RLP的唯一目標就是解決結構體的編碼問題;對原子資料型別(比如,字串,整數型,浮點型)的編碼則交給更高層的協議;以太坊中要求數字必須是一個大端位元組序的、沒有零佔位的儲存的格式。

簽名後,資料將會被髮送到 ETH 節點。

2. 資料驗證

對應到以太坊的 sendRawTransaction RPC 介面。

  1. 收到 RLP 序列化的資料後,先進行 RLP 的反序列化
func (s *PublicTransactionPoolAPI) SendRawTransaction(..., encodedTx hexutil.Bytes) (common.Hash, error) {
	tx := new(types.Transaction)
	if err := rlp.DecodeBytes(encodedTx, tx); err != nil { // 反序列化
		return common.Hash{}, err
	}
	return submitTransaction(ctx, s.b, tx)
}
複製程式碼
  1. 資料的基礎校驗,主要是一些範圍限制以及格式限制校驗
    • tx.Size() > 32*102
    • tx.Value().Sign() < 0
    • pool.currentMaxGas < tx.Gas()
    • ...
  2. 檢查簽名,所使用的是 secp256k1.RecoverPubkey 方法,secp256k1 本身支援根據簽名資訊反推公鑰

用訊息和簽名推匯出對方的公鑰。再通過公鑰,簽名,訊息的雜湊值計算出一個叫 r 的值,這個 r 是簽名的一部分,校驗簽名就是拿計算出來的 r 和簽名中攜帶的 r 經行對比,如果一致就校驗通過


if C.secp256k1_ext_ecdsa_recover(
    context,
    (*C.uchar)(unsafe.Pointer(&pubkey[0])), 
    sigdata,  // 簽名
    msgdata) == 0 { // msgdata tx 的 hash 內容
    
    return nil, ErrRecoverFailed
}
複製程式碼

3. 資料篡改

因為簽名生成的 V R S 是由私鑰進行簽名的,如果修改者只修改了外部的值,例如 value,本來是要轉 10 個 ETH , 被改成轉 100 個,等資料傳到以太坊的時候,在檢查簽名的時候,就會發現不匹配,而丟擲錯誤。

相關文章