github.com/lmittmann/w3@v0.20.0/docs/pages/vm-overview.mdx (about) 1 # VM 2 3 <DocLink title="w3vm.VM" /> is an easy-to-use Ethereum Virtual Machine (EVM), built on top of `go-ethereum`'s `vm.EVM`. It supports **tracing**, **state forking** via RPC, and can be used for simulation, debugging EVM execution, or testing Smart Contracts. 4 5 * **State forking** via RPC or custom state fetchers enables transaction simulations or Smart Contract tests on live, or historical chain state. 6 * **Tracing** of EVM execution is supported via `go-ethereum/core/tracing.Hooks`. 7 8 9 ## Get Started 10 11 <Steps> 12 13 ### Create a VM Instance 14 15 Create a VM instance, that forks the latest Mainnet state. 16 17 ```go 18 client, err := w3.Dial("https://eth.llamarpc.com") 19 if err != nil { 20 // ... 21 } 22 defer client.Close() 23 24 vm, err := w3vm.New( 25 w3vm.WithFork(client, nil), 26 w3vm.WithNoBaseFee(), 27 ) 28 if err != nil { 29 // ... 30 } 31 ``` 32 33 ### Simulate a Simple Message 34 35 Transfer ETH from the zero address to a random recipient. 36 37 ```go 38 recipient := w3vm.RandA() 39 40 receipt, err := vm.Apply(&w3types.Message{ 41 From: common.Address{}, 42 To: &recipient, 43 Value: w3.I("1 ether"), 44 }) 45 if err != nil { 46 // ... 47 } 48 ``` 49 50 ### Verify the Recipient's Balance 51 52 Verify the recipient's balance after the applied message. 53 54 ```go 55 balance, err := vm.Balance(recipient) 56 if err != nil { 57 // ... 58 } 59 60 fmt.Printf("Balance: %s ETH\n", w3.FromWei(balance, 18)) 61 // Output: Balance: 1 ETH 62 ``` 63 64 </Steps> 65 66 67 ## Setup 68 69 A new VM instance is created using the `w3vm.New` function, which accepts various options to customize the VM behavior: 70 71 * `WithChainConfig(cfg *params.ChainConfig)`: Sets the chain configuration. If not provided, the VM defaults to the Mainnet configuration. 72 * `WithNoBaseFee()`: Forces the EIP-1559 base fee to 0. 73 * `WithBlockContext(ctx *vm.BlockContext)`: Sets the block context for the VM. 74 * `WithPrecompile(addr common.Address, contract vm.PrecompiledContract)`: Registers a precompile contract at the given address in the VM. 75 * `WithHeader(header *types.Header)`: Configures the block context for the VM using the provided header. 76 * `WithState(state w3types.State)`: Sets the pre-state of the VM. When used with `WithFork`, the pre-state overrides the forked state. 77 * `WithStateDB(db *state.StateDB)`: Specifies the state database for the VM, typically a snapshot from `VM.Snapshot`. 78 * `WithFork(client *w3.Client, blockNumber *big.Int)`: Forks state from a live Ethereum client at the specified block number. 79 * `WithFetcher(fetcher Fetcher)`: Assigns a fetcher to the VM. 80 * `WithTB(tb testing.TB)`: Enables persistent state caching when used in conjunction with `WithFork`. 81 82 83 ## Execution 84 85 Messages represent transactions or contract calls that can be executed by the VM. 86 87 <Callout type="info">All execution methods support **tracing** via `go-ethereum/core/tracing.Hooks`. [Learn more ➔](/vm-tracing) </Callout> 88 89 ### `Apply` Method 90 91 <DocLink title="Apply" id="w3vm.VM.Apply" /> applies a `w3types.Message` to the VM and returns a `Receipt`. If the execution doesn't revert, the VM's underlying state may change. 92 93 #### Example: Apply a Message 94 95 ```go 96 msg := &w3types.Message{ 97 From: addrSender, 98 To: &addrRecipient, 99 Value: w3.I("1 ether"), 100 Gas: 21000, 101 } 102 103 receipt, err := vm.Apply(msg) 104 if err != nil { 105 // ... 106 } 107 fmt.Printf("Gas Used: %d\n", receipt.GasUsed) 108 ``` 109 110 ### `ApplyTx` Method 111 112 <DocLink title="ApplyTx" id="w3vm.VM.ApplyTx" /> is like `Apply`, but takes a `types.Transaction` instead of a message. The given transaction is converted to a message internally, using a signer, that is derived from the VM's chain configuration and fork block. 113 114 ### `Call` Method 115 116 <DocLink title="Call" id="w3vm.VM.Call" /> is like `Apply`, but any state changes during execution are reverted in the end, so the VM's state is never modified. 117 118 #### Example: Call `balanceOf` 119 120 ```go 121 funcBalanceOf := w3.MustNewFunc("balanceOf(address)", "uint256") 122 123 msg := &w3types.Message{ 124 To: &addrToken, 125 Func: funcBalanceOf, 126 Args: []any{addrOwner}, 127 } 128 129 receipt, err := vm.Call(msg) 130 if err != nil { 131 // handle error 132 } 133 134 var balance *big.Int 135 if err := receipt.DecodeReturns(&balance); err != nil { 136 // handle error 137 } 138 fmt.Printf("Balance: %s\n", balance) 139 ``` 140 141 ### `CallFunc` Method 142 143 <DocLink title="CallFunc" id="w3vm.VM.CallFunc" /> is a helper, that greatly simplifies common usage of `Call`. It is designed analogues to the `eth.CallFunc` RPC client method. 144 145 #### Example: Call `balanceOf` with `CallFunc` 146 147 This is a simplified version of the [Call `balanceOf`](#example-call-balanceof) example. 148 149 ```go 150 funcBalanceOf := w3.MustNewFunc("balanceOf(address)", "uint256") 151 152 var balance *big.Int 153 err := vm.CallFunc(addrToken, funcBalanceOf, addrOwner).Returns(&balance) 154 if err != nil { 155 // handle error 156 } 157 fmt.Printf("Balance: %s\n", balance) 158 ``` 159 160 ### `Receipt` Type 161 162 The `Receipt` struct contains the result of an executed message. 163 164 #### Fields 165 166 * `GasUsed uint64`: Gas used for executing the message (including refunds). 167 * `MaxGasUsed uint64`: Maximum gas used during executing the message (excluding refunds). 168 * `Logs []*types.Log`: Logs emitted while executing the message. 169 * `Output []byte`: Output of the executed message. 170 * `ContractAddress *common.Address`: Address of the created contract, if any. 171 * `Err error`: Execution error, if any. 172 173 #### Methods 174 175 * `DecodeReturns(returns ...any) error`: Decodes the return values. This method only works, if the executed message had `w3types.Message.Func` set. 176 177 178 ## State 179 180 The VM provides methods to read, and write account state. 181 182 ### Reading State 183 184 * `vm.Balance(addr common.Address) (*big.Int, error)`: Returns the balance of the given address. 185 * `vm.Nonce(addr common.Address) (uint64, error)`: Returns the nonce of the given address. 186 * `vm.Code(addr common.Address) ([]byte, error)`: Returns the code of the given address. 187 * `vm.StorageAt(addr common.Address, slot common.Hash) (common.Hash, error)`: Returns the state of the given address at the given storage slot. 188 189 <Callout type="info"> 190 An error only can only occur, if the VM fails to fetch state via a `w3vm.Fetcher`. Thus, it is safe to ignore the error, if no state fetcher is used by the VM. 191 </Callout> 192 193 ### Writing State 194 195 * `vm.SetBalance(addr common.Address, balance *big.Int)`: Sets the balance of the given address. 196 * `vm.SetNonce(addr common.Address, nonce uint64)`: Sets the nonce of the given address. 197 * `vm.SetCode(addr common.Address, code []byte)`: Sets the code of the given address. 198 * `vm.SetStorageAt(addr common.Address, slot common.Hash, value common.Hash)`: Sets the state of the given address at the give storage slot. 199 200 201 ## Helper 202 203 * `w3vm.RandA() common.Address`: Returns a random address. 204 * `WETHBalanceSlot(addr common.Address) common.Hash`: Returns the storage slot that stores the WETH balance of the given address. 205 * `WETHAllowanceSlot(owner, spender common.Address) common.Hash`: Returns the storage slot that stores the WETH allowance of the given owner to the spender. 206 207 ### Storage Slot Calculation 208 209 Calculate storage slots for mappings. Solidity and Vyper use different parameter ordering for keccak256 hash calculation. 210 211 * `SoliditySlot(pos, key common.Hash) common.Hash`: Single mapping storage slot. 212 * `SoliditySlot2(pos, key0, key1 common.Hash) common.Hash`: Double mapping storage slot. 213 * `SoliditySlot3(pos, key0, key1, key2 common.Hash) common.Hash`: Triple mapping storage slot. 214 * `VyperSlot(pos, key common.Hash) common.Hash`: Single HashMap storage slot. 215 * `VyperSlot2(pos, key0, key1 common.Hash) common.Hash`: Double HashMap storage slot. 216 * `VyperSlot3(pos, key0, key1, key2 common.Hash) common.Hash`: Triple HashMap storage slot.