ダウンロード
メニューを閉じる -

ユニトライによるオンチェーンスケーラビリティの向上を目指して

RSK は2015年に、イーサリアムに対応した Bitcoin サイドチェーンとして誕生しました。2016年を振り返ると、RSK サイドチェーンがまだ開発段階にあった時期に、当社はイーサリアムの主要コンポーネントの一つであるアカウントトライ(イーサリアムのイエローペーパーでは「ワールドステート」トライとも呼ばれる)を置き換えることで、デザインの向上と簡易化を図ることにしました。ワールドステートトライとは、イーサリアムのようなブロックチェーン内の主要データベースであり、その補助データ構造は「安全な改良版パトリシアトライ」と呼ばれています。当社は置換ステートデータ構造を設計しました。これは今ではユニトライと呼ばれるものへと進化しています。

laBitConf にてユニトライを発表している Sergio Lerner氏(RSK Labs)(2016年)

 

(オリジナルの)ユニトライの主な特性の一部を以下に示します。

  1. 16進基数木が2進(バイナリ)基数木に置き換えられます。
  2. 任意長値をストレージセルに保存できます。
  3. すべてのトライを組み合わせ、コントラクトストレージセルをアカウントセルと結合して、「ユニトライ」と呼んでいるより大きな単一データ構造に組み込みます。
  4. リンクが最新アップデートタイムスタンプ(「最新アップデートタイムスタンプ」フィールド)によって増加し、その結果、ユニトライがストレージレントと、ノードの自動ハイバネーションに対応します。
  5. 親ノードのそれぞれの子に対して、接頭辞が親ノードに保存されます。これにより、ハイバネーションによるリーフノードの削除が可能になるので、データ破棄を最大限に生かすことができます。さらに、同時トランザクション処理に対するクロスノードの副作用を防止できます。
  6. トライの不均衡を防止するため、キーは10バイト(80ビット)のハッシュ接頭辞により保護(「prefix secured」)されていますが、現在もハッシュ付き接頭辞の後にフルキー(ハッシュプレイメージ)が含まれています。
  7. ノードにはそのペイロードのサイズが保存されます。
  8. ノードには、サブツリーによって消費されるバイト数が保存されます。
  9. ノードが小さすぎてデータベースへの独立保存には適していない場合、そのノードを親ノードに埋め込みます。これにより、32バイトのハッシュダイジェストをこのノードの参照に使用できます。

 

ユニトライの利点にはその効果が証明されているものもあれば、すぐには分からないものもあります。以下は主な改善点のリストです。

 

  • 全体的なデザインを簡易化
  • 実装の複雑性を軽減、それによって合意失敗のリスクを軽減
  • Lightweight クライアントのデザインを簡易化
  • ステート同期化の並行化力と悪質なステートプロバイダに対する回復力を強化することで、その処理時間を短縮(別名高速同期/ワープ同期)
  • SPV クライアントと SPV ブリッジに対してよりシンプルな不正防止策を実現
  • よりシンプルなステートガベージ収集を実現
  • ストレージセル別の契約賃貸を実現
  • ストレージセル別のハイバネーションとウェイクアップを実現
  • ストレージセル別コリジョン検出を利用した並行処理を実現
  • コードデータ取り込み不要の高速 EXTCODESIZE クエリーを実現

 

ユニトライのデザインは、RSK Labs が RSK blockchain のために提案したものであり、2016年11月4日と5日に laBitConf で概要が発表されました。しかしながら、その時点ではまだ利用開始になっていなかった RSK メインネットに対して当社が主に優先していたのは、イーサリアム開発ツールとの互換性を高めて維持することであったため、ユニトライの実装の延期を決定し、ユニトライのデータ構造に加えた2つの重要な変更を公開するにとどまりました。その変更とは、16進数ではなく2進数の採用と、任意長値の保管です。2進数の採用により、データベースの完全返還ではなくユニトライの動的変換を実行すれば、将来的なユニトライへの移行を実現できます。これが賢い選択となり、現在はツリー構造全体の高速移行を動的に試験しており、非常に複雑な構造のパーツを保護できています。

 

