ブロックチェーンとは:
汎用分散データベース
変更履歴集積としてのデータベース (like 銀行通帳, Git)
ブロックチェーン:
\[\mathtt{∅} \stackrel{B_{1}}→ S_{1} \stackrel{B_{2}}→ S_{2} \stackrel{B_{3}}→ S_{3} \stackrel{B_{4}}→ S_{4} \stackrel{B_{5}}→ S_{5} \stackrel{B_{6}}→ \cdots\]
複数のデータベースノードが状態のレプリカを持つ:
衝突をどう解消するか?
チェーンが分岐する。どちらを選ぶか:
\(↗︎\stackrel{B_{n+1}}→ S_{n+1} \stackrel{B_{n+2}}→ S_{n+2} \stackrel{B_{n+3}}→ S_{n+3}\)
\(.. \stackrel{B_{n-1}}→ S_{n-1} \stackrel{B_{n}}→ S_{n}\)
\(↘︎\underset{B'_{n+1}}→ S'_{n+1} \underset{B'_{n+2}}→ S'_{n+2} \underset{B'_{n+3}}→ S'_{n+3}\)
ノード間の衝突を解決するアルゴリズム。
完璧なアルゴリズムは存在しない[FLP85]が、
Paxos や Raft など実用上問題ないアルゴリズムがある。
誰もがノードを立て参加できる
パーミッションレスな分散DBネットワーク:
シビル攻撃
閉じたネットワークでの合意形成アルゴリズムは動作しない。
オープン・ネットワークではアカウントをいくらでも作れる。 票数水増しにより合意形成の操作と妨害ができてしまう。
シビル攻撃(票数水増し)を不可能にする難しくする:
換金性のあるトークン → 暗号通貨の誕生
暗号通貨は非中央集権分散DBのシビル攻撃への解
汎用DBだからプログラムを置くこともできる
契約の自動執行が可能 (Non native tokens, 分散型交換所(DEX), etc)
金銭的価値の貯蔵手段となったブロックチェーン。
バグ、セキュリティーホールは価値の喪失や窃取につながる。
ハッキングによる窃取が発生した場合、被害回復は非常に難しい:
バグの無い事が非常に求められる。テストだけでは不十分
投資銀行などでもバグは大きな金銭的損失を引き起こす。
が、一回り昔、自分の周辺では形式検証が使われているという話はなかった。(個人の感想です)
価値を扱う OSS は攻撃者の格好の標的。
テストでは不十分で、形式検証でバグを極力なくすべき。
とはいえ、形式検証が大いに使われているわけでもなく、
毎年多額の被害が発生している†
弊社にとって別の意味で大変です😩
開発速度と安全性のバランスから OCaml を選択
分散環境での合意形成に使われる、複製できない「投票権」として 計算資源(Proof of Work)ではなく、ステーク(チェーン上に保有するトークン量)を使用。
計算資源を浪費しないのでエネルギー効率が良い:
プロトコルのアップグレード案をチェーン上の投票で承認する†
ステークホルダが理解できない機能は否決される。
約3ヶ月に一度のプロトコルアップグレード。忙しい。
メリハリが大切: 形式検証するべき vs テストで済ますべき
検証活動が一番盛んだと思われる
ハックしやすく、検証しやすい
言語自体を安全に、検証しやすく:
option
, result
(Either
)list
, set
, map
LOOP
)Michelson の Coq モデル。
LOOP
によって停止しない事を避けるため、評価器に 再帰呼び出し上限 fuel
を設定。例: boomerang
Michelson + 篩型
詳しくは、この後の
を。
内部は純粋関数型
副作用バリバリの「普通の」プログラム (ex. Python) から Michelson へのコンパイルは難しい…
コントラクトの不変条件や事後条件を記述できる†
トークン実装での条件例:
# トータル発行量は変化しない:
specification {
s1: ledger.sum(tokens) = totalsupply;
}
#自分自身に送金する場合、状態は変わらない
postcondition transfer_p3 {
%from = %to -> ledger = before.ledger
}
これらの証明すべき条件を Why3を通して抽出し、 自動証明や証明支援系で証明する。
Coq でスマートコントラクトを書いて、Michelson に持っていく
Contract interaction テストが可能
Mechanized verification of the LIGO compiler
さすがに時間がかかりそう…
(形式検証による正しさ証明とは比べるべくもないが、
コンパイラ実装が間違っていると出力 Michelson の型エラーとして現れることが多い。 その点は楽。)
いろいろ道具立てはある。
これからは contract interaction
NaCl互換の暗号ライブラリ。F\(*\)で安全性が検証されている:
F\(*\) のサブセット Low\(*\) で書かれている。 KreMLin を使って C にコンパイル。
ブロックチェーン状態ためのファイルシステム
Merkle Patricia Tree を利用
実装が間違っていると、ブロックチェーン状態がおかしくなる!!
このままでは各ノードのディスク上のデータ幅が違いすぎる
最適化: Internal を Branch と Extender に分け、幅をそろえる
最適化のため不変条件が複雑化
OCaml で書かれた木の操作が不変条件を保存する事を F\(*\) で証明(論文)。
初期の Plebeia Merkle hash 計算:
Hash consing のランダムテストでデータが壊れた:
H(Extender(\(l\), File(\(v\))))
= H(Extender(\(l\), Directory(Extender(\(l\), File(\(v\))))))
修正版:
修正版の正しさを Coq で証明:
Tezos のプロトコルコードの正しさを証明していくプロジェクト
OCaml コードを Coq コードに変換する coq-of-ocaml を使用。
Nakamoto consensus に基づくアルゴリズム。
確率的 finality: ブロックが作られても後で別のブランチに覆される可能性がある(確率は指数関数的に減るが)。
\(↗︎\stackrel{B_{n+1}}→ S_{n+1}\) 😢
\(.. \stackrel{B_{n-1}}→ S_{n-1} \stackrel{B_{n}}→ S_{n}\)
\(↘︎\underset{B'_{n+1}}→ S'_{n+1} \underset{B'_{n+2}}→ S'_{n+2} \underset{B'_{n+3}}→ S'_{n+3}\)
BFT consensus に基づく合意アルゴリズム(3/18ころ切替)
確定的 finality: 一度ブロックがチェーンに付け加えられると覆されることはない。
Tenderbake には正しさの手証明はある。 機械証明に向けて TLA+ を使ったモデル化がされている。
TLA+ を使い、Tezos ネットワークに参加したばかりのノードが正しく現在のネットワークのブロックチェーン状態に追いつくことの検証も行っている。
カバーしていない検証事例がまだあります:
をご覧ください
ブロックチェーンは非中央集権オープンネットワークDB
動作のため金銭的価値のあるトークンを扱う宿命
OSSで価値を扱うため形式検証してバグを無くしたい
Tezos では全レイヤで形式検証を頑張っている