鏈上原始交易解碼:拆解區塊鏈交易的輸入、輸出與腳本結構

鏈上原始交易解碼:拆解區塊鏈交易的輸入、輸出與腳本結構
字号
【导读】從十六進位原始位元組出發,介紹 UTXO 與帳戶模型的解碼差異、比特幣交易欄位與腳本模板、SIGHASH 標誌,以及以太坊型別化交易與 Calldata 解析流程。

打開任何一個區塊瀏覽器,輸入一筆交易哈希,通常會得到一張整理完備的表格:發送方、接收方、金額、手續費、確認數與狀態。這張表格是瀏覽器節點解析後的呈現,而鏈上真正被廣播、被節點驗證並打包進區塊的核心資料,本質上是一串十六進位原始字元(Raw Transaction Hex)。

這串原始位元組中並沒有直接標註「發送方」這個欄位,也沒有「帳戶餘額」的即時標籤。裡層結構僅由位元組長度前綴、引用的輸出索引、解鎖腳本、鎖定腳本與簽名組成。當區塊瀏覽器的解析邏輯與預期出現落差,或者面對多簽、合約內部調用與複雜找零機制時,掌握鏈上原始交易解碼的能力,便成為釐清資金真實流向與鏈上狀態的唯一確定手段。

區塊瀏覽器是經過二次加工的譯文,原始位元組才是底層共識認可的原文。

帳本模型差異:UTXO 與帳戶模型的解碼心智

同樣被稱為交易,比特幣與以太坊在底層位元組序列化上存在根本差異。理解帳本架構是解讀原始欄位的前提,能避免在比特幣交易中尋找發送方地址,或在以太坊交易中尋找找零輸出的概念錯位。

兩者在底層結構上的共通點在於:原始交易資料均不包含顯式的發送方(From)欄位。比特幣依靠輸入所引用的前序輸出腳本與當前提供的簽名驗證花費權限;以太坊則透過簽名參數反向推導出發送方公鑰與地址。瀏覽器介面呈現的來源地址,皆為解碼器運算後填入的視覺化資訊。

比較項目 UTXO 模型(比特幣系) 帳戶模型(以太坊系)
價值載體 未花費交易輸出(UTXO) 全局狀態樹中的帳戶餘額
交易本質 銷毀一組既有 UTXO,生成一組全新 UTXO 觸發狀態轉換的單向指令
發送方判定 無顯式欄位,由輸入解鎖腳本/見證資料證明 無顯式欄位,由 ECDSA 簽名(v, r, s)反推得出
找零機制 必須明確包含找零輸出,未分配差額視為手續費 無找零概念,直接扣除轉帳與消耗費用
費用計算 輸入總額 – 輸出總額 = 礦工費 實際 GasUsed × 有效 Gas 價格

比特幣原始交易的位元組結構拆解

比特幣交易的序列化具有高度嚴謹的定長與長度前綴規則。包含隔離見證(SegWit)擴展的通用交易欄位排列順序如下:

欄位名稱 位元組長度 欄位說明
Version 4 位元組 小端序,指定交易規則版本(常用 1 或 2)
Marker & Flag 可選 2 位元組 SegWit 專用標記,固定為 0x0001(非 SegWit 交易無此欄位)
TxIn Count 可變整數(CompactSize) 輸入陣列元素數量(1、3、5 或 9 位元組)
TxIn List 可變長度 包含所有輸入向量本體
TxOut Count 可變整數(CompactSize) 輸出陣列元素數量(1、3、5 或 9 位元組)
TxOut List 可變長度 包含所有輸出向量本體
Witness Data 可變長度 僅 SegWit 交易包含,緊接於輸出列表後、LockTime 之前
LockTime 4 位元組 小端序,指定交易生效的區塊高度或 Unix 時間戳

在解析位元組時需注意兩個關鍵編碼規則:

  • 小端序(Little-Endian)讀取:數值型欄位(如版本號、金額、LockTime)均採用低位元組在前的方式編碼。例如金額欄位為 8 位元組整數(單位為 Satoshi)。同時,輸入中的前序交易哈希在序列化資料中為小端序存放,而區塊瀏覽器顯示的 TxID 為大端序(需將位元組順序前後完全反轉)。
  • 可變整數(CompactSize / VarInt):長度編碼並非固定寬度。小於 253 時佔 1 位元組;等於 0xfd 時後接 2 位元組;等於 0xfe 時後接 4 位元組;等於 0xff 時後接 8 位元組。解析時必須動態判斷步長。