2017年内に、私たちはイーサリアムフォーラムにおいて Vitalik がイーサリアムに対して同様の変更を提案しているのを見て驚きました。彼は複合ステートツリーの利点も強調していました。このツリーは、トライ統一こそがはるかに優れた総合デザインであるという私たちの第一のテーマに対応していました。

 

Vitalik の複合ステートトライ案(2017年)

来るべき時の到来

2019年1月、RSK blockchain が産声を上げ、100%のアップタイムで1年を締めくくりました。そこで当社は、以下のネットワークアップグレードでのユニトライのデータ構造の採用を推進する取り組みを刷新することにしました。当社は旧来の RSKIP を編集・改良して新しい RSKIP を作り出し、さらにリファレンス実装を作り上げました。この記事は当社の取り組みの一部を示しており、 RSK コミュニティがどのようにしてこの変更案の恩恵を受けるのかを説明しています。RSKIP16をアップデートし、RSKIP107RSKIP108RSKIP109を追加しました。RSKIP107では、ノードを保存時に圧縮する方法について説明しています。RSKIP108では、アカウントアドレスとストレージセルアドレスをトライキーにマッピングする方法について説明しています。RSKIP109では、短いストレージアドレスの使用を奨励するためのストレージセル書き込みコストを再定義します。さらに、一度に全部を実装して試験も行い、ステートのアップグレードから同期までで、ノード性能とメモリー消費に著しい向上が見られました。ただし、試験で何もかもがスムーズに進んだわけではありません。例えば、提案内容からトライノードの接頭辞を親ノードに移動させるという案は除外することにしました。新トライと旧トライ間の高速変換はツリー構造の類似点に依存しており、この変更によってその変換が複雑になってしまうためです。

 

ハードフォーク関連のリスクを軽減するためには、変更内容を2回連続のネットワークアップグレードに分けて行うことが最善の戦略であると考えています。最初は2019年第2四半期で、ユニトライ、接頭辞によるキーの保護、ペイロードサイズのキャッシュ、ツリーサイズオンキャッシュ、ディスク上でのノード圧縮が含まれます。2回目は2019年第4四半期で、ストレージレント用の最新アップデートタイムスタンプが含まれます。ストレージレント RSKIP がまだ完成しておらず、また、1回目のネットワークアップグレードではトライの完全移行が必要になりますが、2回目のネットワークアップグレードでの変更がトライノードの新規作成にしか反映されない(トライの移行は不要)ことから、ストレージレント関連機能は延期する予定です。

独自のネットワークアップグレード

アカウントノードとストレージノードの単一ツリーへの完全統合は、ハードフォーク経由でしか実現できません。つまり、大半のマイナーがこの変更に対応するためにアップグレードを実行する必要があり、フルノードも同期状態を維持するためにすべてアップグレードする必要があるということです。しかしユニトライのアップグレードは、プラットフォームエコノミーに関連する変更を一切伴いません。ストレージコストはやや低下しますが、これは実際のストレージコストを課金分にしっかりと合致させた結果です。この課金はコミュニティの当事者全員の利益になります。さらに、この課金がプラットフォームの安全性やプライバシーに影響することはありません。大半の開発ツールとウォレットはワールドステートの内部要素に直接アクセスすることはなく、そのためにこのハードフォークから影響を受けません。

 

アップグレードメカニズムの不都合な点とは、旧来のフルノードのステートデータベースが新たなデータベースとの互換性を持たなくなるということです。旧トライと新トライの両方に対して互換性があるフルノードを作成することは、非常に困難な作業になるにもかかわらずほとんど利点がありません。良いニュースと言えば、パフォーマンス面で多くの改良点があることから、新しい完全同期化にかかる時間は以前の数分の一になることです。さらに、ノードスタートアップ時にステートデータベースを新しいフォーマットに移行して試験を行ったので、ノードによってソフトウェアのアップグレード後のアップタイムをほぼ中断のない状態で維持できました。

 

ユニトライ

 

ユニトライは、アカウント情報に全コントラクトのストレージセルを組み合わせたものです。コントラクトストレージセルを、コントラクトのストレージアドレスに対応するノードにルートされているサブツリーのリーフとして保存します。さらに、コントラクト情報を区切って複数の異なるツリーサブノードにします。以下の簡略図に1つのアカウント(ECDSA 管理)が示されていますが、これには子やコントラクトがなく、コントラクトのコードを保存している子ノードが1つと、実際のストレージセルを含む子サブツリーがあります。

 

