V God の設計コンセプトが発表され、イーサリアムの潜在的な長所と短所が詳しく説明
ここここ、この再版は校正済みです。原訳者のキム氏に感謝の意を表したいと思います。
原文の執筆時期は不明ですが、イーサリアムの設計コンセプトとここ数年のイーサリアムの進化を振り返る出発点とみなすことができます。それはその革新性を反省するだけでなく、その配慮の欠如を反省することでもある。
原則として
原則として
イーサリアム プロトコルの設計は次の原則に従っています。
Sandwich Complex Model (「複雑な階層化モデル」とも訳される): 私たちは、イーサリアムの基礎となるプロトコルは可能な限りシンプルであるべきであり、インターフェイスの設計は (開発者向けの高レベルのプログラミングであるかどうかにかかわらず) 理解しやすいものであるべきだと信じています。言語インターフェイスまたはユーザー指向の使用インターフェイス)。避けられない複雑な部品は中間層に配置します。中間層はコア コンセンサスの一部ではなく、エンド ユーザーには見えず、高水準言語コンパイラ、パラメータのシリアル化および逆シリアル化スクリプト、ストレージ データ構造モデル、leveldb ストレージ インターフェイス、ネットワーク プロトコルが含まれます。もちろん、区別の境界線は完全に明確ではなく、場合によっては適切に調整する必要があります。
自由: ユーザーはイーサリアム プロトコルの使用を制限されるべきではなく、特定のイーサリアム契約や取引を支持したりサポートしなかったりするべきではありません。これは、「ネット中立性」の概念の背後にある基本原則と似ています。ビットコイン トランザクション プロトコルは、この原則に従っていません。ビットコイン トランザクション プロトコルは、ブロックチェーンの「オフラボ目的」(データ ストレージ、メタ プロトコルなど)を奨励しません(校正注:オフラボの本来の目的は、頭痛を治療するための咳止め薬の使用など、承認された適応症以外の症状に対する薬の使用(ここでは「型破りな使用」と言い換えます)、また、場合によっては、準プロトコル層の変更(例:使用期間の制限など)を使用する人もいます。 OP_RETURN フィールドを 40 バイトに設定する)、「不正な」方法でブロックチェーンを使用するアプリケーションを攻撃する傾向)。したがって、イーサリアムでは、大まかなインセンティブの互換性を達成するためにトランザクション手数料のみを使用する方法を断固としてサポートします。ユーザーがネットワーク全体でより多くのリソースを消費するほど、ユーザーがコストを自分で負担する場合でも、支払わなければならない価格は高くなります(つまり、ピグー)税)。
一般化: イーサリアム プロトコルのプロパティとオペコードは、低レベルの概念 (素粒子など) を最大限に活用して、今日は役に立たないと思われるが将来役立つ可能性のあるものを組み合わせるなど、自由に組み合わせることができるようにする必要があります。また、不必要な機能を削除することで、低レベルの概念をより効率的にすることができます。この原則に従う例としては、dapp に情報を提供する方法として、以前のようにすべてのトランザクションとメッセージをログに記録するのではなく、LOG オペコードを選択したことが挙げられます。初期の「メッセージ(message)」という概念は、完全に「関数呼び出し(function call)」や「外部の観察者にとって興味のあるイベント情報(event)」を含むさまざまな概念の集合体であり、この2つは完全に分離可能。
最大の特徴は機能がないことです。一般化の原則に従うため、高度なユース ケースをプロトコルの一部として組み込むことを拒否します。たとえ頻繁に使用されるユース ケースであっても、決して埋め込みません。これらのユースケースを実際に実装したい場合は、コントラクト内でサブプロトコルを作成できます (例: イーサリアムベースのサブ通貨、ビットコイン/ライトコイン/ドージコインのサイドチェーンなど)。例えば、イーサリアムにはビットコインのような「タイムロック」機能がありません。ただし、この機能は次のプロトコルを通じてシミュレートできます。ユーザーは署名されたデータ パケットを処理のために特定のコントラクトに送信し、データ パケットが特定のコントラクトで有効であれば、対応する機能が実行されます。
リスク回避的ではない: リスクの増加によって目に見える利益がもたらされる場合には、より高いリスクを負います (例: 一般的な状態遷移、ブロック時間の 50 分の 1 の削減、コンセンサスの効率など)。
最初のレベルのタイトル
ブロックチェーン層プロトコル
副題
UTXO 1 ではなくアカウント
ビットコインとその多くの亜種は、ユーザーの残高情報を UTXO 構造に保存し、システム全体の状態は一連の「未使用の出力」で構成されます (これらの「未使用の出力」はコインと考えることができます) (校正注:比喩は「小切手」かもしれません。)各 UTXO には所有者と独自の値属性があります。トランザクションは、複数の UTXO を消費しながら、いくつかの新しい UTXO を生成します。また、トランザクションには次の有効性要件が適用されます。
1. 参照される各入力は有効かつ未使用である必要があります; 2. トランザクションの署名は各入力の所有者の署名と一致する必要があります; 3. 入力の合計値は出力の合計値以上である必要があります。
画像の説明
~ビットコインで採用されている三式簿記~
しかし、イーサリアムはUTXOスキームを放棄し、より単純な方法に切り替えました。状態(状態)の概念を使用して一連のアカウントを保存し、各アカウントには独自の残高とイーサリアム固有のデータ(コードと内部メモリ)があります。取引開始者の口座残高が取引手数料をカバーするのに十分な場合、取引は有効となり、対応する金額が開始者の口座から差し引かれ、受取口座に入金されます。場合によっては、受信側アカウントで実行する必要があるコードがある場合、トランザクションによってコードの実行がトリガーされ、アカウントの内部メモリが変更され、他のアカウントに送信する追加のメッセージが作成される場合もあります。 、その結果、新しいトランザクションが発生します。
イーサリアムは UTXO の概念を採用していませんが、UTXO にはいくつかの利点があります。
より高度なプライバシー保護:ユーザーがトランザクションごとに新しいアドレスを使用する場合、アカウントを相互リンクするのは困難です。これは、高度なセキュリティ要件が必要な通貨システムには適していますが、Dapp には適していません。なぜなら、dapps は通常、ユーザーの複雑なバインディング状態を追跡する必要があり、dapps の状態は通貨システムの状態ほど単純に分割できないからです。
潜在的なスケーラビリティ:理論的には、UTXO は特定のタイプのスケーラビリティ スキーム (スケーラビリティ パラダイム) により適しています。これは、たとえ全員 (TA 自身を含む) がこのデータを忘れていたとしても、保有者だけが通貨の所有権を証明できるメルケル証明を持つ必要があるためです。その人は本当にダメージを受けますが、他の人は影響を受けません。イーサリアムアカウントシステムでは、アカウントに対応するマークルツリーの部分を全員が失った場合、そのアカウントは、そのアカウントに送信されたメッセージを含め、そのアカウントに影響を与える可能性のあるメッセージを処理できなくなります。それ。ただし、UTXO だけが拡張できるわけではなく、UTXO に依存せずに拡張する方法もあります (ここでは拡張はありません、翻訳者注)。
アカウントの利点は次のとおりです。
多くのスペースを節約: アカウントに 5 つの UTXO がある場合、UTXO モードからアカウント モードに切り替えると、必要なスペースが 300 バイトから 30 バイトに減少します。具体的な計算は次のとおりです: 300 = (20+32+8) * 5 (20 はアドレスのバイト数、32 は TX ID のバイト数、8 は金種によって占有されるバイト数です); 30 = 20 + 8 + 2 (20 はアドレス バイト、8 はアカウント残高値バイト、2 はノンス 2 バイト); ただし、アカウントはパトリシア ツリーに保存する必要があるため、実際の節約量はそれほど大きくありません。さらに、各トランザクションは 1 つの参照、1 つの署名、および 1 つの出力のみを生成する必要があるため、イーサリアムのトランザクションはビットコインのトランザクションよりも小さくなります (イーサリアムでは 100 バイト、ビットコインでは 200 ~ 250 バイト)。
より強力な互換性: UTXO 構造にはブロックチェーン層の概念がないため、技術的にも法的にも、レッド リスト/ブラック リストを確立し、これらの「有効な出力」のソースに基づいて区別することはあまり現実的ではありません。
シンプルさ: イーサリアムのコーディングは、特に複雑なスクリプトが含まれる場合に、よりシンプルで理解しやすくなります。あらゆる分散アプリケーションを (仕方なく) UTXO で実装できますが、この方法では基本的に、特定の UTXO が出力できる UTXO の種類とその使用条件をスクリプトが制限できるようになります (たとえば、スクリプトの実行を支援するマークル ツリー証明を含める必要があります)。対応するアプリケーションは状態ルートを変更します)。したがって、UTXO の実装は、イーサリアムのアカウントの使用方法よりもはるかに複雑です。
ライト クライアント: ライト クライアントは、指定された方向にステート ツリーをスキャンすることで、アカウントに関連するすべてのデータにいつでもアクセスできます。 UTXO パラダイムでは、各トランザクションは異なる参照を使用する必要があります。これは、前述の UTXO ルート状態伝播メカニズムを使用する長時間実行される dapp アプリケーションにとって間違いなく負荷がかかります。
私たちは、特に任意の状態やコードを含む可能性のあるサポートしたい種類の DAPP の場合、アカウントの利点が代替手段を大きく上回ると信じています。さらに、「どの機能も最大の機能ではない」という基本原則に沿って、ユーザーがプライバシーを本当に重視するのであれば、契約内の署名付きデータ パケット プロトコルを通じて暗号化された「ミキサーとコインジョイン」を構築できると考えています。パス。
アカウント方式の弱点は、リプレイアタック(同じトランザクションを繰り返し実行することを意味するリプレイ攻撃)を防ぐために、各トランザクションに「ノンス」(シリアル番号)が必要なことです。したがって、各アカウントにはリアルタイムで更新される nonce 値が必要であり、新しいトランザクションごとに、アカウントの nonce 値が独自の nonce として 1 ずつ増加します (トランザクション処理後に、この値によってアカウントの nonce 値が更新されます) (校正メモ:アカウント モード。トランザクションにこの消耗品識別子が付加されていない場合、トランザクションは繰り返し処理できるため、受信側アカウントはコストを支払うことなく何度もアカウントを収集できますが、送信側アカウントは完全に吸い取られます。開始されたトランザクションが処理されると、イーサリアム アカウントのノンスが増加するため、この問題は解決されます)。つまり、使用されなくなったアカウントであっても、アカウントのステータスを削除することはできません。この問題の簡単な解決策は、トランザクションにブロック番号を含めて、一定期間後にトランザクションを取得できなくなるようにし、ナンスを頻繁にリセットすることです。
この状態のアカウント (長期間使用されていないアカウントなど) を削除したい場合は、まずそのアカウントに「ping」を送信する必要があり、ブロックチェーン プロトコルを完全にスキャンするオーバーヘッドは非常に大きくなります。このメカニズムは 1.0 には実装されていないため、バージョン 1.1 以降でこのメカニズムが使用される可能性があります。
校正メモ: これが、イーサリアムが将来直面する「状態爆発」問題の技術的な理由です。すべての状態データは完全に保存されなければならず、アカウントは合理的に削除できません。ブロックチェーンプロトコルとして、イーサリアムのノードはトランザクション(トランザクション)の順序についての合意に達するだけでなく、グローバルな状態(表現形式としては状態のルートがブロックに含まれる必要がある)に関しても合意に達する必要があります。したがって、状態を削除するにはネットワーク全体の合意が必要であり、そうでないと分裂に陥ってしまいます。
この記事この記事。
メルケル・パトリシア・ツリー (MPT)
アラン・ライナーによって考案され、リップル・プロトコルに実装されたマークル・パトリシア・ツリー/トライは、イーサリアムの主要なデータ構造であり、すべてのアカウント状態と各ブロックのトランザクションおよび受領データを保存するために使用されます。 MPT はマークル ツリーとパトリシア ツリーを組み合わせたもので、これら 2 つのツリーを組み合わせて作成される構造は次の特性を持ちます。
キーと値のペアのセットに対応するルート ハッシュ値は一意であるため、特定のツリーにキーと値のペアが存在すると誤って主張したい場合、(攻撃者が約 2^128 の計算能力を持っていない限り) それは間違いなく見破られます。力)。
キーと値のペアの追加、削除、変更の時間計算量は対数的です。
MPT は、状態ツリー全体を表す効率的で更新が簡単な「フィンガープリント」を提供します。 MPT の詳細な説明: https://github.com/ethereum/wiki/wiki/Patricia-Tree。
MPT の具体的な設計上の決定事項は次のとおりです。
ノードには、KV ノードとディスクリート ノードの 2 種類があります。 KV ノードの存在により効率が向上します。これは、特定の領域でツリーがまばらな場合、KV ノードをツリーの高さを圧縮するための「ショートカット」として使用できるためです (詳細については、MPT の詳細な説明を参照してください)。
離散ノードはバイナリではなく 16 進数です。これによりルックアップがより効率的になりますが、ノードをバッチに格納することで 16 進ツリーのルックアップ効率をバイナリでシミュレートできるため、この選択は理想的ではないことが現在では認識されています。ただし、MPT ツリー構造の実装は非常にエラーが発生しやすく、少なくともステート ルートで不一致が発生することになるため、1.1 まで変更を保留することにしました。
空の値と非メンバーシップの間には区別はありません。これはロジックを簡素化するために行われ、イーサリアムで有効になっていないアカウントの値 (残高) はデフォルトで 0 になり、空の文字列も 0 で表されます。ただし、これは一般性をある程度犠牲にするため、最適ではないことを強調しておく必要があります。
終端ノードと非終端ノードの違い: 技術的には、イーサリアムのすべてのツリーは固定長 (つまり、キーの長さ) データを保存するために使用されるため、ノードを「終端ノードであるかどうか」識別する必要はありません。汎用性を高めるために、イーサリアムの MPT の実装が他の仮想通貨でもそのまま採用されることを期待して、このロゴを追加します。
SHA3(k) を「セキュリティ ツリー」(状態ツリーとアカウント ストレージ ツリー) のキーとして使用します。SHA3(k) を使用すると、多数のアカウント (アカウントは最大 64 レベルの状態ツリーを作成できます) を生成し、繰り返し生成する必要があります。 SLOAD および SSTORE オペコードにより、DoS 攻撃がさらに困難になります。これにより、ツリーの列挙も困難になることに注意してください。クライアントで列挙できるようにしたい場合、最も簡単な方法は、データベース マッピング sha3(k) -> k を維持することです。
校正メモ: ここでの意味は、k がデータを保存するマークル ツリーのキーとして使用される場合、その分布は非常にまばらになる可能性があり、攻撃者は保存するために深いツリー パスを必要とするアカウントを簡単に計画し、これらのアカウントをターゲットにすることができるということです。状態アクセス操作を繰り返し呼び出すと、ネットワーク内のノードに過負荷がかかります。ただし、ハッシュ関数の結果はランダムに分散されます。sha3(k) をキーとして使用すると、キーの分散がより均一になり、ツリーの高さが短くなります。) 。
この機能には長所と短所もあり、DoS 攻撃がより困難になる一方で、ブロック内のトランザクションのステート ツリーのアクセス パスが重なりにくくなるため、各検索の両方が可能になります。最悪の場合の複雑さ。
さらに、このことは、状態アクセスのパスが重複しないため、MPT が「ステートレス」 (ブロック自体が検証に必要なデータを保持し、検証者はグローバル状態を持つ必要がない) を実現するのにも適さないものとします。証拠のスペース効率も最悪のケースです。もちろん、マークルツリーの証拠自体のスペース効率が十分に高くないということも言えます
RLP
RLP (再帰長プレフィックス): 再帰長プレフィックス。
RLP エンコーディングはイーサリアムの主要なシリアル化形式であり、ブロック、トランザクション、アカウント状態、ネットワーク プロトコル メッセージなどあらゆる場所で使用されます。詳細については、RLP の公式説明を参照してください: https://github.com/ethereum/wiki/wiki/RLP
RLP は、ネストされたバイト配列 3 を格納することを唯一の目的とする、非常に単純化されたシリアル化形式であることを目的としています。 protobuf や BSON などの既存のソリューションとは異なり、RLP は Boolean (ブール)、float (浮動小数点)、double または integer (整数) などの特定のデータ型を定義しません。ネストされた配列の形式で構造を格納するだけであり、配列の意味を決定するのはプロトコル次第です。 RLP はマップ コレクションも明示的にサポートしていません。準公式の提案は、キーと値のペアのコレクション k1、k2 を表すために [[k1, v1], [k2, v2], ...] のネストされた配列を使用することです。 ...文字列の標準ソートに従って。
RLP と同じ機能を持つスキームとして protobuf や BSON があり、これらは古くから使用されているアルゴリズムです。ただし、イーサリアムでは、(1) 実装が簡単である、(2) バイトの一貫性が絶対に保証されているという理由から、RLP を使用することを好みます。
多くの言語には、キーと値のペアのコレクションの明示的な順序付けがありません。また、浮動小数点形式には、同じデータに対して異なるエンコーディングや異なるハッシュが発生する可能性がある多くの特殊なケースがあります。プロトコルを内部で開発することで、これらの目標を念頭に置いてプロトコルを設計することができます (これは、仮想マシンなどのコードの他の部分にも適用される一般原則です)。 BitTorrent で使用されるエンコード方式である bencode は、RLP の代替となる可能性があります。ただし、バイナリ RLP よりもわずかに劣る 10 進エンコード方式が使用されます。
圧縮アルゴリズム
ネットワーク プロトコルとデータベースは両方とも、カスタム圧縮アルゴリズムを使用してデータを保存します。アルゴリズムは次のように説明できます: 他の値を保持しながら 0 に対してランレングス エンコーディング 4 を使用します (sha3(' ') などの特殊なケースを除く)。たとえば、次のようになります。
圧縮アルゴリズムが存在する前は、イーサリアム プロトコルの多くの場所にいくつかの特殊なケースがありました。たとえば、sha3 は、アカウントにコードを保存する必要がないように、sha3(' ')=' ' になるように再定義されることがよくありました。これにより 64 バイトを節約できます。しかし最近、イーサリアムのデータ構造を肥大化させたこれらの特殊なケースはすべて削除され、代わりにデータ保存機能がブロックチェーン プロトコルの外側の層、つまりネットワーク プロトコルとその挿入ユーザー データベース実装に追加されました。これにより、モジュール化機能が強化され、コンセンサス層が簡素化され、圧縮アルゴリズムの継続的な更新が比較的簡単に展開できるようになります (たとえば、ネットワーク プロトコルのバージョン番号によって区別して展開できます)。
木の利用(トライ)
注意: 知識のこの部分を理解するには、読者がブルーム フィルター 5 の原理を理解する必要があります。概要は http://en.wikipedia.org/wiki/Bloom_filter でご覧いただけます。
Ethereum ブロックチェーンの各ブロック ヘッダーには、状態ツリー、トランザクション ツリー、レシート ツリーという 3 つのツリーへのポインターが含まれています。
状態ツリーは、ブロックを処理した後の状態全体を表します。
トランザクション ツリーはブロック内のすべてのトランザクションを表し、これらのトランザクションはインデックスをキーとしてインデックス付けされます (たとえば、k0: 最初に実行されたトランザクション、k1: 2 番目に実行されたトランザクション)。
レシート ツリーは、各トランザクションに対応するレシートを表します。
トランザクション レシートは、RLP エンコードされたデータ構造です。
で:
medstate: トランザクションが処理された後の状態ツリーのルート。
Gas_used: トランザクションの処理後に使用されたガスの量。
logs: は、多数の [address, [topic1, topic2...], data] 要素のリストです。これらの要素は、トランザクション実行中に呼び出されるオペコード LOG0 ... LOG4 によって生成されます (メイン呼び出しとサブ呼び出しが含まれます)。アドレスはログを生成するコントラクトのアドレスです。トピックは最大 4 つの 32 バイト値です。データは 1 つのワードです。任意のサイズのセクション配列。
logbloom: トランザクション内のすべてのログのアドレスとトピックで構成されるブルーム フィルター。
ノート:
ノート:
UTXO: 未使用のトランザクション出力、文字通り: 未使用のトランザクション出力、つまり、どのトランザクションからも入力として参照されていないトランザクション出力。これは、価値 (所有権) 情報を保存するためにビットコイン プロトコルで使用されるデータ構造です。 —— 校正メモ
Nonce (Number used Once または Number Once の略) は、暗号学において、一度だけ使用される任意のまたは非反復のランダムな値であり、暗号化技術における初期ベクトルと暗号化されたハッシュ関数の両方が重要な役割を果たします。さまざまな認証プロトコルの通信アプリケーションを使用することで、リプレイ攻撃 (リプレイ攻撃) に対抗するために認証情報が再利用されないことが保証されます。 ——訳者注
ネストされた配列: 配列を作成し、そこに他の配列を設定します。配列ペットなど:
var cats : String[] = ["Cat","Beansprout", "Pumpkin", "Max"];
var dogs : String[] = ["Dog","Oly","Sib"];
var pets : String = [cats, dogs];——訳者注
run-length-encoding: 統計的なエンコーディング。主な手法は、ビットまたは文字の繰り返しシーケンスを検出し、それらの出現回数に置き換えることです。 (百度百科事典) - 翻訳者注記
最初のレベルのタイトル
ブロックおじさんの報酬
GHOST プロトコルは、2013 年 10 月に Yonatan Sompolinsky と Aviv Zohar によって最初に提案された注目すべき革新です。これは、高速ブロック生成に関連する問題を解決する最初の本格的な試みです。
GHOST の目的は、このような問題を解決することです。ブロック時間が短くなると (したがって確認速度が速くなり)、より多くのブロックが「時代遅れ」になるため、安全性が低くなります。これは、マイナー A の場合、ブロックがネットワーク内で伝播するのに時間がかかるためです。がブロックを掘り出してネットワーク全体にブロードキャストし、ブロードキャストの途中で B もブロックを掘り出すと、B のブロックは古くなり、B の現在のマイニングはネットワークのセキュリティに貢献しません。
さらに、集中化の問題があります。A が 30% のコンピューティング能力を持つマイニング プールである場合、B は 10% のコンピューティング能力を持っています。 A は 70% の時間で古いブロックを生成します (残りの 30% の時間で最新のブロックが生成されるため、TA はブロックの送信を待たずに最新ブロックのデータを「即座に」取得したと考えることができます)。 B は、時間の 90% を古いブロックの生成に費やします。ブロック生成間の時間間隔が非常に短い場合、陳腐化率が高くなり、A のより大きな計算能力によりマイニングがより効率的になります。したがって、ブロックの生成が早すぎると、大規模なネットワーク コンピューティング能力を持つマイニング プールの事実上の独占に簡単につながります。
Sompolinsky 氏と Zohar 氏によると、GHOST は、どのチェーンが最も長いかを計算する過程で古いブロックによって引き起こされるネットワーク セキュリティの低下の問題を解決します。つまり、親ブロックとそれ以前のブロックだけでなく、古くなった担保ブロック(イーサリアムでは「おじさんブロック」と呼びます)も追加して、どのブロックの総作業量が最も多いかを計算します。 証明に進みます。
2 番目の問題: 集中化の問題を解決するために、別の戦略を採用しました: ブロック報酬は古いブロックにも提供されます: 古いブロックをマイニングすることに対する報酬は、ブロックの基本報酬の 7/8 です。時間ブロックの甥のブロックは、基本報酬の 1/32 を報奨金として受け取ります。ただし、取引手数料は叔父と甥のブロックには付与されません。
イーサリアムでは、古いブロックは、兄弟ブロックの 7 世代以内の直系子孫ブロックによってのみ、叔父ブロックとして含めることができます。この制限の理由は、第一に、GHOST プロトコルが古いブロックの世代間距離を制限しない場合、古いブロックの有効性の計算に多くのオーバーヘッドが費やされること、第二に、古いブロックに対する無制限のインセンティブ ポリシーが存在することです。マイナーはメインチェーンでのマイニングへの熱意を失い、最終的に計算によると、レイヤー 7 に限定された時代遅れのブロック報酬ポリシーは、マイナスの副作用なしに望ましい効果のほとんどを提供することが示されています。
集中化リスクを測定するためのシミュレーターはここにあります: https://github.com/ethereum/economic-modeling/blob/master/ghost.py
より高度な議論はここにあります: https://blog.ethereum.org/2014/07/11/toward-a-12-second-block-time/
校正メモ: ここでの「インクルード」の技術的な形式は次のとおりです。甥ブロックは、ブロック ヘッダー内の叔父ブロックのブロック ハッシュ値を参照し、次に叔父ブロックのブロック ヘッダーをブロック本体に含めます。
ブロックタイム アルゴリズムの設計上の決定には、次のものが含まれます。
ブロック時間 12 秒: これはすでにネットワーク遅延の最小時間間隔より長いため、12 秒が選択されます。ビットコイン ネットワークの遅延の測定に関する 2013 年の論文では、新しく生成されたブロックがノードの 95% に伝播するのにかかる時間は 12.6 秒であると判明しましたが、論文では伝播時間はブロックに比例するとも述べられています。サイズが大きいため、より高速な通貨では、伝播時間が大幅に短縮されることが期待できます。伝播間隔は約 2 秒で一定です。ただし、安全のため、分析ではブロックの伝播に 12 秒かかると仮定しています。
祖先の 7 世代以内の制限: この設計の目的は、少数のブロックのみを保持し、以前のブロックをクリアすることです。引用可能な範囲の 7 世代は、望ましい効果のほとんどを提供することが示されています。
1 世代の子孫制限: (例: c(c(p(p(p(p(head))))) は、c = child および p =parent の場合は無効です。これは、簡素化のための設計目標でもあり、前述のシミュレーターは、これが重大な集中化のリスクを引き起こさないことを示しています。 (校正注: この文はわかりにくいです。考えられる意味としては、「アンクル ブロックの子孫はアンクル ブロックとして使用できない、つまり、主鎖の側枝の世代のみがアンクル ブロックとして使用できる」ということです。 。)
アンクル ブロックは有効である必要があります: アンクル ブロックは有効なブロックではなく、有効なヘッダーである必要があります。これも簡素化のために行われ、ブロックチェーン モデルを (DAG にならずに) 線形データ構造として保持します。ただし、叔父ブロックが有効なブロックであることを要求することも有効です。
最初のレベルのタイトル
難易度更新アルゴリズム
現在、イーサリアムは次のルールに従って難易度の更新を実行します。
難易度更新ルールの設計目標は次のとおりです。
高速更新: ハッシュパワーの増減に応じてブロック間の時間を迅速に調整する必要があります。
低いボラティリティ: マイニングパワーが一定であれば、難易度が大きく変動することはありません。
シンプル: アルゴリズムの実装は比較的シンプルである必要があります。
低メモリ: アルゴリズムは、あまりにも多くの履歴ブロックに依存すべきではなく、できるだけ少ない「メモリ変数」を使用する必要があります。最新の 10 個のブロックがあると仮定すると、これら 10 個のブロックのヘッダーに格納されているメモリ変数を追加すると、これらのブロックをアルゴリズムの計算に使用できます。
アンブレイカブル: このアルゴリズムは、マイナーにタイムスタンプを改ざんしたり、計算能力を繰り返し追加または削除するためにプールをマイニングしたりする動機を過度に与えるべきではありません。
最初のレベルのタイトル
ガソリンと料金
ビットコインのすべてのトランザクションはほぼ同じであるため、ネットワーク コストは 1 つの単位でモデル化されます。イーサリアムでのトランザクションはより複雑であるため、トランザクション料金では、ネットワーク帯域幅コスト、ストレージ コスト、計算コストなど、アカウントのさまざまな側面を考慮する必要があります。特に、イーサリアム プログラミング言語はチューリング完全であるため、トランザクションでは帯域幅、ストレージ、計算コストをいくらでも使用できますが、最終的にどのくらい使用されるかは確実に予測できません (いわゆる「チューリング停止問題」のため) ) ) (校正注: つまり、チューリング マシン上で実行可能なプログラムが有限のステップ数内で終了すると断言する信頼できる方法はありません)。無限ループを使用したサービス拒否攻撃を防ぐことは、私たちの重要な目標です。
イーサリアム取引手数料の基本的な仕組みは次のとおりです。
各トランザクションでは、消費するガスの量 (つまり、startgas の値を指定) と、ガスの単位ごとに支払う料金 (つまり、gasprice) を指定する必要があります。 (校正メモ: ここでの開始ガスは、現在使用されているガス制限です。)
データベースの読み取りと書き込み、メッセージの送信、各ステップでの計算など、トランザクション実行中のすべての操作は一定量のガスを消費します。
トランザクションが完了し、消費されたガス値が指定された制限値未満の場合、トランザクションは正常に実行され、残りのガス値は変数gas_remに代入され、トランザクション完了後、送信者は返されたイーサを受け取ります。 Gas_rem * ガスプライスの値。マイナーへの報酬は、(startgas - Gas_rem) * エーテルのガスプライス相当です。
トランザクションの実行中にガスが枯渇した場合、すべての実行は元の状態に復元されますが、トランザクションはまだ有効ですが、トランザクションの唯一の結果は、startgas * Gasprice の値をマイナーに支払うことです。もう一方は変更されません。
コントラクトが別のコントラクトにメッセージを送信する場合、メッセージによって引き起こされるサブ実行にガス制限を設定することができます。サブ実行のガスがなくなると、サブ実行は復元されますが、ガスは依然として消費されます。 (校正注:本記事校正時(2021年7月9日)時点では変更ありませんが、今後変更される可能性があります。「」を参照)削除を検討する価値のある EVM 機能》)
たとえば、次のような上記の点を満たす必要があります。
トランザクションでガス制限を指定する必要がなかった場合、悪意のあるユーザーが数十億ステップのループを含むトランザクションを送信する可能性があります。このようなトランザクションの処理には長い時間がかかる可能性があるため、誰もそのようなトランザクションを処理できませんが、誰もネットワーク上のマイナーに事前に通知することができないため、サービス拒否の脆弱性が発生します。
厳格なガスカウントの代替手段は時間制限ですが、主観的すぎるため役に立ちそうにありません (一部のコンピューターは他のコンピューターよりも高速であり、たとえ全員のコンピューターが同じであっても、問題が発生する可能性はあります)。
startgas * Gasprice の値全体を最初に設定する必要があります。これにより、トランザクション実行中にアカウントが「破産」してガス料金の支払いを続けることができなくなります。アカウントが残高を別の場所に置くことができるため、実行中に残高を確認することもできません。
ガスが不足した場合にトランザクションの実行が完全に元に戻されない (ロールバック) 場合、契約は変更されないように強力な安全対策を講じる必要があります。
サブ制限が存在しない場合、悪意のあるアカウントが他のコントラクトに対してサービス拒否攻撃を実行する可能性があります。攻撃者は、まず被害者コントラクトと合意に達し、次に計算プロセスの開始時に無限ループを挿入し、被害者コントラクトにメッセージを送信するか、被害者コントラクトを修復しようとすると、トランザクション全体がデッドロックになります。 (校正注:この文章もわかりにくいです。)
コントラクトではなくトランザクション送信者にガス料金の支払いを要求することで、開発者の操作性が大幅に向上します。イーサリアムの初期バージョンではガスの料金をコントラクトによって支払っていたため、かなり深刻な問題が発生しました。各コントラクトは、各受信メッセージがコントラクトで消費するのに十分なイーサを提供することを保証する「ゲートキーパー」コードを実装する必要がありました。
ガス消費量の計算には次の特徴があります。
どの取引にも、21000 ガスの基本料金がかかります。これらの料金は、署名から送信者のアドレスを復元するために設計された楕円曲線アルゴリズムの実行コスト、およびトランザクションの保存に費やされるハード ドライブと帯域幅スペースの支払いに使用できます。
トランザクションには無制限の量の「データ」を含めることができます。仮想マシン内の特定のオペコードにより、そのようなトランザクションを受信するコントラクトがデータにアクセスできるようになります。データの「固定消費」ルールは、ゼロ バイトあたり 4 ガス、非ゼロ バイトあたり 68 ガスです。この式が生じるのは、ユーザーがコントラクトに送信するほとんどのトランザクションが一連の 32 バイトのパラメーターで構成されており、そのほとんどのパラメーターの先頭にゼロ バイトが多数あるためです。この構造は非効率的に見えるかもしれませんが、圧縮アルゴリズムのおかげで、実際には非常に効率的です。この構造が、予想されるバイト数に従ってパラメータを厳密にラップする他のより複雑なメカニズムを置き換えることができ、その結果、コンパイル段階の複雑さが大幅に増加することを期待しています。これはサンドイッチ複合モデルの例外ですが、費用対効果の観点から合理的なモデルでもあります。
アカウントストレージ項目の設定に使用されるオペレーションコード SSTORE の消費量は次のとおりです: 1) ゼロ値をゼロ以外の値に変更すると、20000 ガスを消費します。 2) ゼロ値をゼロ値に変更するか、非ゼロ値に変更します。ゼロ値をゼロ以外の値に変更すると、5000 ガスが消費されます。3) ゼロ以外の値をゼロ値に変更すると、5000 ガスが消費されます。さらに、トランザクションが正常に実行された後、15000 ガスが返金されます (つまり、トランザクションガスを排出せずに実行されます)。還元額の上限は、取引で消費したガス総額の50%となります。これにより、人々は保管されているアイテムを片付ける小さなインセンティブが得られます。このようなインセンティブが欠如しているため、多くの契約のストレージ スペースが有効に活用されておらず、それが保存データの急速な拡大につながっていることに私たちは気づいています。この設計は、一度確立された契約が無期限に存在できるという保証を失うことなく、「保管アイテムの継続レンタル」モデルの利点のほとんどを提供します。遅延返金メカニズムが必要なのは、サービス拒否攻撃を防止できるためです。攻撃者は、少量のガスを含むトランザクションを送信し、ガスが使い果たされるまでサイクルで多数のストレージ アイテムをクリアすることができます。検証には多くの計算能力が必要ですが、実際にはストレージをあまり空にせず、大量のガスもかかりません。 50% の上限は、トランザクションをパッケージ化するマイナーがトランザクションを実行するための計算時間の上限を決定できるようにするためのものです。
(校正注:まず、SSTOREなどの状態アクセスオペコードのガス消費量はイーサリアムのハードフォークに伴い何度も変更されています。2021年7月時点の最新値は「」で確認できます)ベルリンのアップグレード内容概要"; 近い将来、このオペコードの値は変化し続けるでしょう。第二に、ここでのガス返金メカニズムは、状態データの拡張の問題を軽減するためにアクティブ化されておらず、問題を悪化させています。これは、人々が の値を変更できるためです。ガス価格 ガス価格が安いときはゴミデータを大量に書き込み、ガス価格が高いときはそれらのデータをクリアしてガスを入手する、これが「GasToken」の原理です。ガス返金メカニズムが「ロンドン」フォークで変更されることが確認されました。「」を参照してください。イーサリアム「ロンドン」アップグレードプレビュー》。)
契約により提供されるメッセージ データには費用はかかりません。メッセージ呼び出し中に実際にデータをコピーする必要がないため、呼び出しデータ (呼び出しデータ) は単に親コントラクトのメモリへのポインタとみなすことができ、子プロセスの実行時に変更されません。
メモリは無限に拡張できる配列ですが、32バイトのメモリを拡張するごとに1ガスコストを消費し、32バイト未満は32バイトとしてカウントされます。 (校正メモ: メモリは一般にメモリと訳されますが、イーサリアムの文脈ではデータを保存するため、EVM は 3 種類の EVM のうちの 1 つであるため、その特殊性を示すために訳されていません。)
一部のオペコードの計算時間はパラメータに大きく依存し、ガス オーバーヘッドの計算は動的に変更されます。たとえば、EXP のコストは指数関数的です (10 ガス + 10 ガス/バイト、つまり、x^0 = 1 ガス、x^1 ... x^255 = 2 ガス、x^256 ... x^65535 = 3ガスなど)。コピー オペコード (CALLDATACOPY、CODECOPY、EXTCODECOPY など) には、1 ガス + 1 ガス/32 バイトのオーバーヘッドがあります (切り上げ。LOG オペコードのルールも同様です)。メモリ拡張のオーバーヘッドはここには含まれていません。これが含まれる場合、正方形の攻撃ベクトル (50,000 CALLDATACOPY、毎回 50,000 ガスを消費する、計算量は 50,000^2 になるはずですが、動的課金ルールを使用しない場合は ~50,000 ガスを支払うだけで済みます) になります。 )。
オペコード CALL (および CALLCODE ) の値がゼロ以外の場合、追加の 9000 ガスがかかります。これは、値の転送によってアーカイブ ノードの履歴ストレージが大幅に増大するためです。実際の操作の消費量は 6700 ですが、これに基づいて受信機に自動的に与えられるガス値を強制的に増加させ、この値は少なくとも 2300 であることに注意してください。これは、トランザクションを受け入れるウォレットに少なくともログを生成するのに十分なガスがあるようにするために行われます。 (校正メモ:「」を参照してください)削除を検討する価値のある EVM 機能》)
ガスメカニズムのもう 1 つの重要な部分は、ガス価格自体に組み込まれた経済性です。ビットコインのデフォルトのアプローチは、マイナーがゲートキーパーとして機能し、最低料金を動的に設定する、純粋に任意の料金を取ることです。イーサリアムでは、トランザクション送信者は任意の数のガスを設定できます。この方法は、マイナーやトレーダーが需要と供給に基づいて価格を決定できる「市場経済」の具体化であるため、ビットコイン コミュニティで非常に人気があります。ただし、このアプローチの問題は、トランザクション処理が市場原理に従っていないことです。トランザクション処理は、マイナーが送信者に提供するサービスと考えることができますが (直感的に聞こえます)、実際にはマイナーが処理するすべてのトランザクションはネットワーク内のすべてのノードで処理される必要があるため、トランザクション処理の大部分のコストはすべて負担されます。それを処分するかどうかを決定するのは鉱山労働者ではなく、第三者機関によってです。したがって、「コモンズの悲劇」問題が発生する可能性が非常に高い。
最初のレベルのタイトル
仮想マシン
イーサリアム仮想マシンはトランザクション コードを実行するエンジンであり、イーサリアムと他のシステムの主要な違いでもあります。仮想マシンは「コントラクトおよびメッセージ モデル」とは別に考慮する必要があることに注意してください。たとえば、SIGNEXTEND オペコードは仮想マシンの機能ですが、実際には、「コントラクトは他のコントラクトを呼び出し、サブコールのガス制限を指定できる」は「コントラクトとメッセージ モデル」の一部です。
EVM の設計目標は次のとおりです。
シンプル: できるだけ少ない低レベルのオペコード、できるだけ少ないデータ型、できるだけ少ない仮想マシン構造。
結果は明確です。VM 仕様では、あいまいさが許容される余地はなく、結果は完全に決定的である必要があります。また、ガス消費量を測定できるように、計算ステップは正確である必要があります。
省スペース: EVM コンポーネントは可能な限りコンパクトである必要があります。
使用目的に特化: VM 上に構築されたアプリケーションは、20 バイトのアドレスと 32 ビットのカスタム暗号化値を処理でき、カスタム暗号化のモジュロ演算、読み取りブロックおよびトランザクション データ、および状態相互作用などの機能を備えている必要があります。
シンプルかつ安全: VM の悪用を防ぐために、一連のガス消費コスト モデルを簡単に確立できる必要があります。
最適化に優しい: ジャストインタイム コンパイル (JIT) および高速バージョンの VM を構築できるように、最適化が容易である必要があります。
同時に、EVM には次の特別な設計もあります。
一時ストレージと永続ストレージの違い: まず、一時ストレージと永続ストレージとは何かを見てみましょう。一時ストレージ: VM のすべてのインスタンスに存在し、VM の実行が終了すると消えます。永久ストレージ: ブロックチェーン状態レイヤーに存在します。次のツリーが実行されるとします (S は永続ストレージ、M は一時ストレージ)。
A が B に電話をかけます。
B は BS[0]=5、BM[0]=9 を設定します。
B は C に電話します。
C は B に電話します。
このとき、B が BS[0] を読み出そうとすると、以前に B に格納されていたデータである 5 が取得されますが、B が BM[0] を読み出そうとすると、BM は一時記憶域であるため、0 が取得されます。 、および読み取りが取得されると、それは仮想マシンの新しいインスタンスになります。内部呼び出し(内部呼び出し)で、BM[0] = 13、BS[0] = 17 に設定すると、内部呼び出しと C の呼び出しは両方とも終了し、B の外部呼び出し(外部呼び出し)に戻ります。 、この時点で M を読み取ると、 BM[0] = 9 (この値は同じ VM 実行の最後のインスタンスで設定されました)、BS[0] = 17 が表示されます。 B の外部通話が終了し、A が再び B に通話すると、BM[0] = 0 および BS[0] = 17 になります。この違いの目的は次のとおりです。 1. 各実行インスタンスにはメモリ領域が割り当てられ、ループ呼び出しによってメモリ領域が劣化することがないため、安全なプログラミングが容易になります。 2. 迅速に操作できるメモリ内フォームを提供します。ツリーを変更する必要があるため、ストレージの更新は必然的に遅くなります。
スタック/メモリ モード: 初期には、次の 3 種類の計算状態がありました (次の命令を指すプログラム カウンタを除く): スタック (スタック、32 バイトの標準 LIFO スタック)、メモリ (メモリ、一時的なバイト配列)無期限に延長できる)、ストレージアイテム(ストレージ、永久ストレージ)。一時ストレージ側では、スタックとメモリに代わるのはメモリのみのパラダイム、またはレジスタとメモリのハイブリッドです (この 2 つに大きな違いはなく、レジスタは本質的にメモリの一種です)。この場合、各命令には 3 つの引数があります。たとえば、 ADD R1 R2 R3: M[R1] = M[R2] + M[R3] です。スタック パラダイムを選択した理由は明らかで、コードが 4 分の 1 に小さくなります。
ワード サイズ 32 バイト: ビットコインなどのほとんどの構造では、ワード サイズは 4 バイトまたは 8 バイトです。 4 バイトまたは 8 バイトは、メモリ アドレスと暗号計算にとって制限が多すぎます。サイズを制限せずに、それに応じて安全なガスモデルを確立することは困難です。 32 バイトは、大きすぎて非効率になることなく、多くの暗号化アルゴリズムで必要な大きな値とアドレスを格納するには十分なサイズであるため、理想的なサイズです。
当社には独自の仮想マシンがあります。当社の仮想マシンは Java、Lisp、Lua などの言語で開発されています。 1) 他の仮想マシンは複雑さの割にコストがかからず、変更が容易であるため、私たちの VM 仕様は他の多くの仮想マシンよりもはるかに単純です。私たちのスキームの複雑さは、開発の強化への障壁を生み出し、コンセンサスエラーなどの潜在的なセキュリティ上の欠陥をもたらし、複雑さのコストを高くします。2) 私たちの VM は、32 バイトをサポートするなど、より特化しています。3) 複雑な外部は必要ありません。インストールが失敗する原因となる依存関係; 4) 完全なレビュー メカニズムは、特別なセキュリティ要件に固有である可能性があります; 外部 VM を使用しても、作業量はあまり節約されません。
可変の拡張可能なメモリ サイズが使用されます。固定メモリ サイズは、小さすぎても大きすぎても不必要な制約です。メモリサイズが固定の場合、メモリにアクセスするたびにアクセスが境界を超えているかどうかを確認する必要があり、明らかに効率的ではありません。
1024 呼び出しの深さの制限: メモリがオーバーフローする前に呼び出しの深さが深すぎるため、多くのプログラミング言語がクラッシュします。したがって、ブロックガス制限を制限として使用するだけでは十分ではありません。
型なし: 簡潔にするためです。ただし、DIV、SDIV、MOD、SMOD は、符号付きまたは符号なしのオペコードを使用します (オペコード ADD および MUL では、符号付きと符号なしは同等であることがわかります); ケースは単純です (例: a * b -> (a * b) / 2^32)。 a / b -> a * 2^32 / b (32 ビット長、整数定数の +、-、および *)。
校正メモ: 元の翻訳には次の段落もありますが、現在のバージョンの原文では対応する段落が削除されています。スタック サイズに制限はありません。特別な理由はありません。多くの場合、ガス オーバーヘッドとブロック ガス キャップが常に各リソースの消費量の上限として機能するため、この設計は厳密には必要ありません。
この VM の一部のオペコードの機能と目的は理解しやすいですが、理解しにくいものもあります。特別な理由をいくつか示します。
ADDMOD,MULMOD: ほとんどの場合、mulmod(a, b, c) = a * b % c ですが、楕円曲線アルゴリズムでは 32 バイトのモジュラス演算が使用され、実際には a * b % c の直接実行が行われます。 ((a * b) % 2^256) % c を実行すると、まったく異なる結果が得られます。 32 バイトの空間で 32 バイトの値の a * b % c 計算をコンセンサスで実行するのは難しく、面倒です。
SIGNEXTEND: SIGNEXTEND オペコードの目的は、大きな符号付き整数から小さな符号付き整数への型変換を容易にすることです。将来のジャストインタイム仮想マシンには、主に 32 バイトの整数を処理する長時間実行されるコードのチャンクを検出する機能が搭載される可能性があり、小さな符号付き整数は処理を高速化できるため、小さな符号付き整数が役立ちます。
SHA3: Ethereum コードでは、SHA3 は安全で高強度の可変長データ ハッシュ マッピング方法として広く使用されています。一般に、メモリを使用する場合は、悪意のある衝突を防ぐためにハッシュ関数を使用する必要があり、マークル ツリーや同様の Ethereum データ構造を検証する場合にもハッシュ関数を使用する必要があります。重要なのは、SHA256、ECRECVOR、RIPEM160 などの SHA3 に似たハッシュ関数は、オペコードの形式ではなく、疑似コントラクトの形式で含まれていることです。この目的は、それらを別のカテゴリに入れることであり、後で適切な「ネイティブ プラグイン」システムを思いついた場合、拡張オペコードを必要とせずにそのようなコントラクトをさらに追加できるようになります。
ORIGIN: ORIGIN オペコードはトランザクションの送信者によって提供され、その主な機能は、契約が支払われたガスを返せるようにすることです。
COINBASE: COINBASE の主な役割は、1) サブコインがネットワーク セキュリティに貢献できるようにすること、2) マイナーが分散型経済として機能し、シェリングコインなどのサブコンセンサス ベースのアプリケーションをセットアップできるようにすることです。
PREVHASH: PREVHASH は、半安全なランダム性のソースとして使用できます。さらに、非常に複雑な「イーサリアム ライト クライアント」の再帰構造を必要とせずに、コントラクトが前のブロックのマークル ツリー状態証明を評価できるようになります。
EXTCODESIZE,EXTCODECOPY: 主な機能は、コントラクトがテンプレートに従って他のコントラクトのコードをチェックし、他のコントラクトと対話する前にそれらをシミュレートできるようにすることです。参照: https://lesswrong.com/lw/aq9/decion_theories_a_less_wrong_primer/
JUMPDEST: ジャンプ先がいくつかのインデックスに限定されている場合 (特に、静的ジャンプは常に一定であるのに対し、動的デスティネーション ジャンプの計算量は O(log (有効なチャレンジデスティネーションの数)) である)、JIT 仮想マシンはより簡単です。埋め込む。したがって、1) 有効な変数ジャンプ先を制限する、2) 動的ジャンプではなく静的ジャンプの使用を奨励する必要があります。これら 2 つの目標を達成するために、次のルールを設定します: 1) プッシュ直後のジャンプは、別のジャンプではなくどこにでもジャンプできる; 2) 他のジャンプは JUMPDEST にのみジャンプできる。コード内の前の操作を参照して、現在のジャンプが静的ジャンプであるか動的ジャンプであるかを判断できるようにするために、ジャンプに対する制限が必要です。静的ジャンプの必要がないことが、それらを使用する動機となっています。プッシュ データへのジャンプを無効にすると、JIT VM のコンパイルと実行も高速化されます。
LOG: LOG はイベントのログです。
CALLCODE: このオペコードにより、コントラクトは独自のストレージ項目を使用して、別のスタックスペースとメモリにある他のコントラクトの「関数」を呼び出すことができます。これにより、ブロックチェーン上に標準ライブラリ コードを柔軟に実装できます。
SELFDESTRUCT: コントラクトが存在する必要がなくなった場合、コントラクト自体を削除できるようにします。 SELFDESTRUCT はすぐには実行されませんが、トランザクションの実行後に実行されます。これは、実行後に SELFDESTRUCT をロールバックできるようにすると、キャッシュの複雑さが大幅に増加し、効率的な VM 実装に役立たないためです。
元のリンク:
(以上)
元のリンク:
https://eth.wiki/en/fundamentals/design-rationale
著者: ヴィタリック
翻訳・校正:kim & A Jian