交易輸入與輸出結構剖析

在 UTXO 模型中,輸入(TxIn)負責引導並消耗既有資產,輸出(TxOut)負責鎖定並分配新資產。

交易輸入(TxIn)的五大組成

每個輸入項目在序列化資料中由五個部分組成:

鏈上原始交易解碼:交易輸入(TxIn)的五大組成相关概念与关系示意
每個輸入項目在序列化資料中由五個部分組成:
  1. Previous TxID(32 位元組):被引用的前序交易雜湊(小端序存放)。
  2. Previous Output Index(4 位元組):前序交易中的輸出索引號(vout,從 0 起算)。
  3. Script Length(VarInt):解鎖腳本(scriptSig)的長度。
  4. ScriptSig(可變長度):提供解鎖所需的簽名與公鑰等數據(原生 SegWit 交易此處長度為 0x00)。
  5. Sequence(4 位元組):交易序號。

Sequence 欄位在不同條件下具備多重功能:當值小於 0xfffffffe 時,代表支援 BIP125 手續費替代機制(Opt-in RBF);當交易版本 nVersion >= 2 且 Sequence 最高位(bit 31)為 0 時,此欄位會被解析為 BIP68 相對時間鎖;若所有輸入的 Sequence 均為 0xffffffff,交易直接定稿,LockTime 將不再施加約束。

交易輸出(TxOut)與腳本模板

每個輸出由兩部分構成:8 位元組的金額(Value,以 Satoshi 為單位的小端序)以及帶長度前綴的鎖定腳本(scriptPubKey)。常見的腳本標準特徵如下:

腳本類型 位元組開頭模式 解析邏輯說明
P2PKH 76 a9 14 ... 88 ac 標準公鑰哈希鎖定,解鎖需簽名與完整公鑰
P2SH a9 14 ... 87 腳本哈希鎖定,常用於傳統多重簽名
P2WPKH 00 14 ... 原生隔離見證 v0 公鑰哈希,簽名資料移至 Witness 欄位
P2WSH 00 20 ... 原生隔離見證 v0 腳本哈希(32 位元組 SHA256)
P2TR 51 20 ... Taproot(SegWit v1),支援密鑰路徑與腳本樹路徑花費
OP_RETURN 6a ... 不可花費輸出(腳本驗證必然失敗),專門用於鏈上嵌入任意資料

簽名雜湊範圍:SIGHASH 標誌

比特幣交易簽名並非直接對全部原始資料進行雜湊,而是依據簽名末尾的 SIGHASH 標誌 決定簽名涵蓋的資料範圍:

  • 0x01 (SIGHASH_ALL):簽名覆蓋所有輸入與所有輸出,最常見且具備最高防篡改性。
  • 0x02 (SIGHASH_NONE):簽名覆蓋所有輸入,但不覆蓋任何輸出,允許第三方修改收款對象。
  • 0x03 (SIGHASH_SINGLE):僅覆蓋所有輸入以及與該輸入相同索引號的單一輸出。
  • 0x81 (ALL | ANYONECANPAY):僅覆蓋當前輸入與所有輸出,允許其他人追加輸入組合。

以太坊型別化交易與 Calldata 解析

以太坊在經歷演進後,依據 EIP-2718 標準確立了型別化交易(Envelope Transaction)體系。在序列化位元組的最前端,單一標記位元組決定了後續 RLP 的編碼邏輯:0x01 代表 EIP-2930 存取清單交易,0x02 代表 EIP-1559 費用市場交易,0x03 代表 EIP-4844 Blob 攜帶交易。

以 EIP-1559 交易為例,其封裝欄位包含:chainId、nonce、maxPriorityFeePerGas、maxFeePerGas、gasLimit、to、value、data、accessList、以及簽名欄位(yParity, r, s)。在早期 Legacy 交易中,v 值僅代表恢復識別碼(27 或 28);在 EIP-155 實施後,v 的計算納入了 chainId,以防止跨鏈重放攻擊。