ブロックチェーンステートのユニトライのサンプル

 

アカウントとコントラクトストレージの組み合わせでは、キーが違うだけではなく、キーのマッピングも変わります。イーサリアムのアカウントトライがどのように機能するか簡単に振り返ってみましょう。このトライは、アカウントアドレスのハッシュダイジェストをキーとして使用して値を取得することによって、「保護」されます。トライのノードは、アカウントアドレス別ではなくハッシュダイジェスト別に分類されます。このキー変換は、増え続けるキー接頭辞を共有する値を含むデータ構造をばらまいてツリーを長いチェーンにしてしまうというスパム攻撃を防止するために実行されます。この攻撃によって、フルノードによるチェーン参照の実行処理が非常に遅くなる、あるいは特定のトライインクルージョンプルーフのサイズが大きくなるおそれがあります。ユニトライでは、フルプレーンのアカウントアドレスの前にある80ビットのハッシュダイジェスト接頭辞からキーが構築されます。キーをトライに拡散させて確率的な制約の均衡を保つために、80ビットの接頭辞のみを使用します。ツリー再生成攻撃の影響が最小限に抑えられると仮定すると、影響を抑制するには80ビットあれば十分です。このような攻撃に対抗するには、特殊な ASIC ベースのハッシュ接頭辞総当たりハードウェアの設計が必要になります。このハードウェアは、プルーフオブワークのマイナーに酷似しており、このような数百万の「マイニング」ボックスを生み出します。最新の Bitcoin マシンが任意の80ビット接頭辞のプレイメージ検索を実行できると想定すると、攻撃者は80種類の80ビット位置にあるコリジョンを探し出してトライをほんの少し悪化させるために、約600万米ドルの電力を費やす必要があります。さらに、ブロック処理時間に対する影響は(キャッシュにより)ごくわずかで、不均衡なアカウントのインクルージョンプルーフのサイズは、2キロバイトずつしか増加しないと思われます。

 

この新しいマッピングの利点は、アカウントアドレスとストレージセルアドレスがステートに保存されることです。これにより、多くのデータ収集アプリケーションで、ブロックチェーン全体にインデックスを付けないでユーザーに有意義な情報を提供できます。下の図は、アカウントアドレスとストレージアドレスを1つのトライキーに変換する様子を表しています。

 

アカウントアドレスとストレージアドレスのトライキーへの変換

全体像を示すために、データの各タイプをユニトライにマッピングする方法を説明します。

キー 説明
0x00

SHA3(account_addr)[0:9] account_addr

Rlp(ノンス、数量、フラグ) アカウントステート
0x00

SHA3(account_addr)[0:9] account_addr

0x80

バイト配列 アカウントコード
0x00

SHA3(account_addr)[0:9] account_addr

0x00

0x00 ストレージツリーを隔離するためのプレースホルダー
0x00

SHA3(account_addr)[0:9] account_addr

0x00

SHA3(storage_address)[0..9]

trimmed_storage_address

バイト配列 ストレージセルの値

 

最初の0バイトはこのツリーを特別名前空間に保尊するために使用します。これにより、将来の改良においてコリジョンのリスクがない状態で他の名前空間を活用できます。将来行われる可能性のある改良のうち、各自の名前空間を消費する可能性のあるものは以下の通りです。

  • プルーフオブワークのプルーフを有効にするために(NiPowPow)過去のすべてのブロックハッシュのツリー(またはフォレスト)に拡大する特殊ノードと、スキップリストを保存する
  • セキュリティ強化のために、キー長さのバイト数が高い(256バイト)アカウントアドレスを参照する
  • RSKIP32 によって定義されるダブルハッシュアドレスを使用してアカウントアドレスを参照する

RSKIP16 ユニトライとVitalik’s proposal には多くの相違点があります。その1つは、ユニトライでは、ノンスと数量は異なるノードには保存されませんが、一緒に保存されることです。これにはいくつか理由があります。

  • これらの2つのフィールドのシリアル化と逆シリアル化にはほぼ時間がかからないため、さらに細かく分割すると、アカウントステートを回復するために追加されたディスクアクセスによって効率損失が生じます。
  • コントラクトの指定アドレスのデータを取得して、将来的にコントラクトの変更を追跡できるようにすることが推奨されます。
  • アカウントは、トライに「スパム」を仕掛けるために使用される可能性があるため、アカウントによって消費されるスペースを削減することが重要です。

 

