VM
Ethereum Virtual Machine execution environment for Ontomir SDK
The x/vm module from Ontomir evm provides a fully compatible Ethereum Virtual Machine execution environment as a Ontomir SDK module.
For conceptual understanding of EVM architecture and design, see [EVM Architecture](/docs/evm/next/documentation/concepts/overview).
Parameters
The module parameters control EVM behavior and access policies :
evm_denom
string
"atest"
Token denomination for EVM transactions (18 decimals)
extra_eips
[]int64
[]
Additional EIPs to activate beyond hard fork defaults
active_static_precompiles
[]string
[]
Activated static precompile addresses
evm_channels
[]string
[]
IBC channel IDs for EVM-compatible chains
access_control
AccessControl
Permissionless
Permission policy for EVM operations
history_serve_window
uint64
8192
Historical block hash depth for EIP-2935 (v0.5.0+)
**Breaking Change in v0.5.0:** The `allow_unprotected_txs` parameter has been removed from consensus parameters. Non-EIP155 transaction acceptance is now configured per-node in `app.toml` under `[json-rpc].allow-unprotected-txs`.
Parameter Details
Defines the token used for gas and value transfers in EVM:
Must be registered in bank module
Should have 18 decimal precision
Used for all EVM operations (gas, transfers, contracts)
Example:
"atest","aevmos","wei"
Activates additional EIPs beyond fork defaults:
1344
ChainID opcode
Minimal
1884
Repricing for trie-size-dependent opcodes
Increases SLOAD
2200
Structured definitions for net gas metering
Variable
2929
Gas cost for state access opcodes
Increases cold access
3198
BASEFEE opcode
Minimal
3529
Reduction in refunds
Reduces max refund
3855
PUSH0 instruction
New opcode
Controls EIP-2935 historical block hash storage depth:
Purpose: Enables smart contracts to access historical block hashes via BLOCKHASH opcode Range: Must be > 0, recommended ≤ 8192 for optimal performance Storage Impact: Higher values increase node storage requirements
Configuration Examples:
{
"history_serve_window": 8192 // Default: full EIP-2935 compatibility
}{
"history_serve_window": 1024 // Performance optimized: reduced storage
}{
"history_serve_window": 16384 // Extended history: maximum compatibility
}Smart Contract Usage:
contract HistoryExample {
function getRecentBlockHash(uint256 blockNumber) public view returns (bytes32) {
// Works for blocks within history_serve_window range
return blockhash(blockNumber);
}
}Granular control over contract operations:
type AccessControl struct {
Create AccessControlType // Contract deployment
Call AccessControlType // Contract execution
}Access Types:
PERMISSIONLESS: Open access, list = blacklistRESTRICTED: No access, list ignoredPERMISSIONED: Limited access, list = whitelist
Configuration Profiles
```json { "evm_denom": "atest", "extra_eips": [3855], "active_static_precompiles": [ "0x0000000000000000000000000000000000000100", "0x0000000000000000000000000000000000000400" ], "evm_channels": [], "access_control": { "create": {"access_type": "PERMISSIONLESS", "access_control_list": []}, "call": {"access_type": "PERMISSIONLESS", "access_control_list": []} }, "history_serve_window": 8192 } ``` ```json { "evm_denom": "atoken", "extra_eips": [], "active_static_precompiles": [ "0x0000000000000000000000000000000000000804" ], "evm_channels": [], "access_control": { "create": { "access_type": "PERMISSIONED", "access_control_list": ["0x1234...", "0xABCD..."] }, "call": {"access_type": "PERMISSIONLESS", "access_control_list": []} }, "history_serve_window": 4096 } ``` ```json { "evm_denom": "asecure", "extra_eips": [], "active_static_precompiles": [], "evm_channels": [], "access_control": { "create": {"access_type": "RESTRICTED", "access_control_list": []}, "call": { "access_type": "PERMISSIONED", "access_control_list": ["0xTrustedContract"] } }, "history_serve_window": 1024 } ```
Chain Configuration
Hard fork activation schedule :
homestead_block
0
Block
DELEGATECALL
byzantium_block
0
Block
REVERT, RETURNDATASIZE, STATICCALL
constantinople_block
0
Block
CREATE2, EXTCODEHASH, SHL/SHR/SAR
istanbul_block
0
Block
CHAINID, SELFBALANCE
berlin_block
0
Block
Access lists (EIP-2929, 2930)
london_block
0
Block
BASEFEE, EIP-1559
shanghai_time
0
Timestamp
PUSH0
cancun_time
0
Timestamp
Transient storage, blob transactions
prague_time
nil
Timestamp
TBD
verkle_time
nil
Timestamp
Verkle trees
Static Precompiles
Precompiled contracts at fixed addresses :
0x0000...0100
P256
3000
P256 curve verification
0x0000...0400
Bech32
5000
Bech32 address encoding
0x0000...0800
Staking
Variable
Delegation operations
0x0000...0801
Distribution
Variable
Reward claims
0x0000...0802
ICS20
Variable
IBC transfers
0x0000...0803
Vesting
Variable
Vesting account ops
0x0000...0804
Bank
Variable
Token transfers
0x0000...0805
Gov
Variable
Governance voting
0x0000...0806
Slashing
Variable
Validator slashing info
Activation
# Via genesis
{
"active_static_precompiles": [
"0x0000000000000000000000000000000000000804",
"0x0000000000000000000000000000000000000800"
]
}
# Via governance proposal
evmd tx gov submit-proposal update-params-proposal.jsonMessages
MsgEthereumTx
Primary message for EVM transactions :
message MsgEthereumTx {
google.protobuf.Any data = 1; // Transaction data (Legacy/AccessList/DynamicFee)
string hash = 3; // Transaction hash
string from = 4; // Sender address (derived from signature)
}Validation Requirements:
Valid signature matching
fromaddressSufficient balance for gas + value
Correct nonce (account sequence)
Gas limit ≥ intrinsic gas
MsgUpdateParams
Governance message for parameter updates:
message MsgUpdateParams {
string authority = 1; // Must be governance module
Params params = 2; // New parameters
}State
Persistent State
0x01
Parameters
Params
0x02
Contract code
[]byte
0x03
Contract storage
[32]byte
Transient State
0x01
Transaction logs
[]Log
Per block
0x02
Block bloom
[256]byte
Per block
0x03
Tx index
uint64
Per block
0x04
Log size
uint64
Per block
0x05
Gas used
uint64
Per tx
Events
Transaction Events
ethereum_tx
amount, recipient, contract, txHash, txIndex, txGasUsed
Every EVM transaction
tx_log
txLog (JSON)
When contracts emit events
message
sender, action="ethereum", module="evm"
Every message
Block Events
block_bloom
bloom (hex)
End of each block with EVM txs
Queries
gRPC
```protobuf service Query { // Account queries rpc Account(QueryAccountRequest) returns (QueryAccountResponse); rpc OntomirAccount(QueryOntomirAccountRequest) returns (QueryOntomirAccountResponse); rpc ValidatorAccount(QueryValidatorAccountRequest) returns (QueryValidatorAccountResponse);
// State queries
rpc Balance(QueryBalanceRequest) returns (QueryBalanceResponse);
rpc Storage(QueryStorageRequest) returns (QueryStorageResponse);
rpc Code(QueryCodeRequest) returns (QueryCodeResponse);
// Module queries
rpc Params(QueryParamsRequest) returns (QueryParamsResponse);
rpc Config(QueryConfigRequest) returns (QueryConfigResponse);
// EVM operations
rpc EthCall(EthCallRequest) returns (MsgEthereumTxResponse);
rpc EstimateGas(EthCallRequest) returns (EstimateGasResponse);
// Debugging
rpc TraceTx(QueryTraceTxRequest) returns (QueryTraceTxResponse);
rpc TraceBlock(QueryTraceBlockRequest) returns (QueryTraceBlockResponse);
// Fee queries
rpc BaseFee(QueryBaseFeeRequest) returns (QueryBaseFeeResponse);
rpc GlobalMinGasPrice(QueryGlobalMinGasPriceRequest) returns (QueryGlobalMinGasPriceResponse);}
</Expandable>
### CLI
<CodeGroup>
```bash Query-Account
# Query EVM account
evmd query vm account 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0
# Query Ontomir address
evmd query vm Ontomir-account 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0# Query balance
evmd query vm balance 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0
# Query storage slot
evmd query vm storage 0xContractAddress 0xStorageKey
# Query contract code
evmd query vm code 0xContractAddress# Query module parameters
evmd query vm params
# Query EVM config
evmd query vm config# Trace transaction
evmd query vm trace-tx 0xTxHash
# Trace block
evmd query vm trace-block 12345JSON-RPC
Supported Methods
| Method | Description | | --------------------------- | -------------------------------------------------------- | | `eth_accounts` | List accounts | | `eth_blockNumber` | Current block number | | `eth_call` | Execute call without tx | | `eth_chainId` | Get chain ID | | `eth_createAccessList` | Generate access list for tx optimization (v0.5.0+) | | `eth_estimateGas` | Estimate gas usage (optimized in v0.5.0+) | | `eth_gasPrice` | Current gas price | | `eth_getBalance` | Get account balance | | `eth_getBlockByHash` | Get block by hash | | `eth_getBlockByNumber` | Get block by number | | `eth_getCode` | Get contract code | | `eth_getLogs` | Get filtered logs | | `eth_getStorageAt` | Get storage value | | `eth_getTransactionByHash` | Get tx by hash | | `eth_getTransactionCount` | Get account nonce | | `eth_getTransactionReceipt` | Get tx receipt (enhanced with max\_used\_gas in v0.5.0+) | | `eth_sendRawTransaction` | Submit signed tx | | `eth_syncing` | Sync status | | Method | Description | | -------------------- | --------------- | | `web3_clientVersion` | Client version | | `web3_sha3` | Keccak-256 hash | | Method | Description | | --------------- | -------------------------- | | `net_version` | Network ID | | `net_listening` | Node accepting connections | | `net_peerCount` | Number of peers | | Method | Description | | -------------------------- | ---------------------------- | | `debug_traceTransaction` | Detailed tx trace | | `debug_traceBlockByNumber` | Trace all txs in block | | `debug_traceBlockByHash` | Trace all txs by hash | | `debug_getBadBlocks` | Get invalid blocks | | `debug_storageRangeAt` | Get storage range | | `debug_intermediateRoots` | Get intermediate state roots |
Hooks
Post-transaction processing interface :
type EvmHooks interface {
PostTxProcessing(
ctx sdk.Context,
msg core.Message,
receipt *ethtypes.Receipt,
) error
}Registration
// In app.go
app.EvmKeeper = app.EvmKeeper.SetHooks(
vmkeeper.NewMultiEvmHooks(
app.Erc20Keeper.Hooks(),
app.CustomKeeper.Hooks(),
),
)Use Cases
Process EVM events in Ontomir modules
Bridge EVM logs to Ontomir events
Trigger native module actions from contracts
Custom indexing and monitoring
Gas Configuration
Gas Consumption Mapping
Basic ops
3-5
3-5
1:1 mapping
SLOAD
2100
2100
Cold access
SSTORE
20000
20000
New value
CREATE
32000
32000
Contract deploy
Precompile
Variable
Variable
Set per precompile
Gas Refunds
Maximum refund: 50% of gas used (after London)
refund = min(gasUsed/2, gasRefund)
finalGasUsed = gasUsed - refundBest Practices
Chain Integration
Precompile Selection
Only enable necessary precompiles
Test gas costs in development
Monitor usage patterns
Access Control
Start restrictive, open gradually
Use governance for changes
Monitor blacklist/whitelist events
Fork Planning
{ "shanghai_time": "1681338455", // Test first "cancun_time": "1710338455" // Delay for safety }
Contract Development
Gas Optimization
// Cache storage reads uint256 cached = storageVar; // Use cached instead of storageVar // Pack structs struct Packed { uint128 a; uint128 b; // Single slot }Precompile Usage
IBank bank = IBank(0x0000000000000000000000000000000000000804); uint256 balance = bank.balances(msg.sender, "atest");
dApp Integration
Provider Setup
const provider = new ethers.JsonRpcProvider( "http://localhost:8545", { chainId: 9000, name: "evmos" } );Error Handling
try { await contract.method(); } catch (error) { if (error.code === 'CALL_EXCEPTION') { // Handle revert } }
Troubleshooting
Common Issues
"out of gas"
Insufficient gas limit
Increase gas limit or optimize contract
"nonce too low"
Stale nonce
Query current nonce, retry
"insufficient funds"
Low balance
Ensure balance > value + (gasLimit × gasPrice)
"contract creation failed"
CREATE disabled or restricted
Check access_control settings
"precompile not active"
Precompile not in active list
Enable via governance
Debug Commands
# Check EVM parameters
evmd query vm params
# Trace failed transaction
evmd query vm trace-tx 0xFailedTxHash
# Check account state
evmd query vm account 0xAddressReferences
Source Code
EVM Architecture - Conceptual overview
Fee Market Module - EIP-1559 implementation
ERC20 Module - Token conversions
最后更新于
