witnessなトランザクション用にBIP-144で新しいシリアライゼーションフォーマットが定義された↓
techmedia-think.hatenablog.com
ので実際にそのフォーマットに従ってトランザクションをパースしてみた。
フォーマットの変更点
詳細はBIP-144に定義されているけど、新しいシリアライゼーションフォーマットは以下のデータで構成される。
- version
- marker
- flag
- txins
- txouts
- witness
- locktime
この内、従来のトランザクションのフォーマットになかったのが、marker
(0x00
)とflag
(現在は0x01
)とwitness
。
witness
はトランザクションの全てのwitnessデータをシリアライズしたもの。witnessのデータはtxinのスタックアイテムの数を示すvar_intで始まる。その後にスタックアイテムが続き、各スタックアイテムはアイテムの長さを示すvar_intで始まる。witnessデータはスクリプトではないので、520バイトの制限も無い。
トランザクションのハッシュ
従来のトランザクションハッシュ(txid
)とは別に、↑のmarker
とflag
とwitness
を含めて計算したハッシュ値wtxid
が追加された。
パース処理
witnessなトランザクションをシリアライズしたデータが↓
010000000001017429cc7f5323b3142bd69ead220506d25194453869ac2da56fa9f0b0b6bef25f0100000017160014acb7723d69307cec7da04fd5f8d38024e8afae5dffffffff01e8030000000000001976a914548742b7ee154defc3837876854490e8f6770c5e88ac0248304502210089b7eae18320dddf00e1e189e645b30a87d89cb1cac5bf6508df5fe79354c0cb0220070eb81658ca5e441c15ff4d11cd9ba4dd71f2be35a51da43fdf951d7ca19d5f012103c4ede29e2972d7ea15c141df4b8bc5aaf9cd0a1aba6e67cc3b6f9cee9d111f9000000000
decoderawtransaction
正しくパースできているか確認するため、Bitcoin CoreのAPIを使って正しいwitnessデータを確認しておく。
bitcoin-cli -regtest decoderawtransaction 010000000001017429cc7f5323b3142bd69ead220506d25194453869ac2da56fa9f0b0b6bef25f0100000017160014acb7723d69307cec7da04fd5f8d38024e8afae5dffffffff01e8030000000000001976a914548742b7ee154defc3837876854490e8f6770c5e88ac0248304502210089b7eae18320dddf00e1e189e645b30a87d89cb1cac5bf6508df5fe79354c0cb0220070eb81658ca5e441c15ff4d11cd9ba4dd71f2be35a51da43fdf951d7ca19d5f012103c4ede29e2972d7ea15c141df4b8bc5aaf9cd0a1aba6e67cc3b6f9cee9d111f9000000000 { "txid": "e3fb34cf322c33fb4361647548e5327356bd3d47ccac11e31dabdac7e3a7a746", "hash": "9072d375c4093ac7951feeeabc36e6cda5d899ca819285a6200440483adb2bf4", "size": 218, "vsize": 136, "version": 1, "locktime": 0, "vin": [ { "txid": "5ff2beb6b0f0a96fa52dac6938459451d2060522ad9ed62b14b323537fcc2974", "vout": 1, "scriptSig": { "asm": "0014acb7723d69307cec7da04fd5f8d38024e8afae5d", "hex": "160014acb7723d69307cec7da04fd5f8d38024e8afae5d" }, "txinwitness": [ "304502210089b7eae18320dddf00e1e189e645b30a87d89cb1cac5bf6508df5fe79354c0cb0220070eb81658ca5e441c15ff4d11cd9ba4dd71f2be35a51da43fdf951d7ca19d5f01", "03c4ede29e2972d7ea15c141df4b8bc5aaf9cd0a1aba6e67cc3b6f9cee9d111f90" ], "sequence": 4294967295 } ], "vout": [ { "value": 0.00001000, "n": 0, "scriptPubKey": { "asm": "OP_DUP OP_HASH160 548742b7ee154defc3837876854490e8f6770c5e OP_EQUALVERIFY OP_CHECKSIG", "hex": "76a914548742b7ee154defc3837876854490e8f6770c5e88ac", "reqSigs": 1, "type": "pubkeyhash", "addresses": [ "moDu6EtnGGpcTEkNZRJbytr9rJA4H49VRe" ] } } ] }
自前で実装したパース処理
bitcoin-rubyを使って自前でパース処理を実装してみた↓
実行結果が↓
{ "txid": "e3fb34cf322c33fb4361647548e5327356bd3d47ccac11e31dabdac7e3a7a746", "wtxid": "9072d375c4093ac7951feeeabc36e6cda5d899ca819285a6200440483adb2bf4", "version": 1, "marker": 0, "flag": 1, "vin": [ { "prev_out": { "hash": "5ff2beb6b0f0a96fa52dac6938459451d2060522ad9ed62b14b323537fcc2974", "n": 1 }, "scriptSig": "0014acb7723d69307cec7da04fd5f8d38024e8afae5d" } ], "vout": [ { "value": "0.00001000", "scriptPubKey": "OP_DUP OP_HASH160 548742b7ee154defc3837876854490e8f6770c5e OP_EQUALVERIFY OP_CHECKSIG" } ], "witness": [ "304502210089b7eae18320dddf00e1e189e645b30a87d89cb1cac5bf6508df5fe79354c0cb0220070eb81658ca5e441c15ff4d11cd9ba4dd71f2be35a51da43fdf951d7ca19d5f01", "03c4ede29e2972d7ea15c141df4b8bc5aaf9cd0a1aba6e67cc3b6f9cee9d111f90" ], "lock_time": 0 }
witnessのデータがパースでき、wtxidも計算できてることが分かる。