Multi-VM Runtime
The Tenzro Virtual Machine provides a unified execution runtime supporting three distinct virtual machines: Ethereum Virtual Machine (EVM), Solana Virtual Machine (SVM), and Canton DAML. This multi-VM architecture enables cross-ecosystem smart contract deployment, transaction execution, and state management within a single blockchain infrastructure.
Architecture Overview
The multi-VM runtime is built around the MultiVmRuntime orchestrator, which routes transactions to the appropriate executor based on VM type. Each virtual machine maintains its own execution context, gas accounting model, and state management while sharing a unified storage backend through RocksDB.
VM Type Routing
Transactions include a vm_type field that determines which executor processes the transaction. The runtime performs zero-copy routing to minimize overhead during execution dispatch.
use tenzro_vm::{MultiVmRuntime, VmType};
use tenzro_types::{Transaction, Address};
// Initialize multi-VM runtime
let runtime = MultiVmRuntime::new(storage.clone());
// Execute EVM transaction
let evm_tx = Transaction {
vm_type: VmType::Evm,
from: sender_address,
to: Some(contract_address),
data: hex::decode("0xa9059cbb...")?,
gas_limit: 100_000,
gas_price: 20_000_000_000, // 20 Gwei
..Default::default()
};
let result = runtime.execute_transaction(&evm_tx).await?;
// Execute SVM transaction
let svm_tx = Transaction {
vm_type: VmType::Svm,
data: borsh::to_vec(&svm_instruction)?,
gas_limit: 200_000, // Compute units
..Default::default()
};
let result = runtime.execute_transaction(&svm_tx).await?;
// Execute DAML transaction
let daml_tx = Transaction {
vm_type: VmType::Daml,
data: serde_json::to_vec(&daml_command)?,
gas_limit: 50_000,
..Default::default()
};
let result = runtime.execute_transaction(&daml_tx).await?;Block-STM Parallel Execution
Tenzro implements Block-STM (Software Transactional Memory) for optimistic parallel transaction execution. Transactions are executed speculatively across multiple threads with automatic conflict detection and reexecution when conflicts occur.
MVCC Multi-Version Data
The Block-STM engine maintains multi-version concurrency control (MVCC) to track read and write dependencies between transactions. Each transaction operates on a versioned snapshot of state, allowing concurrent execution without blocking.
use tenzro_vm::block_stm::{BlockStmExecutor, BlockStmConfig};
let config = BlockStmConfig {
num_threads: 8,
max_reexecutions: 16,
conflict_threshold: 0.5, // 50% conflict rate triggers sequential fallback
enable_metrics: true,
};
let executor = BlockStmExecutor::new(config, storage.clone());
// Execute block of transactions in parallel
let transactions = vec![tx1, tx2, tx3, tx4, tx5];
let results = executor.execute_block(transactions).await?;
// Access execution metrics
let stats = executor.stats();
println!("Parallel executions: {}", stats.parallel_executions);
println!("Sequential executions: {}", stats.sequential_executions);
println!("Total reexecutions: {}", stats.total_reexecutions);
println!("Conflict rate: {:.2}%", stats.conflict_rate() * 100.0);Conflict Detection
When a transaction reads state that was written by a lower-indexed transaction that has not yet committed, a conflict is detected. The dependent transaction is automatically reexecuted after its dependencies commit.
Automatic Sequential Fallback: If the conflict rate exceeds 50% after multiple reexecution rounds, the executor automatically falls back to sequential execution for the remainder of the block to avoid excessive overhead.
EIP-1559 Fee Market
Tenzro implements EIP-1559 dynamic fee market mechanics with base fee adjustment, fee burning, and priority fees. The base fee adjusts by ±12.5% per block based on gas usage relative to the 15M gas target.
Base Fee Calculation
use tenzro_vm::fee_market::FeeMarket;
let mut fee_market = FeeMarket::new();
// Current block used 20M gas (above 15M target)
let parent_gas_used = 20_000_000;
let parent_gas_limit = 30_000_000;
let parent_base_fee = 1_000_000_000; // 1 Gwei
let new_base_fee = fee_market.calculate_next_base_fee(
parent_base_fee,
parent_gas_used,
parent_gas_limit,
);
println!("New base fee: {} wei", new_base_fee); // 1.125 Gwei (12.5% increase)
// Fee burning
let base_fee_burned = fee_market.calculate_base_fee_burn(
parent_gas_used,
new_base_fee,
);
println!("TNZO burned: {}", base_fee_burned);Priority Fee Suggestions
The fee market provides priority fee suggestions based on transaction urgency levels: instant, fast, normal, and economy. Priority fees are paid directly to validators as incentive for inclusion.
use tenzro_vm::fee_market::TransactionUrgency;
// Get priority fee suggestions
let instant_priority = fee_market.suggest_priority_fee(TransactionUrgency::Instant);
let fast_priority = fee_market.suggest_priority_fee(TransactionUrgency::Fast);
let normal_priority = fee_market.suggest_priority_fee(TransactionUrgency::Normal);
let economy_priority = fee_market.suggest_priority_fee(TransactionUrgency::Economy);
println!("Instant (next block): {} Gwei", instant_priority / 1_000_000_000);
println!("Fast (1-2 blocks): {} Gwei", fast_priority / 1_000_000_000);
println!("Normal (3-5 blocks): {} Gwei", normal_priority / 1_000_000_000);
println!("Economy (5+ blocks): {} Gwei", economy_priority / 1_000_000_000);
// Total fee calculation
let max_fee_per_gas = fee_market.current_base_fee() + fast_priority;
let effective_gas_price = std::cmp::min(
max_fee_per_gas,
fee_market.current_base_fee() + max_priority_fee_per_gas,
);ERC-4337 Account Abstraction
Tenzro supports ERC-4337 v0.8 account abstraction natively, enabling smart contract wallets, gas sponsorship via paymasters, and custom validation logic. User operations use the v0.8 split-field format (factory/factoryData replace initCode; paymaster/paymasterVerificationGasLimit/paymasterPostOpGasLimit/paymasterData replace paymasterAndData) with PackedUserOperation support and EIP-712 typed data hashing. The gas penalty threshold is set at 40,000.
EntryPoint Contract
The EntryPoint contract coordinates user operation validation, execution, and gas payment. It manages nonce validation, signature verification delegation, and paymaster integration.
use tenzro_vm::account_abstraction::{EntryPoint, UserOperation};
let entry_point = EntryPoint::new(entry_point_address);
// Create user operation (ERC-4337 v0.8 split fields)
let user_op = UserOperation {
sender: smart_account_address,
nonce: 0,
factory: None, // Account factory address (None if account exists)
factory_data: vec![], // Factory init data (replaces initCode)
call_data: encode_function_call("transfer", &[recipient, amount])?,
call_gas_limit: 100_000,
verification_gas_limit: 50_000,
pre_verification_gas: 21_000,
max_fee_per_gas: 20_000_000_000,
max_priority_fee_per_gas: 2_000_000_000,
paymaster: None, // Paymaster address (None if user pays)
paymaster_verification_gas_limit: 0, // Gas for paymaster validation
paymaster_post_op_gas_limit: 0, // Gas for paymaster postOp
paymaster_data: vec![], // Paymaster-specific data
signature: vec![], // Account-specific signature
};
// Validate user operation
let validation_result = entry_point.validate_user_op(&user_op, state)?;
if validation_result.is_valid {
// Execute user operation
let result = entry_point.handle_user_op(user_op, state).await?;
println!("User operation executed: {:?}", result);
}Smart Account Modules
Smart accounts support pluggable modules for social recovery, session keys, spending limits, and batch transactions. Modules extend account functionality without modifying core validation logic.
use tenzro_vm::account_abstraction::{SmartAccount, AccountModule};
use tenzro_vm::account_abstraction::modules::{
SocialRecoveryModule, SessionKeyModule, SpendingLimitModule
};
// Create smart account with modules
let mut account = SmartAccount::new(owner_address);
// Add social recovery (2-of-3 guardians)
let recovery = SocialRecoveryModule {
threshold: 2,
guardians: vec![guardian1, guardian2, guardian3],
};
account.add_module(AccountModule::SocialRecovery(recovery));
// Add session key for limited operations
let session_key = SessionKeyModule {
public_key: session_pk,
allowed_operations: vec!["transfer", "approve"],
valid_until: timestamp + 86400, // 24 hours
call_gas_limit: 100_000,
};
account.add_module(AccountModule::SessionKey(session_key));
// Add spending limit
let spending_limit = SpendingLimitModule {
daily_limit: parse_ether("100")?, // 100 TNZO/day
reset_timestamp: next_midnight,
spent_today: 0,
};
account.add_module(AccountModule::SpendingLimit(spending_limit));
// Validate operation against all modules
let is_valid = account.validate_operation(&user_op)?;Paymaster Gas Sponsorship
Paymasters enable third-party gas sponsorship, allowing applications to subsidize transaction fees for users. Paymasters validate operations and commit to paying gas costs before execution.
use tenzro_vm::account_abstraction::{Paymaster, PaymasterValidationResult};
let paymaster = Paymaster::new(paymaster_address);
// Paymaster validates user operation
let context = paymaster.validate_user_op(&user_op, state)?;
match context {
PaymasterValidationResult::Valid { context_data, valid_until } => {
// Paymaster agrees to sponsor
println!("Gas sponsored until: {}", valid_until);
// Execute operation
let result = entry_point.handle_user_op(user_op, state).await?;
// Paymaster is charged for gas
paymaster.post_operation(result.gas_used, context_data, state)?;
}
PaymasterValidationResult::Invalid(reason) => {
println!("Paymaster rejected: {}", reason);
}
}EIP-7702 EOA Delegation
EIP-7702 allows externally-owned accounts (EOAs) to temporarily delegate execution to a smart contract implementation without deploying a new contract. Users can upgrade their EOA to use spending limits, session keys, and social recovery, then revert to a normal EOA at any time.
This is complementary to ERC-4337: while 4337 creates entirely new smart contract accounts, 7702 upgrades existing EOAs in-place. The delegation setup costs a single SSTORE operation, making it significantly cheaper than deploying a new smart account.
// EIP-7702: Temporarily delegate EOA to smart account implementation
let delegation = EoaDelegation {
eoa_address: user_address,
implementation: smart_account_address,
valid_until: current_block + 1000,
};
// After delegation, the EOA can execute smart account logic
// (session keys, spending limits, batched transactions)
// without deploying a separate contractERC-4337 vs EIP-7702: Use ERC-4337 when you need a dedicated smart contract wallet with custom validation logic. Use EIP-7702 when you want to add smart account features to an existing EOA without migrating assets or changing your address.
Reentrancy Guards (EIP-1153 Transient Storage)
Tenzro precompiles use EIP-1153 transient storage for reentrancy protection. The TransientReentrancyGuard tracks which precompile addresses are currently executing. If a precompile attempts to call back into itself or into another guarded precompile, the call reverts immediately.
Transient storage is cleared automatically at the end of each transaction, so there is no persistent gas cost for the guard. This protects against recursive bridge calls, token factory reentrancy, and cross-VM bridge loops.
// Transient reentrancy guard (EIP-1153) — per-transaction, auto-clearing
let guard = TransientReentrancyGuard::new();
// Lock the TNZO Bridge precompile address during execution
guard.lock(TNZO_BRIDGE_ADDRESS)?; // Reverts if already locked
// Execute bridge logic...
execute_bridge_operation(&token, ®istry, &calldata)?;
// Guard automatically cleared at transaction end
// No persistent storage costProtected Precompiles: The reentrancy guard covers TNZO_BRIDGE (0x1001), TOKEN_FACTORY (0x1002), CROSS_VM_BRIDGE (0x1003), STAKING (0x1004), and GOVERNANCE (0x1005). Standard EVM precompiles (0x01-0x09) are stateless and do not require reentrancy protection.
Precompile Registry
Tenzro extends the EVM with custom precompiled contracts for TEE attestation, ZK proof verification, model inference, and settlement operations. Precompiles are callable at reserved addresses starting from 0x0000...0100.
| Address | Precompile | Gas Cost |
|---|---|---|
0x0100 | TEE Attestation Verify | 50,000 |
0x0101 | ZK Proof Verify | 100,000 |
0x0102 | Model Inference Request | 200,000 |
0x0103 | Settlement Execute | 75,000 |
Token Precompiles
In addition to the standard precompiles above, Tenzro provides five token-specific precompiles that enable cross-VM token operations, staking, and governance directly from smart contracts. These precompiles power the unified token architecture described in the Cross-VM Tokens documentation.
| Address | Precompile | Description |
|---|---|---|
0x1001 | TNZO_BRIDGE | Wraps and unwraps native TNZO to VM-specific representations (wTNZO ERC-20 on EVM, wTNZO SPL on SVM). Uses the pointer model so no actual bridging occurs. |
0x1002 | TOKEN_FACTORY | Creates new ERC-20 tokens and registers them in the unified token registry across all VMs. Token IDs are computed deterministically via SHA-256 of creator address and nonce. |
0x1003 | CROSS_VM_BRIDGE | Performs atomic cross-VM token transfers between EVM, SVM, and DAML. Tokens share the same underlying native balance via the TnzoToken layer with no bridge risk. |
0x1004 | STAKING | Stakes and unstakes TNZO tokens directly from smart contracts. Supports Validator, ModelProvider, and TeeProvider roles with delegated staking. |
0x1005 | GOVERNANCE | Enables on-chain governance participation from smart contracts including proposal creation, voting, and voting power queries. |
Token Registry Security
The unified token registry enforces several security invariants across all token operations:
- Deterministic TokenId: Token IDs are computed as
SHA-256(creator_address || nonce), preventing front-running attacks where an adversary could claim a token ID before the legitimate creator. - Creator authentication: Only the token creator (verified by transaction sender address) can mint the initial supply. Subsequent minting requires explicit authorization configured at creation time.
- Overflow-safe arithmetic: All balance operations use
u128checked arithmetic with explicit overflow guards, preventing wraparound exploits on large token supplies. - Atomic cross-VM transfers: When tokens move between EVM, SVM, and DAML, the debit and credit happen within the same transaction. If either side fails, the entire operation reverts with no intermediate state exposed.
- Circuit breaker integration: Per-token rate limiting detects anomalous transfer patterns (sudden volume spikes, rapid drain attempts) and can pause token operations until reviewed.
Gas Oracle
The gas oracle provides real-time gas price estimation and transaction cost calculation. It tracks historical base fees and priority fees to provide accurate predictions for different confirmation speeds.
use tenzro_vm::gas_oracle::GasOracle;
let oracle = GasOracle::new();
// Estimate gas for transaction
let estimated_gas = oracle.estimate_gas(&transaction)?;
println!("Estimated gas: {}", estimated_gas);
// Get current gas prices
let prices = oracle.gas_prices();
println!("Base fee: {} Gwei", prices.base_fee / 1_000_000_000);
println!("Slow priority: {} Gwei", prices.slow_priority / 1_000_000_000);
println!("Normal priority: {} Gwei", prices.normal_priority / 1_000_000_000);
println!("Fast priority: {} Gwei", prices.fast_priority / 1_000_000_000);
// Calculate total transaction cost
let total_cost = oracle.estimate_transaction_cost(
&transaction,
TransactionUrgency::Fast,
)?;
println!("Total cost: {} TNZO", format_ether(total_cost));State Adapter
The state adapter provides a unified interface for all VMs to interact with persistent storage. It tracks dirty state changes during transaction execution and commits them atomically upon successful completion. The StateAdapter::with_storage() constructor accepts an Arc<dyn KvStore> for RocksDB persistence. The commit() method builds a write batch and calls write_batch_sync() with fsync enabled, ensuring state survives restarts.
Gas Constants
| Constant | Value | Description |
|---|---|---|
| MAX_GAS_LIMIT | 30,000,000 | Maximum gas per transaction |
| DEFAULT_GAS_LIMIT | 10,000,000 | Default gas if not specified |
| MIN_GAS_PRICE | 1 Gwei | Minimum gas price accepted |
| TARGET_GAS_USED | 15,000,000 | EIP-1559 target per block |
| MIN_BASE_FEE | 0.1 Gwei | Minimum base fee floor |
| MAX_BASE_FEE | 1000 Gwei | Maximum base fee ceiling |
| MAX_CALL_DEPTH | 1,024 | Maximum call stack depth |
| MAX_CONTRACT_SIZE | 24,576 bytes | Maximum contract bytecode size |
| BLOCK_STM_MAX_REEXEC | 16 | Max reexecution attempts |
| CONFLICT_THRESHOLD | 50% | Sequential fallback trigger |
| AA_MAX_BUNDLE_SIZE | 100 | Max user ops per bundle |
Configuration
use tenzro_vm::{VmConfig, EvmConfig, SvmConfig, DamlConfig};
// Configure multi-VM runtime
let config = VmConfig {
default_gas_limit: 10_000_000,
max_gas_limit: 30_000_000,
default_chain_id: 1337,
evm_config: Some(EvmConfig {
evm_version: revm::EvmVersion::London,
enable_precompiles: true,
max_code_size: 24576,
}),
svm_config: Some(SvmConfig {
compute_budget: 1_400_000,
enable_syscalls: true,
max_account_data_size: 10_485_760, // 10 MB
}),
daml_config: Some(DamlConfig {
canton_endpoint: "http://localhost:5011".to_string(),
max_command_size: 1_048_576, // 1 MB
timeout_seconds: 30,
}),
};
let runtime = MultiVmRuntime::with_config(config, storage)?;Production Readiness
Production-Ready Components:
- EVM executor with full revm integration
- SVM executor with solana_rbpf BPF execution
- DAML executor with real Canton gRPC client
- Block-STM parallel execution with MVCC
- EIP-1559 fee market with base fee adjustment
- ERC-4337 account abstraction (EntryPoint, modules, paymasters)
- EIP-7702 EOA delegation to smart account implementations
- EIP-1153 transient reentrancy guards on all token precompiles
- Gas metering with overflow checks
Additional Production-Ready Components:
- RocksDB-backed state adapter with fsync on commit
- All 9 standard EVM precompiles per EIP specs (ecRecover, SHA-256, RIPEMD-160, Identity, ModExp, EC_ADD, EC_MUL, EC_PAIRING, BLAKE2F)
- Tenzro-specific precompiles wired to real TEE and ZK subsystems
- Transaction signature verification before execution
- Gas refunds with EIP-3529 cap (20% of used gas)
- Nonce validation with cross-chain replay protection
- 30-second execution timeout via tokio::time::timeout
- 128 KB transaction data size limit
- Token registry with deterministic IDs, creator auth, and overflow-safe u128 arithmetic
- Atomic cross-VM token transfers with circuit breaker rate limiting