ユニトライ RSKIP ランドスケープ

ユニトライは9つの RSKIP(RSK Improvement Proposals(RSK 改善案))により定義されます。各 RSKIP は、ユニトライの特殊要素である構造、ストレージ、キーマッピング、ストレージレント、ハイバネーション、ガスコストを表しています。下の図はこの要素区分を表しています。

ユニトライ関連の RSKIP

 

RSKIP のうち初回のネットワークアップグレードで導入するのは4つのみで、残りはその後のネットワークアップグレードで導入する予定です。そうすることで移行によるリスクを最小限に抑えます。

 

ユニトライから取り残されたもの

 

私たちはユニトライに関する議論の本題の中で、ノードデータの接頭辞を2つの異なるノードに分割すると、触れていないツリーブランチの完全不変性を維持するのに役立ち、さらにツリーアップデートのより精密な並列化を実現できると結論付けました。ノードが接頭辞、データ、ブランチという3つの異なるタイプのうちの1つになり得るため、このスキームを PDB トライを呼んでいました。PDB ツリーへの切り替えには重大な構造変更が必要であるため、これはユニトライ案から切り離しました。ただし、PDB ツリーは詳細な研究のためのトピックになる可能性があります。

ブロックチェーンステートの保存に使用する PDB ツリーのサンプル

 

ここで、RSK ユニトライの各利点をもう少し詳しくご説明します。

短めのメンバーシッププルーフ

16進数トライではなくバイナリトライを使用することで、RSK トライのアカウントに対するメンバーシッププルーフが可能な限り短くなり、さらにはメンバーシッププルーフの確認に必要な時間が最適に近づきます。これにより、Lieghtweight ノードが分散化されてモバイルフォン上での実行が可能になるので、バンド幅と電力の消費量が低下します。下図の例では、ターゲットノード(青い円)の存在を証明するために、16進数トライに30のポイント(ドーナツ)と3つのノード(円)が必要となっています。2進数トライには8つのポイントと8つのノードしか必要ではありません。送信されたノードには親リファレンスの送信が不要である場合、親リファレンスを動的に計算できるため、2進数(バイナリ)トライプルーフには16進数トライのスペースの26%が必要になります。

 

16進数トライと2進数トライにおけるメンバーシッププルーフの比較

アカウントノードの比較によるステートサイズの削減

ユニトライのアカウントでは、「ストレージ」トライルートハッシュダイジェストもコードハッシュダイジェストも保存する必要はありません。つまり、アカウントデータのほぼ60%がステートから削除されるということです。例えば、イーサリアムでは104バイトが消費されますが、1 RBTC を保存するアカウントの消費量は約38バイトです。下の図に示すのは、不要なフィールドを削除した場合に節約できるおおよそのスペースです。

不要フィールドの削除によるアカウントノードの圧縮

 

小ノードの埋め込みによるステートサイズの縮小

サイズが約44バイト未満(未使用の厳密値)の子ノードに対応するために、ユニトライには、これらの子ノードを親ノードに直接埋め込む機能があります。この機能については RSKIP107 で説明しています。 最終的には大半のアカウントに31~41バイトのノードが含まれますが、これは大半のアカウントが親ノードに埋め込まれることを意味します。これによってアカウントのオーバーヘッドが62%削減されます。ノードの埋め込みにより短いアカウント記録と組み合わせることでもたらされるアカウントサイズの縮小率は81%に達します。これによって、同期の所要時間とフルノードのリソース要件が縮小されるだけでなく、アカウント作成に伴ってステートにスパムを送信する DoS 攻撃のリスクも軽減されます。次の図の例では、イーサリアムトライに2つの子ノードがあるノードが、子ノードがユニトライに埋め込まれている単一ノードにどのように変換されるのかを示しています。

2つの小ノードを親に埋め込む

ストレージセルキーの圧縮によるステートサイズの縮小およびガスコストの削減

