SeedSignerをいじってみる(2) - MicroSDからPSBTファイルを読み込んで署名する
SeedSignerをいじってみる(2) - MicroSDからPSBTファイルを読み込んで署名する
はじめに
前回はSeedSignerのメニュー色をカスタマイズしてみましたが、今回はもう少し実用的な機能を追加してみました。
今回追加した機能:
- MicroSDカードからPSBTファイルを読み込む機能
- 署名済みPSBTファイルをMicroSDカードに自動保存する機能
「カメラモジュールの接続部分を壊しちゃった...MicroSDカードから直接読み込めたら便利なのに」そんな思いから始まったカスタマイズです。
変更点は、UIとファイルの読み書き処理の追加のみになります。
トランザクションの表示・確認・署名処理には一切手を加えていません。
既存のSeedSignerのセキュリティモデルとPSBT処理ロジックはそのまま維持されています。
⚠️ 注意事項
- この記事は開発・学習目的です
- 実際の資金を扱う際は公式リリース版を使用してください
PSBTとは?
PSBT(Partially Signed Bitcoin Transaction) は、ビットコインの部分署名トランザクション形式です。
従来の流れ:
- ウォレットアプリでPSBTを作成
- QRコードで表示
- SeedSignerのカメラで読み取り
- トランザクション内容を表示・確認して署名
- 署名後のデータをQRコードで表示
- ウォレットアプリで読み取り
今回追加した流れ(太字部分):
- ウォレットアプリでPSBTを作成
- MicroSDカードにコピー ✨
- SeedSignerで直接読み込み ✨
- トランザクション内容を表示・確認して署名
- 署名済みファイルをMicroSDカードに自動保存 ✨
- ウォレットアプリで読み込み
作業の流れ
大きく3つのステップに分かれます:
- 要件分析: どんな機能が必要か考える
- 実装: ソースコードを編集して機能追加
- テスト: 実際にPSBTファイルで動作確認
Step 1: 機能要件の整理
🎯 実現したいこと
- メインメニューに「Load PSBT from SD」ボタンを追加
- MicroSDカード内の
.psbt
ファイルを自動検出 - ファイル選択画面を表示
- 選択したPSBTファイルを読み込み
- 署名後、
[元ファイル名]_signed.psbt
として自動保存
🔍 調査:SeedSignerの内部構造
SeedSignerのソースコードを調べて、以下が分かりました:
メニュー関連:
-
src/seedsigner/views/view.py
のMainMenuView
クラスでメニューを管理 - 既存は4ボタン→5ボタンに拡張が必要
PSBT処理関連:
-
src/seedsigner/views/psbt_views.py
でPSBT関連の画面を管理 -
PSBTSignedQRDisplayView
で署名後の処理を実行
Step 2: 実装
📝 メインメニューの拡張
まず、メインメニューに新しいボタンを追加します。
src/seedsigner/views/view.py
の変更:
class MainMenuView(View):
SCAN = ButtonOption("Scan")
LOAD_PSBT = ButtonOption("Load PSBT from SD") # ← 新機能!
SEEDS = ButtonOption("Seeds", SeedSignerIconConstants.SEEDS)
TOOLS = ButtonOption("Tools", SeedSignerIconConstants.TOOLS)
SETTINGS = ButtonOption("Settings", SeedSignerIconConstants.SETTINGS)
ボタンが5個になったので表示方法も変更:
# MainMenuScreen(4ボタン用)から ButtonListScreen(任意数)に変更
selected_menu_num = self.run_screen(
ButtonListScreen, # ← ここを変更
title=_("Home"),
button_data=button_data,
show_back_button=False,
show_power_button=True,
)
🗂️ PSBTファイル読み込み機能の実装
次に、MicroSDカードからPSBTファイルを読み込む新しいクラスを作成:
class PSBTLoadFromSDView(View):
"""MicroSDカードからPSBTファイルを読み込むビュー"""
def run(self):
# 1. マウントポイントを自動検出
possible_paths = [
"/mnt/*", # 手動マウント
"/media/*", # 自動マウント
]
# 2. .psbtファイルを検索
psbt_files = []
for root, dirs, files in os.walk(sd_card_path):
for file in files:
if file.endswith('.psbt'):
psbt_files.append(os.path.join(root, file))
# 3. ファイル選択画面を表示
# 4. 選択されたファイルを読み込み
# 5. PSBTSelectSeedViewに遷移
重要なポイント:
- 複数のマウントポイント(
/mnt/*
,/media/*
)を自動検出 - ファイルが見つからない場合のエラーハンドリング
💾 署名済みファイル自動保存機能
署名完了後に自動保存する機能を PSBTSignedQRDisplayView
に追加:
class PSBTSignedQRDisplayView(View):
def run(self):
# 署名済みPSBTファイルを保存
self._save_signed_psbt()
# 既存のQR表示処理
qr_encoder = UrPsbtQrEncoder(psbt=self.controller.psbt, ...)
self.run_screen(QRDisplayScreen, qr_encoder=qr_encoder)
def _save_signed_psbt(self):
# 1. 元ファイル名から署名済みファイル名を生成
signed_filename = f"{base_name}_signed.psbt"
# 2. 書き込み可能なディレクトリを探す
writable_dirs = [
os.path.dirname(original_file), # 元ファイルと同じ場所
"/mnt/microsd", # 手動マウント
"/media/pi", # USBマウント
"/home/pi", # ホームディレクトリ
"/tmp" # 一時ディレクトリ
]
# 3. ファイルを保存して成功通知
Step 3: 動作テスト
1. MicroSDカードの準備(ファイル交換用のパーティションを作成)
ここでひとつだけ面倒な問題があります。Raspberry Pi OSの実行中にOS起動用のカードを抜き取ってしまうと、ルートフォルダが見えなくなってしまうためLinuxコマンドの実行ができなくなってしまいます。そこで、途中でMicroSDカードを抜かなくても良いように、前もってファイル交換用のパーティションを作成しておくことにします。このパーティションをPCとRaspberry Piの両方から読み書きできるようにFAT32でフォーマットしておくことでPSBTファイルのやりとりが出来るようになります。
ただ、この作業はRaspberry Piとは別のLinuxマシン上で実行する必要があります。(面倒!😭) 私の場合はMac上のUTMという仮想環境を使ってDebianを起動して実行しました。VirtualBoxでも問題ないはずです。
パーティションサイズの変更や新規作成は、基本的にはLinuxのコマンド(resize2fs, parted, mkfs.vfat)で出来るはずですが、なかなか上手く行かなかったので、この記事ではGUIツール(GParted)を使って実行する方法を記載します。
1.1 既存パーティションの縮小(Raspberry Piとは別のLinuxマシン上で実行)
LinuxマシンにMicroSDカードを接続し、以下の手順でパーティションを縮小します。(私の仮想環境の場合はUSBデバイスとして接続する必要があったので、物理的にMicroSD→USB変換アダプタを使う必要がありました。 面倒^2!😭)
Linuxマシン上で、GPartedを起動します。
2番目のパーティション(ext4)の後ろに適当なサイズの空き領域が出来るように縮小します。この例では1GB分縮小しています。
1.2 新しいFAT32パーティションの作成
空いた領域に新しいパーティションを作成します。ファイルシステムにはFAT32を選択します。
チェックマークのボタンを押してパーティションの変更を書込みます。
3つ目のパーティションがFAT32で作成されていればOKです。
1.3 パーティションの自動マウント設定(Raspberry Pi上で実行)
MicroSDカードをRaspberry Piに差し替えて、Raspberry Piを起動します。
Raspberry Piで新しいパーティションを自動マウントするように設定します:
# マウントポイントを作成
sudo mkdir -p /mnt/data
# デバイスのUUIDを確認
sudo blkid /dev/mmcblk0p3
# /etc/fstabに追加(XXXX-XXXXは上で表示されたUUID)
echo "UUID=XXXX-XXXX /mnt/data vfat uid=1000,gid=1000,umask=0022 0 0" | sudo tee -a /etc/fstab
sudo mount -a
ここまで出来たらファイル交換用のパーティション作成は完了です。(お疲れさまでした。😅)
Raspberry Piの電源をいったん切って、MicroSDカードを抜き取ってPCに接続します。
2. PSBTファイルの配置(PC上で実行)
Sparrowなどのビットコインウォレットアプリを使って、PSBTファイルをMicroSDカード上のファイル交換用パーティション内に保存します。
3. カスタマイズしたSeedSignerのソースコードを取得(Raspberry Pi上で実行)
MicroSDカードをPCからRaspberry Piに差し替えて、Raspberry Piの電源を入れます。
起動したらsshで接続して下のコマンドでSeedSignerのソースコードをカスタマイズ後のバージョンに更新します。
cd ~/seedsigner
git pull
4. SeedSignerを起動
cd ~/seedsigner/src
python3 main.py
- メインメニューに「Load PSBT from SD」が表示される ✅
起動後のホーム画面が、いつもの4つのボタンが上下左右に並んだものではなく、縦に5つのボタンが並んだものに変わっていることに注目。2つ目の「Load PSBT from SD」が今回追加したメニューです。
5. MicroSDカードからPSBTファイルを読み込む
- 「Load PSBT from SD」を押すとPSBTファイルの一覧が表示される ✅
処理したいPSBTファイルを選択すると次の画面に移ります。
6. シードを入力する
ここから先は従来通りの動作になります。
起動後一度も入力していない場合は、シードを入力するための画面が表示されます。カメラでSeedQRをスキャンするか、手動で12単語を入力します。私の場合はカメラモジュールを取り外してしまっているので手動で入力しました。SeedSignerのシード入力画面はなかなか使いやすく、慣れれば12単語なら1分で入力できます。😎
7. トランザクションの内容を確認する
- 選択したPSBTファイルが読み込まれ、QRコードをカメラでスキャンした時と同じ画面が表示される ✅
このあたりの流れは何も変わっていません。
8. 署名する
- 署名完了後、
[元のファイル名]_signed.psbt
がMicroSDカードに自動保存される ✅ - 成功画面でファイル名と保存場所が表示される ✅
- 署名されたデータのQRコードも従来通り表示される ✅
あとは、MicroSDカードをPCに差し替えてSparrowなどのウォレットアプリで読み込み、トランザクションをブロードキャストするだけです。
実際に使ってみた感想
🎯 今回の成果
- 実用性向上: カメラが壊れていても大丈夫。😊
- 自動化: 署名済みファイルの手動保存が不要。そのままMicroSDカードに保存される。
カスタマイズ後のソースコードはこちらに公開しています。
⚠️ 実用時の注意
この機能追加はあくまで学習・開発目的です。 実際にビットコインを扱う際は、公式リリース版を使用することをおすすめします。
🤝 おわりに
オープンソースプロジェクトの素晴らしいところは、「あったらいいな」と思った機能を自分で実装できることです。
この記事が、SeedSignerを使っている方やハードウェアウォレット開発に興味がある方の参考になれば幸いです。
Happy Hacking! 🎉
P.S.
最後まで読んでくださりありがとうございます。
この記事はClaude Code 6割、人間 4割の共同作業で書きました。
Pythonのソースコードについては、実は私自身はほぼ書いていません。作業内容を指示 → Claude Codeが実装 → エラーメッセージをコピペ。 → Claude Codeが修正 → 次の作業内容を指示、というループを10数回繰り返して、ちゃんと動く状態になりました。
それぞれの作業単位で、オリジナルに対して行ったカスタマイゼーションの内容を整理して CUSTOMIZED.md というファイルに記録させました。AIにブログ記事を書かせるさいにはこのような記録を参照するように指示すると上手く行くようです。
Discussion