btc: btcdebを使う (2)
2025/01/20
はじめに
btcdeb を使ってスクリプトのデバッグをしてみよう。
bitcoin-core/btcdeb: Bitcoin Script Debugger
前回はドキュメントに書いてあるように使っただけなので、今回は P2TR script path の確認をしていたときのデータを使ってやってみる。
script path の例
こちらの例を使う。
input tx=d1c40446c65456a9b11a9dddede31ee34b8d3df83788d98f690225d2958bfe3c
でスクリプトはこういう形だ(“leaf script”)。
20 6d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0
OP_CHECKSIG
P2TR 以外であれば pubkey は 33バイトなので 0x21 で始まるが、P2TR の tapscript という時点でシュノア署名になるので 0x20 だ。
いつも「データ長」と書いているが、正しくはスタックにデータを積む OPコードだ。
OPコードの 0x01
-0x4b
までは同じ値の長さをその次のデータからスタックに積む、という命令になっている。
つまりここに出てくる「0x20」は、その次のデータから 0x20 バイト(32 バイト)をスタックに積むのである。
--tx : d1c40446c65456a9b11a9dddede31ee34b8d3df83788d98f690225d2958bfe3c
<<tx:d1c40446c65456a9b11a9dddede31ee34b8d3df83788d98f690225d2958bfe3c>>
02000000
0001
<vin_cnt>
01
<vin#0>
3cfe8b95d22502698fd98837f83d8d4be31ee3eddd9d1ab1a95654c64604c4d1 00000000
00
ffffffff
<vout_cnt>
01
<vout#0>
983a000000000000
1600140de745dc58d8e62e6f47bde30cd5804a82016f9e
<vin#0 witness_cnt>
03
<vin#0 witness#0>
4101769105cbcbdcaaee5e58cd201ba3152477fda31410df8b91b4aee2c4864c7700615efb425e002f146a39ca0a4f2924566762d9213bd33f825fad83977fba7f01
<vin#0 witness#1>
22206d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0ac
<vin#0 witness#2>
21c0924c163b385af7093440184af6fd6244936d1288cbb41cc3812286d3f83a3329
<locktime>
00000000
--txin
を使う
既に展開済みになっているデータもあるので --txin
を使ってみよう。
797505b104b5fb840931c115ea35d445eb1f64c9279bf23aa5bb4c3d779da0c2
のデータである。
--txin : 797505b104b5fb840931c115ea35d445eb1f64c9279bf23aa5bb4c3d779da0c2
<<txin:797505b104b5fb840931c115ea35d445eb1f64c9279bf23aa5bb4c3d779da0c2>>
02000000
0001
<vin_cnt>
<vin#0>
関係ないので省略
<vout_cnt>
02
<vout#0> ※こちら
204e000000000000
225120f3778defe5173a9bf7169575116224f961c03c725c0e98b8da8f15df29194b80
<vout#1>
7472000000000000
1600149524b39436fd4abe0d48b156ebfb5d9c0d48850c
<witness>
関係ないので省略
<locktime>
052d0d00
実行。
$ btcdeb --tx=020000000001013cfe8b95d22502698fd98837f83d8d4be31ee3eddd9d1ab1a95654c64604c4d10000000000ffffffff01983a0000000000001600140de745dc58d8e62e6f47bde30cd5804a82016f9e034101769105cbcbdcaaee5e58cd201ba3152477fda31410df8b91b4aee2c4864c7700615efb425e002f146a39ca0a4f2924566762d9213bd33f825fad83977fba7f0122206d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0ac21c0924c163b385af7093440184af6fd6244936d1288cbb41cc3812286d3f83a332900000000 --txin=02000000000101289c4d2de39f53acc69da3d641810545c1b9b198a0c6b521456e2e12c2b7c6680000000000fdffffff02204e000000000000225120f3778defe5173a9bf7169575116224f961c03c725c0e98b8da8f15df29194b8074720000000000001600149524b39436fd4abe0d48b156ebfb5d9c0d48850c02473044022030b384e51521b2031cf8bab2a8a0f52dbec70cf199a6139b7ed81fbcdd382b48022038df47f71d4c5cf601366e52c3d808fa724e2deb207f5d3408f0577d5dc2f7aa0121037daba156158ed0d92c6acc34c3061af3b1a788b4f33772e27be1fdb569015d0a052d0d00
btcdeb 5.0.24 -- type `btcdeb -h` for start up options
LOG: signing segwit taproot
notice: btcdeb has gotten quieter; use --verbose if necessary (this message is temporary)
input tx index = 0; tx input vout = 0; value = 20000
got witness stack of size 3
34 bytes (v0=P2WSH, v1=taproot/tapscript)
Taproot commitment:
- control = c0924c163b385af7093440184af6fd6244936d1288cbb41cc3812286d3f83a3329
- program = f3778defe5173a9bf7169575116224f961c03c725c0e98b8da8f15df29194b80
- script = 206d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0ac
- path len = 0
- p = 924c163b385af7093440184af6fd6244936d1288cbb41cc3812286d3f83a3329
- q = f3778defe5173a9bf7169575116224f961c03c725c0e98b8da8f15df29194b80
- k = 16ef34a5bc45e95857f751fc3511a6f6ad0a1f631deefcc1a248dda326fe8d85 (tap leaf hash)
(TapLeaf(0xc0 || 206d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0ac))
valid script
- generating prevout hash from 1 ins
[+] COutPoint(d1c40446c6, 0)
4 op script loaded. type `help` for usage information
script | stack
-------------------------------------------------------------------+-------------------------------------------------------------------
<<< taproot commitment >>> | i: 0
Tweak: 924c163b385af7093440184af6fd6244936d1288cbb41cc3812286d3... | k: 858dfe26a3dd48a2c1fcee1d631f0aadf6a61135fc51f75758e945bca534...
CheckTapTweak |
<<< committed script >>> |
6d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0 |
OP_CHECKSIG |
#0000 Tweak: 924c163b385af7093440184af6fd6244936d1288cbb41cc3812286d3f83a3329
- control block:
c0924c163b385af7093440184af6fd6244936d1288cbb41cc3812286d3f83a3329
- leaf script:
206d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0ac
- internal public key:
924c163b385af7093440184af6fd6244936d1288cbb41cc3812286d3f83a3329
- tweaked public key:
f3778defe5173a9bf7169575116224f961c03c725c0e98b8da8f15df29194b80
- signature:
01769105cbcbdcaaee5e58cd201ba3152477fda31410df8b91b4aee2c4864c7700615efb425e002f146a39ca0a4f2924566762d9213bd33f825fad83977fba7f01
btcdeb の k
が不明だ。
スタックの方にも k
が出ているが、また違う値だしこちらの値も不明だ。
スクリプトで必要になるのは OP_CHECKSIG
のための署名だけなので、--tx
の<vin#0 witness#0>
は署名である。
それ以降は script path のルールに従ってスクリプトを次の <vin#0 witness#1>
に、最後は control block を vin#0 witness#2>
に置いてある。
ステップ実行
以下、step
でステップ実行していく。
- #0000 Tweak: 924c163b385af7093440184af6fd6244936d1288cbb41cc3812286d3f83a3329
- 署名がスタックに積まれた
btcdeb> step
- looping over path (0..-1)
- q.CheckTapTweak(p, k, 0) == success
script | stack
-------------------------------------------------------------------+-------------------------------------------------------------------
6d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0 | 01769105cbcbdcaaee5e58cd201ba3152477fda31410df8b91b4aee2c4864c7...
OP_CHECKSIG |
#0001 CheckTapTweak
- #0001 CheckTapTweak
- left script がスタックに積まれた
btcdeb> step
<> PUSH stack 6d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0
script | stack
-------------------------------------------------------------------+-------------------------------------------------------------------
OP_CHECKSIG | 6d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0
| 01769105cbcbdcaaee5e58cd201ba3152477fda31410df8b91b4aee2c4864c7...
#0002 6d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0
- #0002 6d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0
- ここからスクリプトの部分なのだけど、1つ前にスタックに積まれたのはこれじゃないのか?
- シュノア署名どういう出力されているので、実行されたのは
OP_CHECKSIG
? - “success” なので計算はできているのか
btcdeb> step
EvalChecksig() sigversion=3
Eval Checksig Tapscript
- sig must not be empty: ok
- validation weight - 50 -> 136
- 32 byte pubkey (new type); schnorr sig check
GenericTransactionSignatureChecker::CheckSchnorrSignature(65 len sig, 32 len pubkey, sigversion=3)
sig = 01769105cbcbdcaaee5e58cd201ba3152477fda31410df8b91b4aee2c4864c7700615efb425e002f146a39ca0a4f2924566762d9213bd33f825fad83977fba7f01
pub key = 6d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0
SignatureHashSchnorr(in_pos=0, hash_type=01)
- tapscript sighash
- schnorr sighash = c980a90108fc424b92ab0ed0d9d889ebe59fd664d69720daa011e573d4532475
pubkey.VerifySchnorrSignature(sig=01769105cbcbdcaaee5e58cd201ba3152477fda31410df8b91b4aee2c4864c7700615efb425e002f146a39ca0a4f2924566762d9213bd33f825fad83977fba7f, sighash=c980a90108fc424b92ab0ed0d9d889ebe59fd664d69720daa011e573d4532475):
result: success
<> POP stack
<> POP stack
<> PUSH stack 01
script | stack
-------------------------------------------------------------------+-------------------------------------------------------------------
| 01
#0003 OP_CHECKSIG
- #0003 OP_CHECKSIG
- 何も起こらない
btcdeb> step
script | stack
-------------------------------------------------------------------+-------------------------------------------------------------------
| 01
#0003 OP_CHECKSIG
btcdeb>
出力がずれているだけなら、まあ大丈夫なのかな・・・?
btcdeb の issue を見ていると新しくしないと発生している問題(issue#154)もあるようだ。
ただ仕事が忙しいと書いてあるのでなかなか手が回らないのだろう。
おわりに
今回は --txin
だけだったので、もう少しスクリプトをデバッグしているような感じで試してみねば。