BlueWalletというLightning Networkに対応したビットコインウォレットをご存じでしょうか。
見た目がよく、結構安定しているということで人気なウォレットです。
今回は、このBlueWalletのソースコードを解析することで、設計思想やどの程度手堅い作りをしているか、ということに迫ってみたいと思います。
全体像
BlueWalletのソースコードはGitHubにてMITライセンスの下に公開されています。
https://github.com/BlueWallet/BlueWallet/
MITライセンスというのは平たく言うと、ソースコードを再利用していいよ、ただしコピーライトはちゃんと明記してね、というライセンスです。商用利用も問題なく、勝手が良いため現在オープンソースプロジェクトを公開する際によく利用されています。
GitHubで公開されているプロジェクトの場合、Insightsというページを開くとどの程度開発が活発かが分かります。
さて、BlueWalletのGitHubにてトップページやInsightsを覗いてみる(添付図)と、ぱっと見で以下の事がわかります。

- 開発がとても活発(7月10日〜17日だけでも5人によって数十ものコミットが当てられている)
- 中の人以外も開発に参加するコミュニティが育っている(Contributersが65人いる)
- 開発項目がチケット化されBacklogにて管理されており、どう開発に参加すればよいか分かりやすい
アプリのアップデートが速いなあ、とは思っていましたがこんなところにも秘密がありそうです。
さて、実際にソースコードの中身に目を向けてみると、
- ReactNativeというHTML, Javascriptベースな開発基盤を採用している
- bitcoinjs-libなど、業界のオープンソースなライブラリをがっつり利用している
- 乱数生成器、データ記録方式などセキュリティ的に気になるところは手堅く手を打っている
といったところが分かりました。
うまくエコシステムに乗っかり、自分達の開発すべきものを絞っている印象です。
データの記録方法について
最初はカストディアルなLightning Networkによる支払い機能搭載ウォレットとして始まったBlueWalletでしたが、最近ではマルチシグだったり、ハードウェアウォレット対応だったりと色々と機能が増えています。
こういった息の長いアプリになると、バージョンアップをする過程で保管するデータ構造がどんどん変化してきたはずで、その保存方法が気になります。このへんの恨み辛みを調査すべく、ちょっと潜ってみました。
とりあえず、"storage"とかそれっぽい単語でGitHub内を検索してみると、以下のようなトピックを見つけました。
https://github.com/BlueWallet/BlueWallet/pull/1545
どうやら、2020年夏頃にRealmというデータベースエンジンへの乗り換えをしたようです。JavaScriptなエンジンベースからネイティブコードベースなエンジンに処理をオフロードすることを意図しているようです。
既存の保存方法では読み込みスピードが課題になっていたようですね。BlueWalletの場合、トランザクジョンデータをウォレット内にキャッシュする設計思想なようです。この場合、UTXOベースなビットコインですとアプリ内に保存すべきデータがどんどん膨らむことになります。
Realmは、データ構造に統一感を持たせ、いわゆる正規化されたデータを保管すると最大限の性能を発揮できます。ですが、BlueWalletの場合、トランザクジョンデータをアプリ内に保管しているのですが、その構造がtree-likeでちょっと特殊だったようで、せっかくのRealmの機能を最大限使うことはできてないよ、とコメントされていました。それでもデータベースを乗り換えたことで十分速くなったようでよかったですね。
ところがです。Realmは32MBを超えるデータが保存できない、という問題につい最近出くわしたようで、ちょっと大変そうです。
https://github.com/BlueWallet/BlueWallet/issues/3357
とりあえずは巨大データは分割して保存するようにすればよいのですが、データ構造を変えるとなると、頭の痛くなる問題もでてきます。
アプリのバージョンアップの際にマイグレーション(データ構造を変換する作業)を行う必要があるのですが、ここを間違えるとデータが吹っ飛びます。ウォレットの場合、ユーザー資産に直結するものであるため、より慎重にやらないといけません。
ノンカストディアルウォレットを唄う場合、ユーザーのスマートフォンにデータを保管することになりますが、ユーザーがアプリを常に最新版にしてくれているとは限りません。どのバージョン時点のデータ構造からマイグレーションしなきゃならないのか、など考えると辛みがでてきますね。
セキュリティについて
ウォレットにまつわるセキュリティには色々な目線で考えるべき事がありますが、ここでは"乱数"にフォーカスを絞ってBlueWalletを調査してみようと思います。
ビットコインのアドレスって、ぱっと見だと規則性もなくランダムな印象かと思います。実際、ビットコインで署名に使う秘密鍵は乱数を元に作成されています。そして、その秘密鍵と紐付く形で公開鍵、アドレスがつくられます。結果として、アドレスはランダムな文字列になっています。
ウォレットをセットアップする際に24単語をバックアップとしてメモられているかと思いますが、あれは0,1のランダムな数字の羅列、例えば0010111101...といったものを512個分繋げた乱数値(2進数表現という数字の表記法の1つになります)を、人間が扱いやすいよう単語に変換したものになります。
ノンカストディアルウォレットの場合、この乱数値として規則性がないものを利用する必要があります。さもないと、世界中の誰かとアドレスが被ってしまい、勝手にウォレットが共有されることになります。恐ろしいですね。
さて、こうした規則性のない乱数のことを専門用語で真性乱数といいます。どうやって作るかというとスマートフォン自体の持つ熱だったり、加速度センサーなど各種センサーから得られる情報だったりをごちゃまぜにして数字に変換することで得たりします。iPhoneなどではデバイス側でこの機能を提供しており、開発者は各アプリにて簡単に真性乱数を用いる事ができるようなっています。
ですが、この乱数はつくるのがとても遅いという問題があり、普通にスマートフォンアプリを作ると、真性乱数ではなく規則性のある数字(専門用語で擬似乱数といいます)を乱数として無意識に利用していることが多いです。こっちのほうが圧倒的に得られる速度が速くて使い勝手がよく、プラットフォームによってはデフォルトで提供されるものが擬似乱数だったりするためです。
さて、前置きが長くなりました。BlueWalletですが、ソースコードを覗いてみると、ちゃんと真性乱数を生成する専用のライブラリを組み込んでいました。しっかり、ソースコードにコメントも残してあり、手堅いですね。
https://github.com/.../fc11da2aae920b3b27.../class/rng.js...
まとめ
今回はBlueWalletのソースコードを覗いてみたところ、
- うまくエコシステムに乗っかり、自分達の開発すべきものを絞っている印象
- ビットコインUTXOモデルのデータの大きさに苦労している様子
- 乱数まわりはしっかり手堅く実装している
といったことがわかりました。
さて、そんな彼らの動向ですが、今はハードウェアウォレットと連携したLightning Network支払いソリューションを開発中とTwitterに投稿しています。
https://twitter.com/bluewal.../status/1414908931902779394...
これも、Square社のLightning Development Kitを利用しているようで、エコシステムを乗りこなしつつ新しいことをテンポ良く手がける彼らの動向にはこれからも注目していこうと思います。