鏈上原始交易解碼:以太坊型別化交易與 Calldata 解析相关概念与关系示意
以 EIP-1559 交易為例,其封裝欄位包含:chainId、nonce、maxPriorityFeePerGas、maxFeePerGas、gasLimit、to、value、data、acces

Calldata 與事件日誌的解讀差異

當交易 to 指向智慧合約且 value 為 0 時,核心意圖完全由 data 欄位承載:

  • 函數選擇器(Function Selector):Calldata 前 4 位元組,為函數簽名 Keccak-256 雜湊的前 4 位元組。例如 0xa9059cbb 對應 transfer(address,uint256)。
  • 參數列表:自第 5 位元組起,每 32 位元組為一個單位對齊編碼(ABI Encoding)。
  • 事件日誌(Event Logs)結構:依據 EIP-20 規範,Transfer 事件定義為 Transfer(address indexed from, address indexed to, uint256 value)。在解碼收據(Receipt)時,topics[0] 為事件簽名哈希,topics[1] 為發送方地址(from),topics[2] 為接收方地址(to),而轉帳金額 value 屬於未索引欄位,存放於 Log 的 data 區塊中。

標準解碼操作流程與審計要點

  1. 獲取完整原始資料:透過節點 RPC(如 Bitcoin Core 的 getrawtransaction,查詢歷史交易需節點開啟 txindex=1 或傳入所屬區塊哈希;以太坊透過 eth_getRawTransactionByHash)取得未經修剪的 Hex 字串。
  2. 識別協議與交易型別:比特幣檢查第 5、6 位元組是否為 0x0001 判定是否啟用 SegWit 格式;以太坊讀取首位元組判斷 EIP-2718 型別。
  3. 游標步進解析位元組:依序解析版本號、輸入長度、輸入清單、輸出長度、輸出清單、見證資料(若有)與 LockTime。嚴格按照 CompactSize 返回的偏移量推進游標。
  4. 回溯前序狀態:將 TxIn 中的交易哈希反轉為大端序,查詢前序輸出的腳本類型與鎖定金額,以校驗手續費(輸入總值 – 輸出總值)。
  5. 驗證腳本與調用意圖:解析腳本操作碼與參數堆疊;以太坊則進一步提取 Calldata 與 Receipt 日誌,確認是否存在內部調用(Internal Transactions)引發的狀態變更。

常見問題(FAQ)

Q1:為什麼把區塊瀏覽器上的交易雜湊貼進原始交易 Hex 中搜尋不到?

因為位元組序存放格式不同。區塊瀏覽器顯示的 TxID 是經由雙重 SHA-256 後進行「大端序(Big-Endian)」顯示的結果;但在原始交易輸入的 PrevTxID 欄位中,雜湊是以原始「小端序(Little-Endian)」形式序列化。若需在 Hex 中檢索前序交易,必須將 32 位元組字串每兩位一組前後完全倒序排列。

Q2:ERC-20 代幣轉帳的原始金額可以在交易的 Value 欄位中看到嗎?

不能。代幣轉帳並非原生 ETH 轉移,交易本身的 value 欄位通常為 0。代幣轉帳的接收者地址與轉帳數量被編碼在 data(Calldata)中,且合約執行完成後的實際結算數值記載於交易收據 Log 的 data 區塊內。

Q3:如何從原始資料判斷一筆比特幣交易能否進行 RBF 加價替換?

檢查交易中所有輸入項目的 Sequence 數值。依據 BIP125 標準,只要有任一輸入項目的 Sequence 小於 0xfffffffe(常見預設為 0xfffffffd),該筆處於未確認狀態的交易即被視為可選擇性替換(Opt-in RBF)。

Q4:SegWit 交易的見證資料(Witness)放在交易序列化的哪個位置?

見證資料緊接在輸出列表(TxOut List)之後,並排在最後 4 位元組的 LockTime 之前。在自建解碼器時,不能將見證資料視為交易末端,否則會導致最後的 LockTime 欄位解析錯位。

admin

作者负责资讯整理、核查与撰写。 · 已发布 93 篇文章

查看作者全部文章