Parallel Execution
Metis Parallel Executor implements parallel execution of Ethereum Virtual Machine (EVM) transactions using a Block-STM mechanism. It guarantees that, under a given transaction order, the final state and outputs are deterministically consistent with serial execution. Designed for high throughput and efficiency.
Key Features
- Deterministic Parallel Execution: Ensures outputs are consistent with serial execution under a fixed order.
- Optimized Scheduler: Efficiently schedules transactions to minimize re-execution and re-validation.
- Pre-execution Analysis: Utilizes transaction dependency graphs for better conflict avoidance.
- Lock-Free Data Structures: Improves throughput by reducing lock contention.
- Multi-Versioned Memory (MVMemory): Provides STM-style isolation with per-transaction versioning of state.
Architecture Overview
Executor
- Entry point for executing a block of transactions.
- Supports serial and parallel execution modes.
- Delegates transaction scheduling, execution, validation, and finalization.
Let's imagine what happens when the node tells the ParallelExecutor to execute a block.
Step-by-Step (Simplified):
- Receive Task: The
ParallelExecutorgets the block data, including the list of transactions. - Setup Helpers: It initializes its internal machinery:
- A Scheduler to decide which transaction runs next and on which core.
- A MvMemory (Multi-Version Memory) instance to track reads/writes for conflict detection.
- Launch Workers: It spins up multiple worker threads (usually matching the number of CPU cores available). Think of these as the different lanes on our highway.
- Distribute Work: The Scheduler starts assigning transactions to available worker threads.
- Execute & Track: Each worker thread executes its assigned transaction. As it runs, it records the data it reads and the changes it wants to make in the shared MvMemory.
- Validate & Coordinate: The Scheduler and MvMemory work together. After a transaction finishes, they check if it conflicted with others (e.g., did it read stale data?).
- Handle Conflicts: If a conflict occurred, the Scheduler might tell the worker thread to discard its results and re-execute the transaction later, ensuring correctness.
- Collect Results: Once all transactions have been successfully executed and validated without conflicts, the
ParallelExecutorgathers the results (like transaction receipts and state changes) from MvMemory. - Return: The final, verified results for the entire block are returned to the node.
Sequence Diagram (Simplified Internal Flow):
Scheduler
The Scheduler has several key responsibilities:
- Task Assignment: It maintains a list of transactions that need to be processed. When a worker thread becomes free, the Scheduler gives it the next available task (usually executing a specific transaction).
- Dependency Tracking: If Transaction B depends on Transaction A, the Scheduler ensures B doesn't run until A has successfully completed. If A needs to be re-run due to a conflict, B might also need to wait or re-run.
- Status Tracking: It keeps track of the status of each transaction (e.g.,
ReadyToExecute,Executing,Executedbut needs validation,Validated,Blockingon another transaction). - Conflict Handling (Coordination): When MvMemory detects a potential conflict (e.g., a transaction read old data), the Scheduler is notified. It then decides the next steps:
- Validation: Mark a transaction as needing validation checks.
- Re-execution: If validation fails or a dependency changes, schedule the transaction (and potentially others that depend on it) to be executed again with updated information.
- Determining Completion: It knows when all transactions in a block have been successfully executed and validated, signaling that the block processing is complete.
Think of our air traffic controller:
- Task Assignment: "Plane 123, you are cleared for runway 2." (Worker 1, execute Tx5)
- Dependency Tracking: "Plane 456, hold position. Plane 123 needs to land first." (Worker 2, wait for Tx5 before starting Tx8)
- Status Tracking: Knowing which planes are taxiing, taking off, landing, or holding.
- Conflict Handling: "Plane 789, go around! Runway is not clear." (Worker 3, abort Tx10 execution and re-attempt later).
- Completion: Knowing when all scheduled flights for the hour have safely landed or taken off.
Simplified Interaction Diagram:
MVMemory
MvMemory acts as an intermediary between the parallel transactions and the actual blockchain state. It keeps track of multiple "versions" of data items (like the amount of flour) as different transactions propose changes.
Think of it like a collaborative document (like Google Docs):
- Multiple people can view the document (read state).
- Multiple people can type suggestions simultaneously (propose writes).
- The system tracks each person's changes (versions).
- If two people edit the exact same sentence at the same time, the system might flag it as a conflict that needs resolving.
MvMemory manages shared data by keeping multiple versions:
- Reading Data: When a transaction (Chef A) needs to read a piece of data (flour amount),
MvMemorylooks up the location (pantry shelf for flour). It finds the latest version written by a transaction that comes before Chef A in the original block order and has already been successfully executed (or the initial state if no one before A touched it). Chef A records which version they read. - Writing Data: When Chef A finishes and wants to update the flour amount, they don't directly change the main value. Instead, they tell
MvMemory: "I, Chef A, propose a new version for flour amount: 0.5."MvMemorystores this as a potential update associated specifically with Chef A's transaction index. - Tracking Versions:
MvMemorymaintains a history for each data location. For "flour amount", it might look like:- Initial State: 1
- Tx 5 proposes: 0.8 (after using 0.2)
- Tx 12 proposes: 0.7 (after using 0.1 based on Tx 5's version)
- Tx 7 proposes: 0.5 (after using 0.5 based on the initial state)
- Detecting Conflicts (Validation): This is crucial. Let's say Tx 7 read the "Initial State: 1" version of flour. Later, the Scheduler asks
MvMemoryto validate Tx 7.MvMemorychecks: "Did any transaction before Tx 7 (like Tx 5) write a new version of flour after Tx 7 read the initial state?" In our example, yes! Tx 5 wrote "0.8". This means Tx 7's read ("Initial State: 1") was stale by the time Tx 5 finished.MvMemoryreports this conflict back to the Scheduler, which will likely tell Tx 7 to re-execute using the correct data.
VmDB
Key Concepts of VmDB
- Database Interface:
VmDBis designed to look and feel exactly like a standard database to the EVM. It implements theDatabasetrait thatrevm(the EVM implementation used) expects. This allows it to seamlessly plug into the execution process. - State Read Interception: It sits between the EVM and the actual data sources. Every time the EVM tries to read state (e.g.,
basic(address),storage(address, index)), the request goes toVmDBfirst. - Version Resolution: When
VmDBreceives a read request (e.g., for account X's balance), it asks MvMemory: "What's the latest version of account X written by a transaction with an index lower than the one I'm currently working for?".- If
MvMemoryhas such a version,VmDBuses that value. - If
MvMemorydoesn't have a relevant version,VmDBasks the underlying, persistent blockchain database for the value.
- If
- ReadSet Tracking: Every time
VmDBsuccessfully provides a value to the EVM, it records how it got that value. Did it come fromMvMemory(and if so, which specific transaction version)? Or did it come from the underlyingStorage? This record is collected into theReadSet.