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

Develop with pleasure!

福岡でCloudとかBlockchainとか。

P2WPKHを使うトランザクションの作成と署名

Bitcoin Segwit Ruby

だいぶ前に書き始めて放置してたのでちゃんと実装してみた。

以前↓のようにwitnessなトランザクションのパース方法について書いたので、

techmedia-think.hatenablog.com

続いてwitnessなトランザクションを作ってみる。

P2WPKHにBitcoinを送付

まず最初にP2WPKH(Pay-to-Witness-Public-Key-Hash)のscriptPubkeyに対してBitcoinの支払いをするトランザクションを作成する。

P2WPKHのscriptPubkeyは以下のフォーマットの22バイトのデータになる。

0 < 20-byte-pubkey-hash >

実際にtestnetでP2WPKHの支払いをしたトランザクションが↓

{
  "hex": "0100000001f55cb86d8d04d4759fb8b05a198cf4d48d790e6c64d00e072aed98281d0ebff1010000006b483045022100fe718c5f0bb58d86225e1d9370f858b8c864f00112c6a33f9910fa7ea8e9c34b02203cef1a73a0a8e210c6a264446bbb90c86b7b6f6e6f411aa505f0a835ff147204012102effb2edfcf826d43027feae226143bdac058ad2e87b7cec26f97af2d357ddefaffffffff02806d0d00000000001600148911455a265235b2d356a1324af000d4dae0326250a1c917000000001976a9142c159d64daa0de5ae6abac61a9416c8a54e834bd88ac00000000",
  "txid": "fdb55428ed5a1949cad4732fcb1be031a9790e7e0f651fd33129909065511580",
  "hash": "fdb55428ed5a1949cad4732fcb1be031a9790e7e0f651fd33129909065511580",
  "size": 223,
  "vsize": 223,
  "version": 1,
  "locktime": 0,
  "vin": [
    {
      "txid": "f1bf0e1d2898ed2a070ed0646c0e798dd4f48c195ab0b89f75d4048d6db85cf5",
      "vout": 1,
      "scriptSig": {
        "asm": "3045022100fe718c5f0bb58d86225e1d9370f858b8c864f00112c6a33f9910fa7ea8e9c34b02203cef1a73a0a8e210c6a264446bbb90c86b7b6f6e6f411aa505f0a835ff147204[ALL] 02effb2edfcf826d43027feae226143bdac058ad2e87b7cec26f97af2d357ddefa",
        "hex": "483045022100fe718c5f0bb58d86225e1d9370f858b8c864f00112c6a33f9910fa7ea8e9c34b02203cef1a73a0a8e210c6a264446bbb90c86b7b6f6e6f411aa505f0a835ff147204012102effb2edfcf826d43027feae226143bdac058ad2e87b7cec26f97af2d357ddefa"
      },
      "sequence": 4294967295
    }
  ],
  "vout": [
    {
      "value": 0.00880000,
      "n": 0,
      "scriptPubKey": {
        "asm": "0 8911455a265235b2d356a1324af000d4dae03262",
        "hex": "00148911455a265235b2d356a1324af000d4dae03262",
        "type": "witness_v0_keyhash"
      }
    }, 
    {
      "value": 3.99090000,
      "n": 1,
      "scriptPubKey": {
        "asm": "OP_DUP OP_HASH160 2c159d64daa0de5ae6abac61a9416c8a54e834bd OP_EQUALVERIFY OP_CHECKSIG",
        "hex": "76a9142c159d64daa0de5ae6abac61a9416c8a54e834bd88ac",
        "reqSigs": 1,
        "type": "pubkeyhash",
        "addresses": [
          "mjY3vKRzyHkpB5kbEwCxFNmkFb4wKVDVab"
        ]
      }
    }
  ]
}

0番目の出力がP2WPKHへの支払いで、scriptPubKeyのtypewitness_v0_keyhashになっているのがわかる。

witnessなトランザクションの作成と署名

↑でP2WPKH宛に送ったBitcoinを入力にしたトランザクションの作成と署名をする。

