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

# 環境
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](https://github.com/lian/bitcoin-ruby)をつかってp2pkh形式のマルチシグスクリプトでロックされるトランザクションを作成する。

## その他参考
[bitcoin-rubyでp2pkhトランザクションを作成する - Qiita](https://qiita.com/kanna/items/7fe607ec6f6321f2cdc9)
[サンプルコード](https://gist.github.com/kannapoix/9ef66b0267cfe906239184c82711da30)/ 最終的なコードはこちらです。

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

### マルチシグスクリプトの構造
マルチシグスクリプトの構造は以下
`M <Public Key 1> <Public Key 2> ... <Public Key N> N CHECKMULTISIG`
([Mastering Bitcoin](https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch07.asciidoc#multisignature)を参照されたい)

|記号|説明|
|:--:|:--:|
|M|スクリプトを解除するのに最低限必要な署名の数|
|N|有効な署名を作成できる秘密鍵の数|
例えば
`2 <Public Key 1> <Public Key 2> ... <Public Key 5> 5 CHECKMULTISIG`
というスクリプトは、
有効な署名を作成できる秘密鍵の数は５で、そのうち2つの秘密鍵による署名でスクリプトを解除することができるスクリプトである。
2of5のマルチシグと呼ばれる。

# トランザクションの作成
bitcoin-rubyの[TxBuilderクラス](https://github.com/lian/bitcoin-ruby/blob/48b8897efae4aeb67eef0c5750ec30fe1478510b/lib/bitcoin/builder.rb#L136)を使用して2of3のマルチシグスクリプトでロックされたトランザクションを作成する。

 
## input
`TxBuilder`のくわしい使い方は[こちら](https://qiita.com/kanna/items/7fe607ec6f6321f2cdc9#builder)
inputで使用する項目は以下を仮定する。

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

コードは以下

```ruby
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`を指定。
サンプルは以下。

```ruby
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](https://github.com/lian/bitcoin-ruby/blob/48b8897efae4aeb67eef0c5750ec30fe1478510b/lib/bitcoin/script.rb#L817))メソッドに渡される。
`Script::to_multisig_script`がマルチシグスクリプト作成する。

```ruby: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
```

## 作成されたトランザクション
[サンプルコード](https://gist.github.com/kannapoix/9ef66b0267cfe906239184c82711da30)を実行すると`tx`は署名済みトランザクションとなっている。

```ruby
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で送金できる。