Develop with pleasure!

福岡でCloudとかBlockchainとか。

USDTを使ってBitcoin Coreをトレース

Bitcoin Coreでは、User-space Statically Defined Tracing(USDT、※Tetherではない)ベースのトレースポイントが提供されており、Linux環境で動作するBitcoin Coreでは、このトレースポイントを使って、内部のデータにアクセスできるようになっている。

Bitcoin Coreのトレースポイント

Bitcoin Coreには、v23.0の時点で以下のトレースポイントが組み込まれている。

参考:https://github.com/bitcoin/bitcoin/blob/master/doc/tracing.md

トレースポイント 内容
net:inbound_message P2Pネットワーク上のピアからメッセージを受信した際に呼び出される
net:outbound_message P2Pネットワーク上でピアにメッセージを送信する際に呼び出される
validation:block_connected ブロックがチェーンに接続された後に呼び出される
utxocache:flush インメモリのUTXOキャッシュがフラッシュされた後に呼び出される
utxocache:add UTXOキャッシュにコインが追加された際に呼び出される
utxocache:spent UTXOキャッシュからコインが使用された際に呼び出される
utxocache:uncache UTXOキャッシュから意図的にアンロードされ際に呼び出される
coin_selection:selected_coins SelectCoinsが完了すると呼び出される
coin_selection:normal_create_tx_internal 最初のCreateTransactionInternalが完了した際に呼び出される
coin_selection:attempting_aps_create_tx CreateTransactionInternalが楽観的なAvoid Partial Spendsの選択試行のために2回目に呼び出された際に呼び出される
coin_selection:aps_create_tx_internal Avoid Partial Spendが有効になっている2回目のCreateTransactionInternalが完了すると呼び出される

各トレースポイントで取得可能なデータについては↑のドキュメント参照。

トーレス

実際に、上記のトレースポイントに対してトレースしてみる。Bitcoin Coreではリポジトリcontrib/tracingにトレースのサンプルが用意されてる。

bpftraceを使ったトレース

最初は、bpftraceを使ったトレース。

bpftraceをまだインストールしていない場合はインストールから↓(Ubuntu

$ sudo apt-get install bpftrace

P2Pのネットワークメッセージの情報を出力するbpftraceのスクリプトが用意されてるので実行してみる。リポジトリのルートから以下のコマンドを実行↓

$ sudo bpftrace contrib/tracing/log_p2p_traffic.bt
Attaching 3 probes...
Logging P2P traffic
outbound 'inv' msg to peer 0 (outbound-full-relay, 73.166.84.222:8333) with 2 bytes
inbound 'inv' msg from peer 0 (outbound-full-relay, 159.100.255.18:8333) with 1 bytes
outbound 'getdata' msg to peer 0 (outbound-full-relay, 159.100.255.18:8333) with 2 bytes
inbound 'inv' msg from peer 0 (outbound-full-relay, 94.231.253.18:8333) with 1 bytes
outbound 'addrv2' msg to peer 0 (outbound-full-relay, 104.36.175.37:8333) with 2 bytes
inbound 'tx' msg from peer 0 (outbound-full-relay, 159.100.255.18:8333) with 1 bytes
inbound 'inv' msg from peer 0 (outbound-full-relay, 65.21.122.162:8333) with 1 bytes
inbound 'inv' msg from peer 0 (outbound-full-relay, 128.0.51.17:8333) with 1 bytes
...

と、net:inbound_messagenet:outbound_messageの2つのトレースポイントをフックして、データを出力できる。

log_p2p_traffic.btに実行中のbitcoindのパスを記載する必要があり、ローカルでビルドしたものではない場合、適宜パスを修正する必要がある。

pythonでのトレース

サンプルとして、Pythonのスクリプトもある。こちらは、事前に↓のインストールが必要

$ sudo apt-get install python3-bpfcc 

そして、p2p_monitor.pyを実行すると、

$ sudo python3 contrib/tracing/p2p_monitor.py <実行中のbitcoindのパス>

ターミナルにP2Pメッセージのやりとりが表示される↓

Pythonの方は、BCC(BPF Compiler Collection)を使ってeBPF用のバイトコードコンパイルしていて、eBPFのコードはPythonのコード内にCで書く必要がある。bpftraceの方は、独自のDSLを記述する形なので、DSLの仕様さえ学習すればこっちの方がカジュアルに使えそう。