当社の RSKIP108 では、ストレージキーに長い0接頭辞が含まれている場合にストレージセルを圧縮する方法について説明しています。単一バイトアドレスがあって単一バイトを保存するセルは、サイズが小さくノードを埋め込めるため、過去の未圧縮サイズの10%にまで圧縮できます。ユーザーによる圧縮ストレージの使用を奨励するために、RSKIP109  ではコントラクトストレージへの書き込み処理コストを更新します。例えばアドレス 0x00 で 0x01 を保存した場合の消費量は5460ガスユニット程度ですが、イーサリアムでは20Kです。以下の図は、イーサリアムとユニトライでストレージセルアドレス 0x01 に対して使用される異なるキーを表しています。

キーストレージ圧縮の例

取引の並行処理と組み合わせた場合のスケーラビリティの向上

当社の RSKIP04 では、ブロック処理時間を短縮するために、取引の並行処理を提案しています。ブロック処理時間を短縮することで、ブロックの伝搬を高速化してコンセンサスを向上させることができます。つまり、ブロック伝搬を遅らせることなく、より多くの取引をブロックに投入することもできるということです。一般にブロック伝搬の待ち時間が長いと、小規模なマイニングプールに対して最大のマイニングプールが得られるため、私たちが分散化を減少させることなく確信をもってスケーリングしていることは、安心感を与える事実です。しかし、コントラクトステートアクセスの観点から取引を非重複セットに分割できる場合、ブロックチェーンは並行取引処理からしか利益を得られません。すべての取引が単一のトークンコントラクトを呼び出している場合、そのコントラクトは取引のシリアル化を強制してボトルネックになります。RSKIP59 では1つの解決策として、コントラクトストレージセルがサブコントラクトに移動されて親子関係を形成するようにコントラクトを設計することを挙げています。そうすることで、異なるユーザーのトークンバランスが異なるコントラクトに保存されます。さらにこの解決策では、スケーラビリティを実現するために、特定の設計パターンの使用を強制するコントラクトを再設計して再実装する必要があります。しかしユニトライでは、新たなパターンを使用する上での関連障害を克服しなくてもこの問題を解決できます。ユニトライでは、フルコントラクトの同時アクセスの検出にとどまらず、ストレージセルへの同時アクセスをも簡単に検出できます。つまり、2つの取引において同一のストレージセルには書き込まれないのであれば(または一方の取引で書き込まれたセルが他方の取引で読み込まれるのであれば)、両方の取引を同時に実行できるということです。例えば、ERC20 コントラクトでは通常、ソースと送信先アカウントに関連するセルのみが変更されるため、これらのコントラクトには、セルレベル検出を含む即時並行処理機能が備わります。ユニトライでなくても同じ機能性を確保できるかもしれませんが、ユニトライがあれば書き込みコリジョン検出アルゴリズムを大幅に簡易化できます。例として、以下の図に2つのスレッド処理取引を示します。1つ目のスレッドではコントラクト C のセルが変更され(紫色の矢印)ますが、これはスレッド2の影響を受けません。一方スレッド2では、同一コントラクトの別の2つのセルが変更されますが、これはスレッド1で変更されたセルに影響を及ぼしません。

同一コントラクトストレージを変更する2つの実行スレッド

 

ストレージレントと組み合わせた場合の公平性の向上

このイーサリアムデザインの1つの影響とはガス裁定取引が可能になることです。これによりユーザーは有効なデータを保存することなくストレージセルをあらかじめ購入して占有することができます。最初の購入に使用するガスの一部を回収するため、およびこのガスを第三者に販売するために、これらのセルを後で空にします。もう1つの不測の影響として、イーサリアムでは新規ストレージセルの使用に対して高い前金支払額が必要になります。なぜなら、この支払の目的は主に、キーと値のペアに対する永久ストレージと存続保証であるためです。

