LoginSignup
0
0

More than 5 years have passed since last update.

bitcoin-rubyでp2pkhマルチシグスクリプトでロックされるトランザクションを作成する

Posted at

環境

bitcoin-ruby v0.0.18
ruby v2.6.0(by rbenv)
bitcoind v0.17.0.0-5b47b8efd
bitcoin-cli v0.17.0.0-5b47b8efd

やること

bitcoin-rubyをつかってp2pkh形式のマルチシグスクリプトでロックされるトランザクションを作成する。

その他参考

bitcoin-rubyでp2pkhトランザクションを作成する - Qiita
サンプルコード/ 最終的なコードはこちらです。

マルチシグスクリプトとは

解除(unlock)するのに複数の署名を必要とするスクリプト。
multi signature scriptからマルチシグと呼ばれることが多い。

マルチシグスクリプトの構造

マルチシグスクリプトの構造は以下
M <Public Key 1> <Public Key 2> ... <Public Key N> N CHECKMULTISIG
(Mastering Bitcoinを参照されたい)

記号 説明
M スクリプトを解除するのに最低限必要な署名の数
N 有効な署名を作成できる秘密鍵の数

例えば
2 <Public Key 1> <Public Key 2> ... <Public Key 5> 5 CHECKMULTISIG
というスクリプトは、
有効な署名を作成できる秘密鍵の数は5で、そのうち2つの秘密鍵による署名でスクリプトを解除することができるスクリプトである。
2of5のマルチシグと呼ばれる。

トランザクションの作成

bitcoin-rubyのTxBuilderクラスを使用して2of3のマルチシグスクリプトでロックされたトランザクションを作成する。

input

TxBuilderのくわしい使い方はこちら
inputで使用する項目は以下を仮定する。

項目名
前トランザクション c37e9046d2d6cf514f49bdf0d19b88b2ae91fc87f244b8144c111ed3247d6bfb
送信者の秘密鍵 cP9nfzGMqcJ3LrJtsTpWjEUyrybfiFXumzaAobZEBJEPWBtkzDv3

コードは以下

tx = build_tx do |t|
  t.input do |i|
    i.prev_out 'c37e9046d2d6cf514f49bdf0d19b88b2ae91fc87f244b8144c111ed3247d6bfb'
    i.prev_out_index 1
    i.prev_out_script '76a914f9aa5ee91d95360104f173892b916d01d6a485a188ac'.htb
    i.signature_key Bitcoin::Key.from_base58('cP9nfzGMqcJ3LrJtsTpWjEUyrybfiFXumzaAobZEBJEPWBtkzDv3')
  end
end

output

outputに使用する項目は以下を仮定。

項目名
有効な署名を作成できる秘密鍵1 cNBfQu3fAJ1QXMrLvd4PGNAd7RzjUj62kHbkL9owNF2zN2g3M4GB
有効な署名を作成できる秘密鍵2 cPJSC2SZqW3d9EWZTWtnDdGUQY7HFWcCH3cSm4kkkDpidJxp188N
有効な署名を作成できる秘密鍵3 cMujetBk2WXGwnyA1pWZHYLrGVwk1h5V4nYnCQhr9kJshWKPgNpZ
最低限必要な署名の数 2

マルチシグスクリプトの構造は
M <Public Key 1> <Public Key 2> ... <Public Key N> N CHECKMULTISIG
であるから、上記の秘密鍵から公開鍵を生成し、今回作成されるスクリプトは以下のようになる。
2 02ec35d437a41da7ab7f8b8024377ff6b532b49fb95804a73c41af6510663eaf41 039976de4fc156fe8dc5282d89eaf7ddc5e26494877eb8d995d732cd87791a45f4 036647aa901188f4e784bd251e8ddb7802239b911ab66fa90165a3fe5320328ebf 3 OP_CHECKMULTISIG
以下、くわしくみていく。

outputの作り方

outputについても一般的なp2pkhトランザクションの場合と構造は同じ。
しかしTxOutBuilder::toに渡す引数が異なる。
マルチシグの場合toの第一引数には、最低限必要な署名の数と有効な署名を作成できる公開鍵すべてからなる配列を渡す。
第二引数には:multisigを指定。
サンプルは以下。

