Closed 0xalpharush closed 1 week 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.
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