ここで注意するのが、署名の方法も従来とは変わっているということ。
署名時に計算するトランザクションのSIG_HASHの新しい計算方法がBIP-143で定義されている↓

techmedia-think.hatenablog.com

BIP-143の仕様をbitcoin-rubyで実装してみたのが↓

まだプルリクは出してないけど、bitcoin-rubyにsegwit対応のコードを実装してるのが↓

github.com

(仕様が変わる可能性はあるけど)現状の↑を使ってP2WPKHのUTXOを使用するコードは以下のように書ける↓ P2WPKHのwitness<signature> <pubkey>の構成になる。

from_key = Bitcoin::Key.from_base58('P2WPKHのUTXOの秘密鍵')
prev_tx = Bitcoin::Protocol::Tx.new('P2WPKHのUTXOを持つトランザクションのrawデータ')

tx = Bitcoin::Protocol::Tx.new
tx.add_in(Bitcoin::Protocol::TxIn.from_hex_hash(prev_tx.hash, 0))
tx.add_out(Bitcoin::Protocol::TxOut.value_to_address(880000 - 10000, from_key.addr))

# BIP-143の仕様でSIGHASHを生成
sig_hash = tx.signature_hash_for_witness_input(0, prev_tx.out[0].script, 880000)

sig = from_key.sign(sig_hash) + [Bitcoin::Script::SIGHASH_TYPE[:all]].pack("C")

# witnessを構成(P2WPKHなのでwitnessは、 "<署名> <公開鍵>" の構成)
win = Bitcoin::Protocol::TxInWitness.new
win.add_stack(sig.bth)
win.add_stack(from_key.pub)

tx.witness.add_witness(win)

# witnessなペイロード
puts tx.to_witness_payload.bth

生成したwitnessペイロードを実際にtestnetでブロードキャストしたトランザクションが↓

{
  "hex": "010000000001018015516590902931d31f650f7e0e79a931e01bcb2f73d4ca49195aed2854b5fd0000000000ffffffff0170460d00000000001976a9148911455a265235b2d356a1324af000d4dae0326288ac02473044022009ea34cf915708efa8d0fb8a784d4d9e3108ca8da4b017261dd029246c857ebc02201ae570e2d8a262bd9a2a157f473f4089f7eae5a8f54ff9f114f624557eda7420012102effb2edfcf826d43027feae226143bdac058ad2e87b7cec26f97af2d357ddefa00000000",
  "txid": "07b09f22abd2d78c41b2984f05d3dd83a3c5905771f0ee290b04f933e0c13d59",
  "hash": "ac6506dab409881178f4d1b416188f903e85a5d588f175d930911532cb53ac58",
  "size": 194,
  "vsize": 113,
  "version": 1,
  "locktime": 0,
  "vin": [
    {
      "txid": "fdb55428ed5a1949cad4732fcb1be031a9790e7e0f651fd33129909065511580",
      "vout": 0,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "txinwitness": [
        "3044022009ea34cf915708efa8d0fb8a784d4d9e3108ca8da4b017261dd029246c857ebc02201ae570e2d8a262bd9a2a157f473f4089f7eae5a8f54ff9f114f624557eda742001", 
        "02effb2edfcf826d43027feae226143bdac058ad2e87b7cec26f97af2d357ddefa"
      ],
      "sequence": 4294967295
    }
  ],
  "vout": [
    {
      "value": 0.00870000,
      "n": 0,
      "scriptPubKey": {
        "asm": "OP_DUP OP_HASH160 8911455a265235b2d356a1324af000d4dae03262 OP_EQUALVERIFY OP_CHECKSIG",
        "hex": "76a9148911455a265235b2d356a1324af000d4dae0326288ac",
        "reqSigs": 1,
        "type": "pubkeyhash",
        "addresses": [
          "mt1hZLajqyc63NkWy7qvgiuum5nuTBdVZ6"
        ]
      }
    }
  ]
}

次はP2WSHの署名を。