Bitcoin 用 Protocol Buffers
別の場所で、bitcoin に protocol buffers を使うことについて議論が続いてきた。利点をまとめると以下の通りだ:
-> エンコードが小さい -> 非常に高速 -> 多数の言語で実装が存在する (新しいクライアントを書くのが格段に楽になる) -> 前方互換性がある (これこそが protocol buffers の眼目だ) -> コード上で極めてシンプルに使える
最初の段階としては、ウォレットファイルを protocol buffers で保存することを提案したい。これは破壊的変更ではなく、しかも他のプログラムからウォレットファイルを解析しやすくなる。最終的には、ネットワーク通信にも bitcoin が protocol buffers を採用することを期待したい。
protocol buffers は手書きのパケット形式より大きくなるかもしれない、と指摘する人もいる。私は逆で、protocol buffers が用いる巧妙なエンコードのおかげで実際にはより小さくなると見ている。これを決着させるには検証が必要だ。protocol buffers でウォレットファイル/ネットワークパケットをエンコードし、現行方式でのパケットサイズと比較してみる。ただし、パケットの中身、何のデータが、どんな形式で格納されているのかを私はまだ把握していない。
参考までに、パケットを 60 バイト未満にするのは無意味だ——Ethernet パケットの最小サイズが 60 バイトだからだ。パケットがそれより小さい場合、60 バイトまでパディングされる。
[Deleted] Quote from: martin on July 30, 2010, 11:37:59 AM
martinの投稿(2010年7月29日 23:29 UTC)エンコードされたprotocol bufferはわずか55バイトだが、bitcoinバージョンは85個の0x00セット(それぞれ2バイトを表すと仮定)だ。つまり、私の設計の悪いprotocol bufferでも手作りのレイアウトの半分以上のサイズだ!
“0x00”グループはそれぞれ 1 バイトを表す。標準バージョンパケットの長さはヘッダー 20 バイトに加えて 87 バイトだ。ヘッダーも大幅に最適化できるだろう:
message start "magic bytes" - 0xF9 0xBE 0xB4 0xD9
command - name of command, 0 padded to 12 bytes "version\0\0\0\0\0"
size - 4 byte int
checksum (absent for messages without data and version messages) - 4 bytes
Obviously using proto buffers here, while absolutely a breaking change, would save a fair bit of space, especially because the "I've created a transaction" packet has the name "tx" meaning that there's at least 10 bytes of overhead in every one of those packets. なぜ破壊的変更だと考えるのか?最初に新しいプロトコルで試して、次に古い bitcoin シリアライゼーション方式でリトライすることは十分可能だろう。また、BitCoin コミュニティがまだ小さいうちに、早めに行うべき変更だと思う。これは新しいクライアント作成の大きな障壁であり、遅らせれば bitcoin の普及を妨げることになる。
Protocol Buffers や boost シリアライゼーションを使わなかった理由は、完全に気密でセキュアにするには複雑すぎるように見えたからだ。コードが大きすぎて、予期しないことを行うような入力を形成する方法がないと確認できるほど読み通せない。
車輪の再発明は嫌いだし、自分でシリアライゼーションルーチンを書くことにしたのは不本意だった。現在のシリアライゼーション形式は可能な限りシンプルでフラットだ。入力ストリームの形成方法に余分な自由度はない。各ポイントで、データ構造の次のフィールドが期待される。与えられる選択肢は受信者が期待しているもののみだ。アップグレードが可能なようにバージョニングがある。
CAddress は、かなりの予約スペースを持つ数少ないオブジェクトだ。(フラグ用に約 7 バイト、将来の IPv6 拡張の可能性のために 12 バイト)
ブロックやトランザクションのような大きなものは、サイズに関してこれ以上あまり最適化できない。データの大部分はハッシュ、鍵、署名であり、これらは圧縮不可能だ。シリアライゼーションのオーバーヘッドは非常に小さく、通常サイズフィールドに 1 バイトだ。
ギャビンの P2P ブロードキャストインフラの既存のものを使うというアイデアについてだが、存在しないと思う。ブロードキャストのみを必要とする P2P システムはほとんどない。分散ハッシュテーブルインフラを提供しようとする Chord のようなライブラリがあるが、それは私たちが必要としない、また望まない非常に大きくて困難な問題だ。それらのライブラリは、私たち自身のものよりもインストールがはるかに難しい。
Protocol Buffers や boost シリアライゼーションを使わなかった理由は、完全に気密でセキュアにするには複雑すぎるように見えたからだ。コードが大きすぎて、予期しないことを行うような入力を形成する方法がないと確認できるほど読み通せない。
失礼な言い方になるかもしれないが、それはトランザクションの SCRIPT フィールドの危険性と同じことに聞こえる。ブロックがクライアントに操作を示すような評価言語まるごとを書くことには抵抗がないのに、protocol buffers のようなライブラリを使うことには抵抗がある、というのは?
ウォレットファイルをカスタム形式の代わりに protocol buffer 形式で出力するオプションを含めることを検討してもらえないか? そうすればデフォルトはあなたがより信頼するカスタム形式のままで、ユーザーは新しいクライアントへ移行したい場合に自分のウォレットを protobuf 形式へエクスポートできる。
— martin
そのケースならなぜ XML を使わない? エクスポートに関して言えば、ディスク上のウォレットファイルのサイズはそれほど大きな問題ではないし、XML はかなり良く圧縮できる。おまけに完全に人間が読める形式だ ― 実際に何が保存されているのかを理解する助けになるだろう。
確かに、だがversionパケットは送られるすべてのパケットの中でおそらく一番小さいものなので、ほかで得られる利点の方が大きい。それと、本題を見失わないでほしい。Protocol Buffersの方がサイズが小さいというのは、forwards compatibleであり、bitcoinを言語間で移植可能にする、という事実に対する副次的な利点だ。
カスタムでないフォーマットはデバッグもしやすい。自分一人が使っているわけではなく、別のプロジェクトにいる大勢の人間がバグを探し、修正してくれる。パケットをデコード・表示するツールも手に入ることが多く、何か問題があったときに気づきやすくなる。個人的にはパケットサイズは最も重要度の低い理由だと思う。