btc: Output Descriptors (3)
2025/03/01
はじめに
もう少し Output Descriptors を扱おう。
libwally-core
多少は Output Descriptors の知識を得られたので、何か作ってみよう。
C言語で libwally-core の API を使って実装する。
Descriptor Functions はある。
ためしに BDK のサンプルにあった Descriptors のデータを与えてみたのだが wally_descriptor_parse()
でエラーになった。
libwally-core の commit 履歴を見たところ、descriptor で tr()
をサポートしたのが 2025年1月 で v1.3.1 よりも後だ。
ならばと 2025年3月1日時点の master
ブランチをビルドしたところコンパイルエラーになった。
Elements 対応で追加されたコードがマクロで囲まれていないためか私の Elements 無しビルドだとエラーになるようなのだ。
まだラベルなどもないので descriptor に関する commit がある程度落ち着いたような感じがするところで checkout すると成功した。
README に書いているが、中途半端なところをチェックアウトした。
まあ、タグも何もないから仕方ないのだが。
libsecp256k1 はシステムにインストールしたものを使っているが、
これは MuSig2 のサンプルを作ったときに v1.3.1 の submodule になっている libsecp256k1-zkp では MuSig2 が有効になっていなかったためだ。
今回の目的ではどちらでもよいと思う。
実装はまだ wally_descriptor_parse()
を呼び出しているだけだ。
サポートしていないとこれでエラーになるのである。
アドレス取得
BDK のサンプルコードと同じことができれば良いと思っていたが、
あちらは Esplora API を使ってブロックチェーンからデータ取得をしているのだった。
libwally-core にはそういう機能は無いので、アドレスをいくつか取得して BDK サンプルと一致することを確認しよう。
libwally-core の descriptor functions は Output Descriptors もあるが miniscript サポートという意味合いもある。
Output Descriptors 自体が miniscript 由来だったっけ?
よく覚えていないが、ともかく libwally-core は descriptors も miniscript も処理できているようになっているそうだ。
- Miniscript
- Miniscript: Streamlined Bitcoin Scripting - by Blockstream - Blockstream Engineering Blog - Medium
BDK のサンプルコードだけではアドレスがあまり出力されないので、他にも出力させるようにした。
“Mutinynet” という知らないネットワークとは言え、系列は Bitcoin testnet なのであまり深く考えずに libwally-core でも使えそうだ。
サンプルでは HD wallet の external / change の両方をスキャンしているので、 その 1つ下のインデックスでアドレスを取得する。
Syncing wallet...
Wallet balance: 99845 sat
Generated external address tb1pzvynlely05x82u40cts3znctmvyskue74xa5zwy0t5ueuv92726s0cz8g8 at index 2
ex 0: tb1pkar3gerekw8f9gef9vn9xz0qypytgacp9wa5saelpksdgct33qdqs257jl
ex 1: tb1pv537m7m6w0gdrcdn3mqqdpgrk3j400yrdrjwf5c9whyl2f8f4p6qg5eh2l
Generated internal address tb1pqrhlqudwf49pye0777n6e3jsfvjq4xtznua479c93e6wrtcfkeqskr27ja at index 1
in 0: tb1pr2xjacaxx5jeqmc44j0vv49j2ylh93hrxraklttry4xh7u932xns6rqysu
unused addresses
ex 2: tb1pzvynlely05x82u40cts3znctmvyskue74xa5zwy0t5ueuv92726s0cz8g8
in 1: tb1pqrhlqudwf49pye0777n6e3jsfvjq4xtznua479c93e6wrtcfkeqskr27ja
external が 0-2、change(internal) が 0-1 のインデックスでアドレスを作っている。
さあ、やってみよう!
$ ./tst
output[ex 0]: tb1pkar3gerekw8f9gef9vn9xz0qypytgacp9wa5saelpksdgct33qdqs257jl
output[ex 1]: tb1pv537m7m6w0gdrcdn3mqqdpgrk3j400yrdrjwf5c9whyl2f8f4p6qg5eh2l
output[ex 2]: tb1pzvynlely05x82u40cts3znctmvyskue74xa5zwy0t5ueuv92726s0cz8g8
output[in 0]: tb1pr2xjacaxx5jeqmc44j0vv49j2ylh93hrxraklttry4xh7u932xns6rqysu
output[in 1]: tb1pqrhlqudwf49pye0777n6e3jsfvjq4xtznua479c93e6wrtcfkeqskr27ja
ex / in とインデックス値の組み合わせで出力されたアドレス文字列は一致している。
なので、このやりかたでよいのだろう。
おわりに
libwally-core で、HD wallet をニモニックではなく descriptors の書式で作ることができたと思う。
もう少し調べるべきかな。