# State

The x/evm module keeps the following objects in state:

Key Value
Block Height []byte{1} + []byte(block.Hash) BigEndian(block.Height)
Bloom []byte{2} + []byte(block.Height) []byte(Bloom)
Tx Logs []byte{3} + []byte(tx.Hash) amino([]Log)
Account Code []byte{4} + []byte(code.Hash) []byte(Code)
Account Storage []byte{5} + []byte(address) + []byte(state.Key) []byte(state.Value)
Chain Config []byte{6} amino(ChainConfig)

# CommitStateDB

StateDBs within the ethereum protocol are used to store anything within the IAVL tree. StateDBs take care of caching and storing nested states. It's the general query interface to retrieve contracts and accounts

The Ethermint CommitStateDB is a concrete type that implements the EVM StateDB interface. Instead of using a trie and database for querying and persistence, the CommitStateDB uses KVStores (key-value stores) and Cosmos SDK Keepers to facilitate state transitions.

The CommitStateDB contains a store key that allows the DB to write to a concrete subtree of the multistore that is only accessible to the EVM module.

Copy // CommitStateDB implements the Geth state.StateDB interface. Instead of using // a trie and database for querying and persistence, the Keeper uses KVStores // and an account mapper is used to facilitate state transitions. // // TODO: This implementation is subject to change in regards to its statefull // manner. In otherwords, how this relates to the keeper in this module. type CommitStateDB struct { // TODO: We need to store the context as part of the structure itself opposed // to being passed as a parameter (as it should be) in order to implement the // StateDB interface. Perhaps there is a better way. ctx sdk.Context storeKey sdk.StoreKey paramSpace params.Subspace accountKeeper AccountKeeper // array that hold 'live' objects, which will get modified while processing a // state transition stateObjects []stateEntry addressToObjectIndex map[ethcmn.Address]int // map from address to the index of the state objects slice stateObjectsDirty map[ethcmn.Address]struct{} // The refund counter, also used by state transitioning. refund uint64 thash, bhash ethcmn.Hash txIndex int logSize uint // TODO: Determine if we actually need this as we do not need preimages in // the SDK, but it seems to be used elsewhere in Geth. preimages []preimageEntry hashToPreimageIndex map[ethcmn.Hash]int // map from hash to the index of the preimages slice // DB error. // State objects are used by the consensus core and VM which are // unable to deal with database-level errors. Any error that occurs // during a database read is memo-ized here and will eventually be returned // by StateDB.Commit. dbErr error // Journal of state modifications. This is the backbone of // Snapshot and RevertToSnapshot. journal *journal validRevisions []revision nextRevisionID int // Per-transaction access list accessList *accessList // mutex for state deep copying lock sync.Mutex }

The functionalities provided by the Ethermint StateDB are:

  • CRUD of stateObjects and accounts:
    • Balance
    • Code
    • Nonce
    • State
  • EVM module parameter getter and setter
  • State transition logic
    • Preparation: transaction index and hash, block hash
  • CRUD of transaction logs
  • Aggregate queries
  • Snapshot state
    • Identify current state with a revision
    • Revert state to a given revision
  • State transition and persistence
    • Preparation: tx and block context
    • Commit state objects
    • Finalise state objects
    • Export state for upgrades
  • Auxiliary functions
    • Copy state
    • Reset state

# State Objects

State objects are used by the VM which is unable to deal with database-level errors. Any error that occurs during a database read is memoized here and will eventually be returned by StateDB.Commit.

The Ethermint stateObject is a concrete type that mimics the functionality from the go-ethereum private stateObject type. It keeps track of the interim values for the contract bytecode, storage state and balance of an EthAccount.

The storage entries (original and "dirty") for each state object are represented as slices instead of maps since latter can cause non-deterministic block app hashes, which result in the chain halting.

When a stateObject is committed during EndBlock. It sets sets the account contract code to store, as well as the dirty storage state. The account's nonce and the account balance are updated by calling the auth and bank module setter functions, respectively.

Copy // stateObject represents an Ethereum account which is being modified. // // The usage pattern is as follows: // First you need to obtain a state object. // Account values can be accessed and modified through the object. // Finally, call CommitTrie to write the modified storage trie into a database. type stateObject struct { code types.Code // contract bytecode, which gets set when code is loaded // State objects are used by the consensus core and VM which are // unable to deal with database-level errors. Any error that occurs // during a database read is memoized here and will eventually be returned // by StateDB.Commit. originStorage Storage // Storage cache of original entries to dedup rewrites dirtyStorage Storage // Storage entries that need to be flushed to disk // DB error dbErr error stateDB *CommitStateDB account *types.EthAccount keyToOriginStorageIndex map[ethcmn.Hash]int keyToDirtyStorageIndex map[ethcmn.Hash]int address ethcmn.Address // cache flags // // When an object is marked suicided it will be delete from the trie during // the "update" phase of the state transition. dirtyCode bool // true if the code was updated suicided bool deleted bool }

The functionalities provided by the Ethermint stateObject are:

  • Storage state getter and setter (temporary)
  • Contract bytecode getter and setter (temporary)
  • Balance getter and setter (temporary)
  • Balance accounting (temporary)
  • Account nonce and address getter and setter (temporary)
  • Auxiliary functions: copy, RLP encoding, empty
  • Commit state object (final)