読者です 読者をやめる 読者になる 読者になる

Develop with pleasure!

福岡でCloudとかBlockchainとか。

Segwitなトランザクションをパースしてみる

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)とは別に、↑のmarkerflagwitnessを含めて計算したハッシュ値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も計算できてることが分かる。