ストレージレントによって両方の問題が緩和されます。ストレージレントの最も議論され受け入れられたフォームには、コントラクトと関わりあい、コントラクトの非アクティブ時間と、非アクティブ時間中にコントラクトによって消費されたメモリースペースに比例して料金を支払うユーザーが必要です。RSKIP61 では、プラットフォームの公平性に影響するオリジナル EVM デザインからの悪影響を防ぐために、コントラクトレントの使用を提案しています。これは、確率的な公平性をもたらすものではありますが、粗削りなものであり、エッジケースではうまく機能しません。数百万のキー/値ペアを保存するがめったに使用されない集団所有コントラクトでは、過剰なストレージレントを最初のユーザーが負担することになり、長い非アクティブ期間の後でコントラクトが呼び出されます。ユニトライによって各ストレージセルの最終アクセス時間を追跡するタスクが簡易化されると、ストレージレントは細かくなるため、コントラクトにおいて呼び出し実行に関わるセルに対してのみレントを支払うことができるようになります。RSKIP113に明記されているこの簡易化は、すべてのノードが公平に扱われることに起因しているので、アカウント、コード、ストレージセルはアクセスされるとレントを消費できます。

よりシンプルなステートガベージ収集による完全性の強化

ステートガベージ収集とは古いステートデータの削除です。古いステートデータは上書きされたため、通常は二度と参照されません。ブロックチェーンの大幅な再編などといった例外的なイベントにおいては、あらかじめ算出したステートチェックポイントから古いブロックを再実行することで、このデータを再計算できます。ただしイーサリアムでのガベージ収集は、多数の個別データベース(またはトライ)に対して適用されなければならないため重要なものです。適用は1つのアクティブコントラクトにつき1つです。ユニトライを使用するということは、ガベージ収集が単一データベースに適用されるということであり、それによって、ガベージ収集時にデータベースを変更して一貫性のない状態で放置してしまう可能性のあるスレッド中断のリスクが緩和されます。

 

さらに高速でさらにシンプルなステート同期

Lightweight ウォレットからブロックチェーンブリッジまで、特定音ブロック高さでブロックチェーンのステートにクエリーを行う必要があるアプリケーションは数多く存在します。ユニトライのバイナリ構造により、最小限のスペース消費と最大限のパフォーマンスで、ステート内のデータメンバーシップの検索と証明を実行できます。さらに、ステート情報の送信に関わるネットワークコマンドの複雑性も緩和されます。

しかし最も重要なのは、ユニトライではステート情報を高速で並行してダウンロードすることで「高速同期」または「ワープ同期」同期を実現できることです。 すべての情報が単一のトライに保存されている場合は、ノードによってより効率的にステート情報を取得できます。ユニトライには、各ノードでルートされたサブツリーによって消費されるバイト数が保存されるので、ユニトライデータ構造はさまざまなサイズのクエリーに対応できます。これはピアによって、特定サイズのトライ「パケット」のリクエストに使用され、任意のバイト数のオフセットから始まります。そのため、負荷がしっかりと分散される方法でリクエストを並行処理できます。例えば、1つのノードによって10のノードからステート情報を収集し、1回目には0K~100K バイトを、2回目には100K~200K バイトをリクエストすることができます。これによって、高速同期の利点(返送データの即時検証)にワープ同期の利点(複数のソースからの大容量データチャンクの同時取得)を組み合わせた同期モードを作成できます。下の図はユニトライの例で、ノードサブツリーサイズを示しています。それぞれがほぼ同量のデータを含む3つのチャンクにトライを分割できます。各チャンクは異なるピアにリクエストされます。リクエスターが各チャンクの内容と限界を把握していなくても、チャックのサイズは事前に把握できます。各チャンクは受領時に効率的に個別確認できます。検証できるように、複数のチャンクにいくつかの内部ノードが含まれます。

検証可能な3つの個別チャンクに分割されたステートユニトライ

ユニトライのもう1つの大きな利点は、トライノードサイズを保存することで、ネットワークノードによって、ステート同期処理完了率を示し、同期処理完了までの時間を予測できることです。

自動コード重複排除を通じた小規模なブロックチェーン

ストレージセルとコードを単一の内容呼び出しデータベースにまとめることで、同じキー/値を含むノードがそのデータベースに1回のみ保存されます。これにより自動データ重複排除機能を利用できるようになります。コントラクトコードの場合、この機能によって、別の重複排除メカニズムが必要になることもなく、データ圧縮技術を使用しないで、ブロックチェーンサイズを縮小できます。トライ内のコードノードには常に同一の接頭辞(0x80)が含まれます。コードが同一というは、ノードハッシュもストレージも同一ということになります。

 

