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&nbsp;more&nbsp;➔](/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.