Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

EVM Bytecode Execution / StateManager: How to keep progress? #2338

Discussion options

Hi👋

Just a quick question, because I haven't seen examples in repo or in previous issues(or I was unattentive). Saying, we have an example like here:

https://github.com/ethereumjs/ethereumjs-monorepo/blob/master/packages/vm/examples/run-solidity-contract.ts

It's a good example to get started, but I can't understand how to save this progress of VM. Here, the code done execution and on the high level we have the next stuff in "blackbox"

  1. Default account in state manager after calling await vm.stateManager.putAccount(address,account) here
  2. Contract bytecode
  3. Contract state where greeting='Hola, Mundo!' after the contract function call await setGreeting(vm, accountPk, contractAddress, SECOND_GREETING)

So, what should I do to "save" this progress?

What should I do to run the vm from some "checkpoint" next time to get the second variant of greeting? StateManager has no instructions in docs. Or maybe I should play with @ethereumjs/blockchain?

Thanks in advance for your reply)

You must be logged in to vote

Hi, the key idea of this all is that to save the current state of the chain (so all accounts and contracts) is in a thing called the stateRoot. You can think of this (high-level) as a cryptographic hash of the entire chain. To checkpoint or rollback, simply save the stateRoot (to get this, use stateRoot = await vm.stateManager.getRoot()) and if you want to rollback, await vm.stateManager.setRoot(stateRoot). If you wish to persist these changes on disk, you need to instantiate a StateManager with a LevelDB which saves to disk, and pass this along the VM constructor.

Replies: 1 comment · 2 replies

Comment options

Hi, the key idea of this all is that to save the current state of the chain (so all accounts and contracts) is in a thing called the stateRoot. You can think of this (high-level) as a cryptographic hash of the entire chain. To checkpoint or rollback, simply save the stateRoot (to get this, use stateRoot = await vm.stateManager.getRoot()) and if you want to rollback, await vm.stateManager.setRoot(stateRoot). If you wish to persist these changes on disk, you need to instantiate a StateManager with a LevelDB which saves to disk, and pass this along the VM constructor.

You must be logged in to vote
2 replies
@VladChernenko
Comment options

Yes, marked as answer) Thanks for hint. For everyone who bumped with the same issue: Your should dig dive deeper. In my case, I've noticed that DefaultStateManager has a Trie instance in constructor options, but I haven't continue and get stucked. To make possible to store stateManager, pass the Trie instance to constructor(using @ethereumjs/trie). When create trie-use constructor with LevelDB as db option. Then, notice that @ethereumjs/statemanager has stuff like "checkpoint" and "commit" what means atomic ops between these methods of stateManager call. Also, as @jochem-brouwer said, get the root via await vm.stateManager.getRoot() and store somewhere.

Later,when you need to start your VM from some "checkpoint", pass the root to await vm.stateManager.setRoot(stateRoot)

Snippet

import {DefaultStateManager} from '@ethereumjs/statemanager'
import {Trie} from '@ethereumjs/trie'
import {VM} from '@ethereumjs/vm'
import {Level} from 'level'
import LevelDB from '<YOUR_IMPLEMENTATION_PATH>' //you can use my version here https://gist.github.com/VladChernenko/e4fca3622aa4a7c0cd1885b91f7977ac

//Our your own options
const common = new Common({ chain: Chain.Rinkeby, hardfork: Hardfork.Istanbul })

const trie = new Trie({
    
    db:new LevelDB(new Level('<YOUR DB>')),

    useKeyHashing:true

})

const stateManager = new DefaultStateManager({trie})

const vm = await VM.create({ common,stateManager })

await vm.stateManager.setStateRoot(Buffer.from('<32-bytes hex root which your previously store>','hex'))

//__________________ Now you can get accounts/make contracts call from checkpoint__________________ 
@holgerd77
Comment options

I think this would already be an example worth to be added to the Statemanager documentation, have added a respective issue #2356.

Answer selected by VladChernenko
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
🙏
Q&A
Labels
None yet
3 participants
Converted from issue

This discussion was converted from issue #2334 on October 07, 2022 15:37.

Morty Proxy This is a proxified and sanitized view of the page, visit original site.