privkeys = [
  'cNBfQu3fAJ1QXMrLvd4PGNAd7RzjUj62kHbkL9owNF2zN2g3M4GB', 
  'cPJSC2SZqW3d9EWZTWtnDdGUQY7HFWcCH3cSm4kkkDpidJxp188N', 
  'cMujetBk2WXGwnyA1pWZHYLrGVwk1h5V4nYnCQhr9kJshWKPgNpZ'
]

recipients_pubkeys = privkeys.map do |private_key| 
  Bitcoin::Key.from_base58(private_key).pub
end

# recipients_pubkeys = [
#   "02ec35d437a41da7ab7f8b8024377ff6b532b49fb95804a73c41af6510663eaf41",
#   "039976de4fc156fe8dc5282d89eaf7ddc5e26494877eb8d995d732cd87791a45f4",
#   "036647aa901188f4e784bd251e8ddb7802239b911ab66fa90165a3fe5320328ebf"
# ]

tx = build_tx do |t|
  t.output do |o|
    o.value 1999000000
    o.to [2, *recipients_pubkeys], :multisig
  end
end

toに渡された引数は、:multisigが指定されたことで、
Script::to_multisig_script(Github)メソッドに渡される。
Script::to_multisig_scriptがマルチシグスクリプト作成する。

to_multisig_script
  def self.to_multisig_script(m, *pubkeys)
    raise "invalid m-of-n number" unless [m, pubkeys.size].all?{|i| (0..20).include?(i) }
    raise "invalid m-of-n number" if pubkeys.size < m
    pubs = pubkeys.map{|pk| pack_pushdata([pk].pack("H*")) }

    m = m > 16 ?              pack_pushdata([m].pack("C"))              : [80 + m.to_i].pack("C")
    n = pubkeys.size > 16 ?   pack_pushdata([pubkeys.size].pack("C"))   : [80 + pubs.size].pack("C")

    [ m, *pubs, n, [OP_CHECKMULTISIG].pack("C")].join
  end

作成されたトランザクション

サンプルコードを実行するとtxは署名済みトランザクションとなっている。

p tx.to_hash
# 以下作成されたトランザクションHash形式
{"hash"=>"181e9c8b40e6ea9185b44210fd178b05edb87c4680ca390925533bfa08514a3e",
 "ver"=>1,
 "vin_sz"=>1,
 "vout_sz"=>1,
 "lock_time"=>0,
 "size"=>271,
 "in"=>
  [{"prev_out"=>
     {"hash"=>
       "c37e9046d2d6cf514f49bdf0d19b88b2ae91fc87f244b8144c111ed3247d6bfb",
      "n"=>1},
    "scriptSig"=>
     "3044022071d9026597c699421bb2bf4bf30eec35e7fc8167ebbd141251fd75a66f7a49ec022040586df4eb3c230e363e68bf8787f2793b24e54ebff67b1e42e6db9fa443e3f701 02dcc5b4984fc69f13b4cf490a205ab4730bbdfeda0cc78f832a2f701955d36e96"}],
 "out"=>
  [{"value"=>"19.99000000",
    "scriptPubKey"=>
     "2 02ec35d437a41da7ab7f8b8024377ff6b532b49fb95804a73c41af6510663eaf41 039976de4fc156fe8dc5282d89eaf7ddc5e26494877eb8d995d732cd87791a45f4 036647aa901188f4e784bd251e8ddb7802239b911ab66fa90165a3fe5320328ebf 3 OP_CHECKMULTISIG"}]}


p tx.to_payload.unpack('H*')
# 以下作成されたトランザクションの16進数表記
["0100000001fb6b7d24d31e114c14b844f287fc91aeb2889bd1f0bd494f51cfd6d246907ec3010000006a473044022038c0d71a88bb4bedd311ea0e7390f6676123cac8c19daf504e1d08d8909cad3b02206813df8cb267ede803b4633a16291bd0ec20df5af0ea9e88ef23da9c236d6147012102dcc5b4984fc69f13b4cf490a205ab4730bbdfeda0cc78f832a2f701955d36e96ffffffff01c05126770000000069522102ec35d437a41da7ab7f8b8024377ff6b532b49fb95804a73c41af6510663eaf4121039976de4fc156fe8dc5282d89eaf7ddc5e26494877eb8d995d732cd87791a45f421036647aa901188f4e784bd251e8ddb7802239b911ab66fa90165a3fe5320328ebf53ae00000000"]

bitcoin-cli sendrawtransactionでbitcoindで送金できる。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0