この記事は、Geth ソースコード シリーズの最初の記事です。このシリーズを通じて、Geth の実装を研究するためのフレームワークを構築します。開発者はこのフレームワークを使用して、興味のある部分を詳しく調べることができます。このシリーズは 6 つの記事で構成されています。最初の記事では、実行層クライアント Geth の設計アーキテクチャと Geth ノードの起動プロセスについて説明します。 Geth コードは非常に頻繁に更新されるため、後で表示されるコードは異なる場合がありますが、全体的な設計は概ね一貫しており、新しいコードも同じ考え方で読み取ることができます。
01\イーサリアムクライアント
Ethereum が Merge アップグレードを実行する前は、トランザクションの実行とブロックチェーンのコンセンサスに責任を持ち、ブロックチェーンが特定の順序で新しいブロックを生成することを保証するクライアントが 1 つしかありませんでした。 Merge アップグレード後、Ethereum クライアントは実行レイヤーとコンセンサス レイヤーに分割されます。実行層はトランザクションの実行、ステータスおよびデータの維持を担当し、コンセンサス層はコンセンサス機能の実装を担当します。実行層とコンセンサス層は API を介して通信します。実行層とコンセンサス層にはそれぞれ独自の仕様があります。クライアントはさまざまな言語を使用して実装できますが、対応する仕様に準拠する必要があります。 Geth は実行層クライアントの実装です。現在主流の実行レイヤーとコンセンサスレイヤーのクライアントは次のように実装されています。
実行層
- Geth: Ethereum Foundationから直接資金提供を受けたチームによって維持され、Goで開発されており、最も安定しており、実績のあるクライアントとして認められています。
- Nethermind: Nethermindチームによって開発・保守され、C#で開発され、初期段階ではEthereum FoundationとGitcoinコミュニティによって資金提供された。
- Besu: 元々はConsenSysのPegaSysチームによって開発され、現在はHyperledgerコミュニティプロジェクトでJavaで開発されている。
- Erigon: Ethereum Foundation と BNB Chain の資金提供を受けて、Erigon チームによって開発および保守されています。 2017年にGethからフォークされ、同期速度とディスク効率を向上させることを目指しています。
- Reth: Paradigm 社が開発し、開発言語として Rust を使用し、モジュール性と高パフォーマンスを重視しています。今では成熟しており、実稼働環境で使用できます。
コンセンサスレイヤー
- Prysm: Prysmatic Labs によって管理されており、Ethereum の最も初期のコンセンサス レイヤー クライアントの 1 つです。 Go 言語で開発され、使いやすさとセキュリティに重点を置いており、初期には Ethereum Foundation から資金提供を受けていました。
- Lighthouse: Sigma Prime チームによって管理され、Rust で開発され、高負荷のシナリオに適した高性能とエンタープライズ レベルのセキュリティに重点を置いています。
- Teku: ConsenSysのPegaSysチームによって開発され、後にJava言語を使用してHyperledger Besuコミュニティの一部となった。
- Nimbus: Status Network チームによって開発および保守され、Nim 言語を使用して、リソースが制限されたデバイス (携帯電話や IoT デバイスなど) 向けに最適化され、組み込みシステムでの軽量な操作を実現することを目的としています。
02\エグゼクティブレベル入門
Ethereum 実行層は、トランザクション駆動型のステートマシンとして考えることができます。実行層の最も基本的な機能は、EVM を介してトランザクションを実行して状態データを更新することです。トランザクションの実行に加えて、ブロックとステータスデータの保存と検証、P2Pネットワークの実行、トランザクションプールの維持などの機能もあります。
トランザクションは、Ethereum 実行層仕様で定義された形式でユーザー (またはプログラム) によって生成されます。ユーザーはトランザクションに署名する必要があります。トランザクションが合法である場合(Nonce が継続的、署名が正しく、ガス料金が十分、ビジネス ロジックが正しい)、トランザクションは最終的に EVM によって実行され、それによって Ethereum ネットワークのステータスが更新されます。ここでの状態は、外部アカウント アドレス、コントラクト アドレス、アドレス残高、コード、データなど、データ構造、データ、データベースの集合を指します。
実行層はトランザクションの実行とトランザクション実行後のステータスの維持を担当し、コンセンサス層は実行するトランザクションの選択を担当します。 EVM はこのステート マシン内の状態遷移関数です。関数の入力は複数の場所から行われる場合があります。これは、コンセンサス レイヤーによって提供される最新のブロック情報から取得される場合もあれば、P2P ネットワークからダウンロードされたブロックから取得される場合もあります。
コンセンサス レイヤーと実行レイヤーは、エンジン API を介して通信します。これは、実行レイヤーとコンセンサス レイヤー間の唯一の通信方法です。コンセンサス レイヤーがブロックを生成する権利を取得した場合、エンジン API を通じて実行レイヤーに新しいブロックを生成するように要求します。ブロック生成権を取得できない場合は、実行層が検証・実行できるように最新のブロックを同期し、イーサリアムネットワーク全体でのコンセンサスを維持します。
実行層は論理的に 6 つの部分に分けられます。
- EVM: トランザクションの実行を担当します。トランザクション実行は、状態番号を変更する唯一の方法でもあります。
- ストレージ: 状態、ブロック、その他のデータの保存を担当します
- トランザクションプール: ユーザーが送信したトランザクションを一時的に保存し、P2Pネットワークを通じて異なるノード間で伝播するために使用されます。
- p2p ネットワーク: ノードの検出、トランザクションの同期、ブロックのダウンロードなどに使用されます。
- RPCサービス: ユーザーがノードにトランザクションを送信するなど、ノードにアクセスする機能や、コンセンサス層と実行層間の相互作用を提供する。
- BlockChain: Ethereumのブロックチェーンデータの管理を担当
次の図は、実行層の主要なプロセスと各部分の機能を示しています。
実行層(ここではフルノードについてのみ説明します)には、3 つの主要なプロセスがあります。
- Ethereum に参加する新しいノードの場合は、P2P ネットワークを介して他のノードからのブロックとステータス データを同期する必要があります。 Full Sync の場合は、ジェネシス ブロックからブロックを 1 つずつダウンロードし、ブロックを検証して、EVM を通じてステータス データベースを再構築します。 Snap Sync の場合は、ブロック検証プロセス全体をスキップし、最新のチェックポイント ステータス データと後続のブロック データを直接ダウンロードします。
- 最新の状態に同期されたノードであれば、エンジンAPIを介してコンセンサス層から最新の出力ブロックを取得し、ブロックを検証した後、EVMを介してブロック内のすべてのトランザクションを実行し、状態データベースを更新してブロックをローカルチェーンに書き込み続けます。
- ノードが最新の状態に同期され、コンセンサス レイヤーがブロックを生成する権利を取得した場合、コンセンサス レイヤーはエンジン API を通じて実行レイヤーに最新のブロックを生成するよう指示します。実行層はトランザクション プールからトランザクションを取得して実行し、ブロックに組み立てて、エンジン API を介してコンセンサス層に渡します。コンセンサス レイヤーは、ブロックをコンセンサス レイヤー P2P ネットワークにブロードキャストします。
03\ソースコードの構造
go-ethereum のコード構造は巨大ですが、その多くは補助コードと単体テストに属しています。 Geth のソースコードを調べるときは、プロトコルのコア実装にのみ焦点を当てる必要があります。各モジュールの機能は以下のとおりです。 core、eth、ethdb、node、p2p、rlp、trie、tridb モジュールに注目する必要があります。
- アカウント: 公開鍵と秘密鍵のペアの生成、署名の検証、アドレスの導出など、Ethereum アカウントを管理します。
- ビーコン: Ethereumビーコンチェーンとの相互作用ロジックを処理し、Proof of Stake(PoS)コンセンサスのポストマージ機能をサポートします。
- ビルド: ビルドスクリプトとコンパイル構成 (Dockerfile、クロスプラットフォームコンパイルのサポートなど)
- cmd: 複数のサブコマンドを含むコマンドラインツールのエントリ
- 共通: バイト処理、アドレス形式の変換、数学関数などの一般的なツールクラス
- コンセンサス: 以前の作業証明 (Ethash)、単一マシンのステーク証明 (Clique)、ビーコン エンジンなどを含むコンセンサス エンジンを定義します。
- コンソール: ユーザーがコマンドラインを通じて Ethereum ノードと直接対話できる対話型 JavaScript コンソールを提供します (Web3 API の呼び出し、アカウントの管理、ブロックチェーン データのクエリなど)
- core: ブロック/トランザクション、ステートマシン、ガス計算などのライフサイクル管理を処理するブロックチェーンのコアロジック。
- 暗号: 楕円曲線(secp256k1)、ハッシュ(Keccak-256)、署名検証を含む暗号化アルゴリズムの実装
- docs: ドキュメント(設計仕様、APIの説明など)
- eth: ノード サービス、ブロック同期 (高速同期、アーカイブ モードなど)、トランザクション ブロードキャストなどを含む、Ethereum ネットワーク プロトコルの完全な実装。
- ethclient: Ethereum クライアント ライブラリを実装し、Go 開発者が Ethereum ノードと対話するための JSON-RPC インターフェースをカプセル化します (ブロックのクエリ、トランザクションの送信、契約のデプロイなど)。
- ethdb: データベース抽象化レイヤー。LevelDB、Pebble、メモリデータベースなどをサポートし、ブロックチェーンデータ(ブロック、ステータス、トランザクション)を保存します。
- ethstats: ノードの動作ステータスを収集して統計サービスに報告し、ネットワークの健全性を監視します。
- イベント: イベントサブスクリプションおよびパブリッシングメカニズムを実装し、ノード内のモジュール間の非同期通信をサポートします(新しいブロックの到着、トランザクションプールの更新など)。
- graphql: GraphQL インターフェースを提供し、複雑なクエリをサポートします (一部の JSON-RPC 関数を置き換えます)
- 内部: 外部からのアクセスが制限された内部ツールまたはコード
- ログ: ログシステム。階層的なログ出力とコンテキストログ記録をサポートします。
- mertrics: パフォーマンス メトリックの収集 (Prometheus でサポート)
- マイナー: マイニング関連のロジック、新しいブロックの生成、トランザクションのパッケージ化(PoWシナリオの場合)
- ノード: ノードサービス管理、P2P、RPC、データベース、その他のモジュールの起動と構成を統合
- p2p: ピアツーピアネットワークプロトコルの実装。ノード検出、データ転送、暗号化通信をサポート。
- params: Ethereum ネットワークパラメータを定義します (メインネット、テストネット、ジェネシスブロック構成)
- rlp: ブロックやトランザクションなどのデータ構造をエンコード/デコードするために使用される、Ethereum専用のデータシリアル化プロトコルRLP(再帰長さプレフィックス)を実装します。
- rpc: 外部プログラムがノードと対話するための JSON-RPC および IPC インターフェースを実装します。
- 署名者: トランザクション署名管理(ハードウェアウォレット統合)
- テスト: プロトコルの互換性を確認するための統合テストとステータステスト
- trie & triedb: アカウントステータスと契約書の効率的な保存と管理のためのMerkle Patricia Trie実装
04\実行層モジュール分割
Geth ノードに外部からアクセスする方法は 2 つあります。1 つは RPC 経由、もう 1 つはコンソール経由です。 RPC は外部ユーザーに適しており、コンソールはノード マネージャーに適しています。ただし、RPC 経由かコンソール経由かに関係なく、それらはすべて、階層化されて構築された内部的にカプセル化された機能を使用します。
最も外側の層は、ノードのさまざまな機能への外部アクセス用の API です。エンジン API は、実行層とコンセンサス層間の通信に使用されます。 Eth API は、外部のユーザーまたはプログラムがトランザクションを送信し、ブロック情報を取得するために使用されます。 Net API は、P2P ネットワークの状態などを取得するために使用されます。たとえば、ユーザーが API を介してトランザクションを送信すると、そのトランザクションは最終的にトランザクション プールに送信され、トランザクション プールによって管理されます。別の例として、ユーザーがデータのブロックを取得する必要がある場合、対応するブロックを取得するにはデータベースの機能を呼び出す必要があります。
API の次のレイヤーは、トランザクション プール、トランザクションのパッケージ化、ブロック出力、ブロックとステータスの同期などのコア機能の実装です。これらの機能は、より低レベルの機能に依存する必要があります。たとえば、トランザクション プール、ブロック、状態の同期は、P2P ネットワークの機能に依存する必要があります。ブロックの生成および他のノードから同期されたブロックは、ローカル データベースに書き込む前に検証する必要があります。これらには、EVM とデータ ストレージの機能が必要です。
実行層のコアデータ構造
イーサリアム
eth/backend.go の Ethereum 構造は、Ethereum プロトコル全体の抽象化であり、基本的に Ethereum の主要コンポーネントが含まれていますが、EVM は例外です。トランザクションが処理されるたびにインスタンス化されるため、ノード全体で初期化する必要はありません。以下のテキストにおける Ethereum はこの構造を指します。
type Ethereum struct { // Ethereum 構成(チェーン構成を含む)config *ethconfig.Config // トランザクション プール。ユーザーのトランザクションは送信後にトランザクション プールに送られます。txPool *txpool.TxPool // ローカル トランザクションの追跡と管理に使用されます。localTxTracker *locals.TxTracker // ブロックチェーン構造blockchain *core.BlockChain // Ethereum ノードのネットワーク層のコア コンポーネントであり、ブロックの同期、トランザクションのブロードキャストと受信、ピア ノード接続の管理など、他のノードとのすべての通信を処理します。handler *handler // ノードの検出とノード ソースの管理を担当します。discmix *enode.FairMix // ブロックチェーン データの永続的なストレージを担当します。chainDb ethdb.Database // さまざまな内部イベントの公開とサブスクリプションの処理を担当します。eventMux *event.TypeMux // コンセンサス エンジンengine consensus.Engine // ユーザー アカウントとキーの管理accountManager *accounts.Manager // ログ フィルターとブロック フィルターの管理filterMaps *filtermaps.FilterMaps // ノードがシャットダウンされたときにリソースが適切にクリーンアップされるように、filterMaps チャネルを安全に閉じるために使用されますcloseFilterMaps chan chan struct{} // RPC API のバックエンド サポートを提供しますAPIBackend *EthAPIBackend // PoS では、コンセンサス エンジンと連携してブロックを検証しますminer *miner.Miner // ノードが受け入れる最小ガス価格gasPrice *big.Int // ネットワーク ID networkID uint64 // ネットワーク関連の RPC サービスを提供して、RPC を介してネットワーク ステータスを照会できるようにしますnetRPCService *ethapi.NetAPI // P2P ネットワーク接続を管理し、ノードの検出と接続の確立を処理し、基盤となるネットワーク転送機能を提供しますp2pServer *p2p.Server // 変更可能なフィールドへの同時アクセスを保護しますlock sync.RWMutex // ノードが正常にシャットダウンされたかどうかを追跡し、異常なシャットダウン後の回復を支援しますTracker *shutdowncheck.ShutdownTracker }
ノード
node/node.go の Node は、もう 1 つのコア データ構造です。コンテナとして、さまざまなサービスの動作の管理と調整を担当します。次の構造では、ライフサイクル フィールドに注意する必要があります。ライフサイクルは、内部関数のライフサイクルを管理するために使用されます。たとえば、上記の Ethereum 抽象化では、ライフサイクルの開始と登録に Node に依存する必要があります。これにより、特定の機能をノード抽象化から分離し、アーキテクチャ全体のスケーラビリティを向上させることができます。このノードは、devp2p 内のノードと区別する必要があります。
type Node struct { eventmux *event.TypeMux config *Config // アカウントマネージャ。ウォレットとアカウントの管理を担当します。 accman *accounts.Manager log log.Logger keyDir string keyDirTemp bool dirLock *flock.Flock stop chan struct{} // p2pネットワークインスタンス server *p2p.Server startStopLock sync.Mutex // 追跡ノードのライフサイクルステータス(初期化、実行中、クローズ) state int lock sync.Mutex // 登録されているすべてのバックエンド、サービス、および補助サービス lifecycles []Lifecycle // 現在提供されているAPIリスト rpcAPIs []rpc.API // RPCに提供されるさまざまなアクセス方法 http *httpServer ws *httpServer httpAuth *httpServer wsAuth *httpServer ipc *ipcServer inprocHandler *rpc.Server databases map[*closeTrackingDB]struct{} }
イーサリアムの実行層を抽象的な次元から見ると、世界コンピュータとしてのイーサリアムには、ネットワーク、コンピューティング、ストレージの 3 つの部分が必要です。次に、Ethereum 実行層でこれらの 3 つの部分に対応するコンポーネントは次のとおりです。
- ネットワーク: devp2p
- 計算: EVM
- ストレージ: ethdb
devp2p
Ethereum は本質的に分散システムであり、各ノードは P2P ネットワークを通じて他のノードに接続されます。 Ethereum における p2p ネットワーク プロトコルの実装は devp2p です。
devp2p には 2 つのコア機能があります。1 つはノード検出で、これによりノードはネットワークにアクセスするときに他のノードとの接続を確立できるようになります。もう 1 つはデータ転送サービスで、ノードが他のノードと接続を確立した後にデータを交換できるようにします。
p2p/enode/node.go の Node 構造は p2p ネットワーク内のノードを表します。enr.Record 構造には、ID 情報 (ノード ID で使用される署名アルゴリズムと公開キー)、ネットワーク情報 (IP アドレス、ポート番号)、サポートされているプロトコル情報 (eth/68 および snap プロトコルのサポートなど)、およびその他のカスタム情報を含むノードの詳細のキーと値のペアが格納されます。この情報は RLP でエンコードされます。具体的な仕様は eip-778 で定義されています。
type Node struct { // ノードレコード。ノードのさまざまなプロパティが含まれます。enr.Record // ノードの一意の識別子。長さは 32 バイトです。id ID // ホスト名。ノードの DNS 名を追跡します。hostname string // ノードの IP アドレス。ip netip.Addr // UDP ポート udp uint16 // TCP ポート tcp uint16 }// enr.Recordtype Record struct { // シーケンス番号 seq uint64 // 署名 signature []byte // RLP でエンコードされたレコード raw []byte // すべてのキーと値のペアのソートされたリスト pairs []pair }
p2p/discover/table.go のテーブル構造は、devp2p ノード検出プロトコルのコア データ構造です。 Kademlia に似た分散ハッシュ テーブルを実装し、ネットワーク内のノード情報を維持および管理するために使用されます。
printf("type Table struct { mutex sync.Mutex // 距離で既知のノードをインデックスします buckets [nBuckets]*bucket // ブートノードナーサリ []*enode.Node rand reseedingRandom ips netutil.DistinctNetSet revalidation tableRevalidation // 既知のノードのデータベース db *enode.DB net transport cfg Config log log.Logger // ネットワーク内のさまざまなイベントを定期的に処理します refreshReq chan chan struct{} revalResponseCh chan revalidationResponse addNodeCh chan addNodeOp addNodeHandled chan bool trackRequestCh chan trackRequestOp initDone chan struct{} closeReq chan struct{} closed chan struct{} // ノードを追加および削除するためのインターフェイス nodeAddedHook func(*bucket, *tableNode) nodeRemovedHook func(*bucket, *tableNode)} world!");
ethdb
ethdb は、Ethereum データ ストレージの抽象化を完了し、統合されたストレージ インターフェイスを提供します。基礎となるデータベースは、leveldb、pebble、またはその他のデータベースにすることができます。インターフェース レベルで統一されている限り、多くの拡張機能が存在できます。
一部のデータ (ブロック データなど) は、ethdb インターフェイスを介して基盤となるデータベースに直接読み書きできます。その他のデータ ストレージ インターフェイスは、ethdb に基づいて構築されます。たとえば、データベース内のデータの大部分はステータス データです。このデータは MPT 構造に整理されます。 Geth における対応する実装は trie です。ノードの操作中に、トライデータは多くの中間状態を生成します。これらのデータを直接呼び出して ethdb を読み書きすることはできません。これらのデータと中間状態を管理し、最終的に ethdb を通じて永続化するには、Triedb が必要です。
基盤となるデータベースの読み取りおよび書き込み機能のインターフェースは ethdb/database.go で定義されていますが、具体的な実装は含まれていません。具体的な実装は、異なるデータベース自体によって実装されます。たとえば、leveldb または pebble データベース。データベースには 2 層のデータ読み取りおよび書き込みインターフェースが定義されており、KeyValueStore インターフェースは、最新のブロックやステータスなど、頻繁に変更される可能性のあるアクティブなデータを格納するために使用されます。AncientStore は、一度書き込まれるとほとんど変更されない履歴ブロック データを処理するために使用されます。
//データベースタイプの最上位インターフェース データベースインターフェース { KeyValueStore AncientStore} //KVデータ型の読み取りおよび書き込みインターフェース KeyValueStoreインターフェース { KeyValueReader KeyValueWriter KeyValueStater KeyValueRangeDeleter Batcher Iteratee Compacter io.Closer} //古いデータ型の読み取りおよび書き込みインターフェース AncientStoreインターフェース { AncientReader AncientWriter AncientStater io.Closer}
EVM
EVM は、Ethereum ステート マシンの状態遷移関数です。すべての状態データの更新は EVM を通じてのみ実行できます。 p2p ネットワークはトランザクションとブロック情報を受信でき、これらは EVM によって処理された後、状態データベースの一部になります。 EVM は基盤となるハードウェアの違いをマスクし、異なるプラットフォーム上の EVM でプログラムを実行しても一貫した結果を生成できるようにします。これは非常に成熟した設計アプローチであり、Java 言語の JVM も同様の設計になっています。
EVM の実装には 3 つの主要コンポーネントがあります。 core/vm/evm.go の EVM 構造は、実行コンテキスト、状態データベースの依存関係など、EVM の全体的な構造と依存関係を定義します。core/vm/interpreter.go の EVMInterpreter 構造は、EVM バイトコードの実行を担当するインタープリタの実装を定義します。 core/vm/contract.go の Contract 構造は、呼び出し元、コントラクト コード、入力など、コントラクト呼び出しの特定のパラメータをカプセル化し、現在のすべてのオペコードは core/vm/opcodes.go で定義されています。
// EVMtype EVM struct { // ブロックコンテキスト(ブロック関連情報を含む)Context BlockContext // トランザクションコンテキスト(トランザクション関連情報を含む)TxContext // アカウントステータスへのアクセスと変更に使用される状態データベースStateDB StateDB // 現在の呼び出し深度 depth int // チェーン構成パラメータchainConfig *params.ChainConfig chainRules params.Rules // EVM構成Config Config // バイトコードインタープリターinterpreter *EVMInterpreter // 中止フラグabort atom.Bool callGasTemp uint64 // プリコンパイル済みコントラクトマッピングprecompiles map[common.Address]PrecompiledContract jumpDests map[common.Hash]bitvec }type EVMInterpreter struct { // EVMインスタンスを指すevm *EVM // オペコードジャンプtabletable *JumpTable // Keccak256 hasherインスタンス(opcodeshasher間で共有)crypto.KeccakState // Keccak256ハッシュ結果bufferhasherBuf common.Hash // Is it読み取り専用モードですか?読み取り専用モードではステータスの変更は許可されませんreadOnly bool // 後続の再利用のために最後の CALL のデータを返しますreturnData []byte }type Contract struct { // 呼び出し元アドレスcaller common.Address // コントラクト アドレスaddress common.Address jumpdests map[common.Hash]bitvec analysis bitvec // コントラクト バイトコードCode []byte // コード hashCodeHash common.Hash // 呼び出し inputInput []byte // コントラクトかどうかdeploymentIsDeployment bool // システム呼び出しかどうかIsSystemCall bool // 利用可能な gasGas uint64 // 呼び出しにアタッチされた ETH の量value *uint256.Int }
その他のモジュール実装
実行層の機能は階層的に実装されており、他のモジュールや機能はこれら 3 つのコア コンポーネントに基づいて構築されます。ここにいくつかのコアモジュールがあります。
eth/protocols の下には、現在の Ethereum p2p ネットワーク サブプロトコルの実装があります。 devp2p 上に構築された eth/68 および snap サブプロトコルがあります。
eth/68 は Ethereum のコア プロトコルです。プロトコル名は eth で、68 はそのバージョン番号です。そして、このプロトコルに基づいて、トランザクション プール (TxPool)、ブロック同期 (Downloader)、トランザクション同期 (Fetcher) などの機能が実装されます。スナップ プロトコルは、新しいノードがネットワークに参加したときにブロックとステータス データをすばやく同期するために使用されます。これにより、新しいノードの起動にかかる時間が大幅に短縮されます。
ethdb は、基盤となるデータベースの読み取りおよび書き込み機能を提供します。 Ethereum プロトコルには複雑なデータ構造が多数あるため、ethdb を介してこれらのデータを直接管理することは不可能です。そのため、ブロックと状態データをそれぞれ管理するために、rawdb と statedb が ethdb に実装されています。
EVM はすべての主要なプロセスを実行します。ブロック構築でもブロック検証でも、トランザクションを実行するには EVM が必要です。
05\Gethノードの起動プロセス
Geth の起動は 2 つの段階に分かれています。最初の段階では、ノードを起動するために必要なコンポーネントとリソースを初期化します。第 2 段階では、ノードを正式に起動し、外部サービスを提供します。
ノードの初期化
geth ノードを起動するときには、次のコードが関係します。
各モジュールの初期化は次のとおりです。
- cmd/geth/main.go: geth ノードの起動エントリ
- cmd/geth/config.go (makeFullNode): 設定を読み込み、ノードを初期化します
- node/node.go: Ethereumノードを初期化するためのコアコンテナ
- node.rpcstack.go: RPCモジュールを初期化する
- accounts.manager.go: accountManager を初期化する
- eth/backend.go: Ethereumインスタンスを初期化する
- node/node.go OpenDatabaseWithFreezer:chaindb の初期化
- eth/ethconfig/config.go: コンセンサスエンジンインスタンスを初期化します(ここでのコンセンサスエンジンは実際にはコンセンサスに参加せず、コンセンサス層の結果を検証し、バリデーターの引き出しリクエストを処理するだけです)
- core/blockchain.go: ブロックチェーンを初期化する
- core/filterMaps.go: フィルターマップを初期化する
- core/txpool/blobpool/blobpool.go: BLOBトランザクションプールを初期化する
- core/txpool/legacypool/legacypool.go: 通常のトランザクションプールを初期化する
- cord/txpool/locals/tx_tracker.go: ローカル トランザクション トラッキング (ローカル トランザクション トラッキングを有効にするように設定する必要があります。ローカル トランザクションはより高い優先度で処理されます)
- eth/handler.go: プロトコルのHandlerインスタンスを初期化する
- miner/miner.go: トランザクションパッケージをインスタンス化するためのモジュール(オリジナルのマイニングモジュール)
- eth/api_backend.go: RPC サービスのインスタンス化
- eth/gasprice/gasprice.go: ガス価格クエリサービスのインスタンス化
- 内部/ethapi/api.go: P2PネットワークRPC APIをインスタンス化します
- node/node.go(RegisterAPIs): RPC APIを登録する
- node/node.go(RegisterProtocols): P2Pプロトコルを登録する
- node/node.go(RegisterLifecycle): 各コンポーネントのライフサイクルを登録する
- cmd/utils/flags.go(RegisterFilterAPI): フィルター RPC API を登録する
- cmd/utils/flags.go(RegisterGraphQLService): GraphQL RPC API を登録する (設定されている場合)
- cmd/utils/flags.go(RegisterEthStatsService): EthStats RPC API を登録する (設定されている場合)
- eth/catalyst/api.go: エンジン API を登録する
ノードの初期化はcmd/geth/config.goのmakeFullNodeで完了し、次の3つのモジュールの初期化に重点が置かれます。
最初のステップでは、node/node.go 内のノード構造 (ノード コンテナー全体) が初期化されます。すべての関数はこのコンテナ内で実行する必要があります。 2 番目のステップでは、Ethereum のさまざまなコア機能の実装を含む Ethereum 構造を初期化します。 Ethereum も Node に登録する必要があります。 3 番目のステップは、Node に Engine API を登録することです。
ノードの初期化では、ノード インスタンスを作成し、外部に公開される p2p サーバー、アカウント管理、および http プロトコル ポートを初期化します。
Ethereum の初期化ははるかに複雑で、コア機能のほとんどはここで初期化されます。まず、ethdb が初期化され、チェーン構成がストレージから読み込まれます。次にコンセンサス エンジンが作成されます。ここでのコンセンサス エンジンはコンセンサス操作を実行せず、コンセンサス レイヤーによって返された結果のみを検証します。コンセンサスレイヤーで出金リクエストが発生した場合、実際の出金操作もここで完了します。次に、ブロック チェーン構造とトランザクション プールを初期化します。
これらすべてが完了すると、ハンドラーが初期化されます。ハンドラーは、トランザクションの同期、ブロックのダウンロードなど、すべての P2P ネットワーク リクエストの処理エントリです。これは、Ethereum が分散型操作を実現するための重要なコンポーネントです。これらすべてが完了すると、eth/68、snap など、devp2p に基づいて実装されたいくつかのサブプロトコルが Node コンテナに登録されます。最後に、Ethereum がライフサイクルとして Node コンテナに登録され、Ethereum の初期化が完了します。
最後に、Engine API の初期化は比較的簡単で、Node に Engine API を登録するだけです。この時点で、ノードの初期化は完了です。
ノードの起動
ノードの初期化が完了したら、ノードを起動する必要があります。ノードを起動するプロセスは比較的簡単です。登録されているすべての RPC サービスとライフサイクルを開始するだけで、ノード全体が外部にサービスを提供できるようになります。
06\まとめ
Ethereum の実行層の実装を深く理解する前に、Ethereum を全体的に理解する必要があります。 Ethereum 全体は、トランザクション駆動型のステートマシンとみなすことができます。実行層はトランザクションの実行と状態の変更を担当し、コンセンサス層は実行層の実行を制御し、実行層によるブロックの生成、トランザクションの順序の決定、ブロックへの投票、ブロックの最終的な確定などを可能にします。このステート マシンは分散化されているため、状態データの一貫性を共同で維持するには、P2P ネットワークを介して他のノードと通信する必要があります。
実行層はトランザクションの順序を決定する役割を担わず、トランザクションの実行とトランザクション実行後のステータスの変化の記録のみを担当します。ここには 2 つの形式のレコードがあります。 1 つはすべてのステータスの変更をブロックの形式で記録することであり、もう 1 つは現在のステータスをデータベースに記録することです。同時に、実行層はトランザクションのエントリ ポイントでもあり、トランザクション プールは、まだブロックにパッケージ化されていないトランザクションを格納するために使用されます。他のノードがブロック、ステータス、トランザクション データを取得する必要がある場合、実行層は P2P ネットワークを介してこの情報を送信します。
実行層には、コンピューティング、ストレージ、ネットワークという 3 つのコア モジュールがあります。計算は EVM の実装に対応し、ストレージは ethdb の実装に対応し、ネットワークは devp2p の実装に対応します。この全体的な理解があれば、具体的な詳細に迷うことなく、各サブモジュールをより深く理解することができます。
07\参照
[1]https://ethereum.org/zh/what-is-ethereum/
[2]https://epf.wiki/#/wiki/protocol/architecture
[3]https://clientdiversity.org/#distribution
[4]https://github.com/ethereum/devp2p
[5]https://github.com/ethereum/execution-specs
[6]https://github.com/ethereum/consensus-specs
・終わり・
目次 |レイ
編集と書式設定 |歓歓
デザイン |デイジー