EXTCODESIZE の高速実行

各ユニトライノードには、そのノードに保存されているデータのサイズがキャッシュに格納されているフィールドが1つ含まれています。イーサリアムトライでは、ノードデータのサイズのクエリーによって、データベースからデータが強制的に取り出されます。ユニトライでは、この新しいフィールドのクエリーを行うことで、EXTCODESIZE 命令コードによって生成されるサイズクエリーなどに対応します。ハードディスクからコードは取り出しません。EXTCODESIZE 命令コードはこれまで、一定のイーサリアム実装において DoS 攻撃の実行に使われてきました。ユニトライにはこの攻撃に対する耐性があります。

 

アップグレード方法の詳細

これまでに、このデータベースがブロックヘッダーに投入されるとステートデータベースを変更するというアップグレードを実行したブロックチェーンはありませんでした。そのため、このアップグレードは他に類を見ないものとなるでしょう。このアップグレードは基本的に2つの段階で発生します。新規ソフトウェアリリースによって新たなトライルートが算出されますが、新ステートトライを旧トライにオンザフライで構造変換する動的アルゴリズムを用いて従来のトライルートも導き出されます。その後、ハードフォークが生じ、新ステートルートが投入・検証され、動的変換はこれ以上発生しなくなります。実際には、ステートトライだけでなく、取引トライと受領トライも変換する必要があります。

ネットワークアップグレードを成功させるにはいくつかのイベントの発生が必要です。タイム R にフルノードソフトウェアの新バージョンがリリースされます。この新リリースには、ジェネシスブロックからタイム C の特定ブロックまでの周期的チェックポイントが含まれます。タイム R の後にタイム C が発生します。タイム H のハードフォークの前にノードがアップグレードされるインターバルが存在します。下の図にタイムラインを示します。

ユニトライ向けネットワークアップグレードのタイムライン

 

新リリース(当社では0.7.0と呼ぶ)がインストールされると、フルノードにより必ず、新規ルールに従ってそのステートデータベースが再構築されます。現在のステートを移行するか、またはジェネシスから最適チェーチップまでのすべてンブロックを再処理することでステートを再計算できます。RSK アップグレードに対しては、この再処理を選びました。これによって、前のデータベースが過去に何らかの原因で破損した場合であっても、すべてのフルノードのデータベースが完璧に同期されます。

イベント C が選択されており、ハードフォークの約2週間前にイベント C が発生します。ユーザーは、リリース日 R の後、ハードフォーク日 H の前に、各自のフルノードソフトウェアをアップグレードする必要があります。C~H の期間に、ノードによって新旧両方のトライのステートルートが計算されます。新ステートトライから旧ステートルートが動的に算出されます。Lightweight ノード(別名SPV ノード)では、CPU の負荷を軽減するために、この短い間隔ではステートルートを確認しないことが決定される可能性があります。これは Lightweight ノードが必ずハッシュレートに従うためです。また、例えば、C~H 間隔に10のステートルートコミットメントのうち1つを検証することで、ノードによってこの期間の確認オーバーヘッドが削減される可能性があります。ただし、ハードフォーク後の最初のブロックでは、旧ステートルートの計算も確認も実行されなくなります。コミュニティが承認すれば、非常にクリーンなハードフォークベントを期待できます。

要約

2016年に RSK が提案したユニトライは、RSK などのアカウントベースのブロックチェーン内にあるステートストレージを大幅に改良したもので、フルノードのパフォーマンスを劇的に向上させます。ユニトライでは、フルノードリソース要件を緩和することで分散化を改良し、取引のより優れた並行処理を実現することで取引スループットを向上させ、ペイロードサイズのキャッシュ格納とアカウントサイズの縮小により DoS 攻撃を防止し、ステートの圧縮により同期時間を短縮します。

私たちは、ユニトライを使用するためにネットワークアップグレードを実行することは容易ではないことは承知していますが、今回の変更を推進するときが来たと考えています。RSK Labs は現在、参照コードを完成させて RSKIP に最後の微調整を施しており、その一方で RSK コミュニティが今回の変更内容を評価しています。今後数か月以内に、安全なネットワークアップグレードによりユニトライの使用を開始できるようにする予定です。