lmittmann / w3

Enhanced Ethereum Integration for Go
http://w3.cool
MIT License
179 stars 32 forks source link

feature request: API to persist local changes alongside contracts/storage fetched from RPC #162

Closed 0xalpharush closed 1 week ago

0xalpharush commented 3 months ago

I would like to be able to deploy contracts and interact with them, simulating a live network (block and timestamp increasing monotonically). It would be great if this were compatible with forking state from an RPC and maintaining a record of what is overridden locally

lmittmann commented 3 months ago

The BlockContext of a VM can currently only be set during creation. However, I think you can still achieve what you want using VM.{Snapshot,Rollback}.

// 1. create client to fork state with
client := w3.MustDial("http://localhost:8545")
defer client.Close()

// 2. create fetcher that always fetches form the forkBlock
forkBlock := big.NewInt(20_000_000)
fetcher := w3vm.NewRPCFetcher(client, new(big.Int).Sub(forkBlock, w3.Big1))

var snap *state.StateDB
// 3. iterate over 10 blocks starting from forkBlock
for i := range 10 {
    // 3.1. construct header for block i, you could also build your own one instead of fetching
    blockNumber := new(big.Int).Add(forkBlock, big.NewInt(int64(i)))
    var header types.Header
    if err := client.Call(
        eth.HeaderByNumber(forkBlock).Returns(&header),
    ); err != nil {
        t.Fatalf("Failed to get header %v: %v", blockNumber, err)
    }

    // 3.2. create VM with fetcher and current header
    vm, err := w3vm.New(
        w3vm.WithFetcher(fetcher),
        w3vm.WithHeader(&header),
    )
    if err != nil {
        t.Fatalf("Failed to create VM: %v", err)
    }

    // 3.3. if this is not the first block, rollback to the end-of-block state of the previous block
    if snap != nil {
        vm.Rollback(snap)
    }

    // 3.4. apply messages for the current block
    // ...

    // 3.5. snapshot the current state at the end of the block
    snap = vm.Snapshot()
}

Making the BlockContext of a VM updateable would be a nice addition, PR's welcome.