statedb

package
v2.0.0-rc.11 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 5, 2024 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

The "evm/statedb" package implements a go-ethereum vm.StateDB with state management and journal changes specific to the Nibiru EVM.

This package plays a critical role in managing the state of accounts, contracts, and storage while handling atomicity, caching, and state modifications. It ensures that state transitions made during the execution of smart contracts are either committed or reverted based on transaction outcomes.

StateDB structs used to store anything within the state tree, including accounts, contracts, and contract storage. Note that Nibiru's state tree is an IAVL tree, which differs from the Merkle Patricia Trie structure seen on Ethereum mainnet.

StateDBs also take care of caching and handling nested states.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Account

type Account struct {
	// BalanceNative is the micronibi (unibi) balance of the account, which is
	// the official balance in the x/bank module state
	BalanceNative *big.Int
	// Nonce is the number of transactions sent from this account or, for contract accounts, the number of contract-creations made by this account
	Nonce uint64
	// CodeHash is the hash of the contract code for this account, or nil if it's not a contract account
	CodeHash []byte
}

Account represents an Ethereum account as viewed by the Auth module state. The balance is stored in the smallest native unit (e.g., micronibi or unibi). These objects are stored in the storage of auth module.

func NewEmptyAccount

func NewEmptyAccount() *Account

NewEmptyAccount returns an empty account.

func (*Account) IsContract

func (acct *Account) IsContract() bool

IsContract returns if the account contains contract code.

func (Account) ToWei

func (acc Account) ToWei() AccountWei

ToWei converts an Account (native representation) to AccountWei (EVM representation). This conversion is necessary when moving from the Cosmos SDK context to the EVM context. It multiplies the balance by 10^12 to convert from unibi to wei.

type AccountWei

type AccountWei struct {
	BalanceWei *big.Int
	// Nonce is the number of transactions sent from this account or, for contract accounts, the number of contract-creations made by this account
	Nonce uint64
	// CodeHash is the hash of the contract code for this account, or nil if it's not a contract account
	CodeHash []byte
}

AccountWei represents an Ethereum account as viewed by the EVM. This struct is derived from an `Account` but represents balances in wei, which is necessary for correct operation within the EVM. The EVM expects and operates on wei values, which are 10^12 times larger than the native unibi value due to the definition of NIBI as "ether".

func (AccountWei) ToNative

func (acc AccountWei) ToNative() Account

ToNative converts an AccountWei (EVM representation) back to an Account (native representation). This conversion is necessary when moving from the EVM context back to the Cosmos SDK context. It divides the balance by 10^12 to convert from wei to unibi.

type EVMConfig

type EVMConfig struct {
	Params      evm.Params
	ChainConfig *gethparams.ChainConfig

	// BlockCoinbase: In Ethereum, the coinbase (or "benficiary") is the address that
	// proposed the current block. It corresponds to the [COINBASE op code]
	// (the "block.coinbase" stack output).
	//
	// [COINBASE op code]: https://ethereum.org/en/developers/docs/evm/opcodes/
	BlockCoinbase gethcommon.Address

	// BaseFeeWei is the EVM base fee in units of wei per gas. The term "base
	// fee" comes from EIP-1559.
	BaseFeeWei *big.Int
}

EVMConfig encapsulates parameters needed to create an instance of the EVM ("go-ethereum/core/vm.EVM").

type JournalChange

type JournalChange interface {
	// Revert undoes the changes introduced by this journal entry.
	Revert(*StateDB)

	// Dirtied returns the Ethereum address modified by this journal entry.
	Dirtied() *common.Address
}

JournalChange, also called a "journal entry", is a modification entry in the state change journal that can be reverted on demand.

type Keeper

type Keeper interface {
	// GetAccount: Ethereum account getter for a [statedb.Account].
	GetAccount(ctx sdk.Context, addr common.Address) *Account
	GetState(ctx sdk.Context, addr common.Address, key common.Hash) common.Hash
	GetCode(ctx sdk.Context, codeHash common.Hash) []byte

	// ForEachStorage: Iterator over contract storage.
	ForEachStorage(
		ctx sdk.Context, addr common.Address,
		stopIter func(key, value common.Hash) bool,
	)

	SetAccount(ctx sdk.Context, addr common.Address, account Account) error
	SetState(ctx sdk.Context, addr common.Address, key common.Hash, value []byte)
	// SetCode: Setter for smart contract bytecode. Delete if code is empty.
	SetCode(ctx sdk.Context, codeHash []byte, code []byte)

	// DeleteAccount handles contract's suicide call, clearing the balance,
	// contract bytecode, contract state, and its native account.
	DeleteAccount(ctx sdk.Context, addr common.Address) error

	IsPrecompile(addr common.Address) bool
}

Keeper provide underlying storage of StateDB

type PrecompileCalled

type PrecompileCalled struct {
	MultiStore store.CacheMultiStore
	Events     sdk.Events
}

PrecompileCalled: Precompiles can alter persistent storage of other modules. These changes to persistent storage are not reverted by a `Revert` of JournalChange by default, as it generally manages only changes to accounts and Bank balances for ether (NIBI).

As a workaround to make state changes from precompiles reversible, we store PrecompileCalled snapshots that sync and record the prior state of the other modules, allowing precompile calls to truly be reverted.

As a simple example, suppose that a transaction calls a precompile.

  1. If the precompile changes the state in the Bank Module or Wasm module
  2. The call gets reverted (`revert()` in Solidity), which shoud restore the state to a in-memory snapshot recorded on the StateDB journal.
  3. This could cause a problem where changes to the rest of the blockchain state are still in effect following the reversion in the EVM state DB.

func (PrecompileCalled) Dirtied

func (ch PrecompileCalled) Dirtied() *common.Address

func (PrecompileCalled) Revert

func (ch PrecompileCalled) Revert(s *StateDB)

Revert rolls back the StateDB cache context to the state it was in prior to the precompile call. Modifications to this cache context are pushed to the commit context (s.evmTxCtx) when StateDB.Commit is executed.

type StateDB

type StateDB struct {

	// Journal of state modifications. This is the backbone of
	// Snapshot and RevertToSnapshot.
	Journal *journal
	// contains filtered or unexported fields
}

StateDB structs within the ethereum protocol are used to store anything within the merkle trie. StateDBs take care of caching and storing nested states. It's the general query interface to retrieve: * Contracts * Accounts

func FromVM

func FromVM(evmObj *vm.EVM) *StateDB

func New

func New(ctx sdk.Context, keeper Keeper, txConfig TxConfig) *StateDB

New creates a new state from a given trie.

func (*StateDB) AddAddressToAccessList

func (s *StateDB) AddAddressToAccessList(addr common.Address)

AddAddressToAccessList adds the given address to the access list

func (*StateDB) AddBalance

func (s *StateDB) AddBalance(addr common.Address, wei *big.Int)

AddBalance adds amount to the account associated with addr.

func (*StateDB) AddLog

func (s *StateDB) AddLog(log *gethcore.Log)

AddLog adds a log, called by evm.

func (*StateDB) AddPreimage

func (s *StateDB) AddPreimage(_ common.Hash, _ []byte)

AddPreimage records a SHA3 preimage seen by the VM. AddPreimage performs a no-op since the EnablePreimageRecording flag is disabled on the vm.Config during state transitions. No store trie preimages are written to the database.

func (*StateDB) AddRefund

func (s *StateDB) AddRefund(gas uint64)

AddRefund adds gas to the refund counter

func (*StateDB) AddSlotToAccessList

func (s *StateDB) AddSlotToAccessList(addr common.Address, slot common.Hash)

AddSlotToAccessList adds the given (address, slot)-tuple to the access list

func (*StateDB) AddressInAccessList

func (s *StateDB) AddressInAccessList(addr common.Address) bool

AddressInAccessList returns true if the given address is in the access list.

func (*StateDB) CacheCtxForPrecompile

func (s *StateDB) CacheCtxForPrecompile() (
	sdk.Context, PrecompileCalled,
)

func (*StateDB) Commit

func (s *StateDB) Commit() error

Commit writes the dirty journal state changes to the EVM Keeper. The StateDB object cannot be reused after [Commit] has completed. A new object needs to be created from the EVM.

cacheCtxSyncNeeded: If one of the Nibiru-Specific Precompiled Contracts was called, a JournalChange of type [PrecompileSnapshotBeforeRun] gets added and we branch off a cache of the commit context (s.evmTxCtx).

func (*StateDB) CommitCacheCtx

func (s *StateDB) CommitCacheCtx() error

CommitCacheCtx is identical to StateDB.Commit, except it: (1) uses the cacheCtx of the StateDB and (2) does not save mutations of the cacheCtx to the commit context (s.evmTxCtx). The reason for (2) is that the overall EVM transaction (block, not internal) is only finalized when [Commit] is called, not when [CommitCacheCtx] is called.

func (*StateDB) CreateAccount

func (s *StateDB) CreateAccount(addr common.Address)

CreateAccount explicitly creates a state object. If a state object with the address already exists the balance is carried over to the new account.

CreateAccount is called during the EVM CREATE operation. The situation might arise that a contract does the following:

1. sends funds to sha(account ++ (nonce + 1)) 2. tx_create(sha(account ++ nonce)) (note that this gets the address of 1)

Carrying over the balance ensures that Ether doesn't disappear.

func (*StateDB) DebugDirties

func (s *StateDB) DebugDirties() map[common.Address]int

DebugDirties is a test helper that returns the journal's dirty account changes map.

func (*StateDB) DebugDirtiesCount

func (s *StateDB) DebugDirtiesCount() int

DebugDirtiesCount is a test helper to inspect how many entries in the journal are still dirty (uncommitted). After calling StateDB.Commit, this function should return zero.

func (*StateDB) DebugEntries

func (s *StateDB) DebugEntries() []JournalChange

DebugEntries is a test helper that returns the sequence of JournalChange objects added during execution.

func (*StateDB) DebugStateObjects

func (s *StateDB) DebugStateObjects() map[common.Address]*stateObject

DebugStateObjects is a test helper that returns returns a copy of the [StateDB.stateObjects] map.

func (*StateDB) Empty

func (s *StateDB) Empty(addr common.Address) bool

Empty returns whether the state object is either non-existent or empty according to the EIP161 specification (balance = nonce = code = 0)

func (*StateDB) Exist

func (s *StateDB) Exist(addr common.Address) bool

Exist reports whether the given account address exists in the state. Notably this also returns true for suicided accounts.

func (*StateDB) ForEachStorage

func (s *StateDB) ForEachStorage(addr common.Address, cb func(key, value common.Hash) bool) error

ForEachStorage iterate the contract storage, the iteration order is not defined.

func (*StateDB) GetBalance

func (s *StateDB) GetBalance(addr common.Address) *big.Int

GetBalance retrieves the balance from the given address or 0 if object not found

func (*StateDB) GetCacheContext

func (s *StateDB) GetCacheContext() *sdk.Context

GetCacheContext: Getter for testing purposes.

func (*StateDB) GetCode

func (s *StateDB) GetCode(addr common.Address) []byte

GetCode returns the code of account, nil if not exists.

func (*StateDB) GetCodeHash

func (s *StateDB) GetCodeHash(addr common.Address) common.Hash

GetCodeHash returns the code hash of account.

func (*StateDB) GetCodeSize

func (s *StateDB) GetCodeSize(addr common.Address) int

GetCodeSize returns the code size of account.

func (*StateDB) GetCommittedState

func (s *StateDB) GetCommittedState(addr common.Address, hash common.Hash) common.Hash

GetCommittedState retrieves a value from the given account's committed storage trie.

func (*StateDB) GetEvmTxContext

func (s *StateDB) GetEvmTxContext() sdk.Context

GetEvmTxContext returns the EVM transaction context.

func (*StateDB) GetNonce

func (s *StateDB) GetNonce(addr common.Address) uint64

GetNonce returns the nonce of account, 0 if not exists.

func (*StateDB) GetRefund

func (s *StateDB) GetRefund() uint64

GetRefund returns the current value of the refund counter.

func (*StateDB) GetState

func (s *StateDB) GetState(addr common.Address, hash common.Hash) common.Hash

GetState retrieves a value from the given account's storage trie.

func (*StateDB) HasSuicided

func (s *StateDB) HasSuicided(addr common.Address) bool

HasSuicided returns if the contract is suicided in current transaction.

func (*StateDB) Keeper

func (s *StateDB) Keeper() Keeper

Keeper returns the underlying `Keeper`

func (*StateDB) Logs

func (s *StateDB) Logs() []*gethcore.Log

Logs returns the logs of current transaction.

func (*StateDB) PrepareAccessList

func (s *StateDB) PrepareAccessList(
	sender common.Address,
	dst *common.Address,
	precompiles []common.Address,
	list gethcore.AccessList,
)

PrepareAccessList handles the preparatory steps for executing a state transition with regards to both EIP-2929 and EIP-2930:

- Add sender to access list (2929) - Add destination to access list (2929) - Add precompiles to access list (2929) - Add the contents of the optional tx access list (2930)

This method should only be called if Yolov3/Berlin/2929+2930 is applicable at the current number.

func (*StateDB) RevertToSnapshot

func (s *StateDB) RevertToSnapshot(revid int)

RevertToSnapshot reverts all state changes made since the given revision.

func (*StateDB) SavePrecompileCalledJournalChange

func (s *StateDB) SavePrecompileCalledJournalChange(
	journalChange PrecompileCalled,
) error

SavePrecompileCalledJournalChange adds a snapshot of the commit multistore (PrecompileCalled) to the StateDB journal at the end of successful invocation of a precompiled contract. This is necessary to revert intermediate states where an EVM contract augments the multistore with a precompile and an inconsistency occurs between the EVM module and other modules.

See PrecompileCalled for more info.

func (*StateDB) SetBalanceWei

func (s *StateDB) SetBalanceWei(addr common.Address, wei *big.Int)

func (*StateDB) SetCode

func (s *StateDB) SetCode(addr common.Address, code []byte)

SetCode sets the code of account.

func (*StateDB) SetNonce

func (s *StateDB) SetNonce(addr common.Address, nonce uint64)

SetNonce sets the nonce of account.

func (*StateDB) SetState

func (s *StateDB) SetState(addr common.Address, key, value common.Hash)

SetState sets the contract state.

func (*StateDB) SlotInAccessList

func (s *StateDB) SlotInAccessList(addr common.Address, slot common.Hash) (addressPresent bool, slotPresent bool)

SlotInAccessList returns true if the given (address, slot)-tuple is in the access list.

func (*StateDB) Snapshot

func (s *StateDB) Snapshot() int

Snapshot returns an identifier for the current revision of the state.

func (*StateDB) SubBalance

func (s *StateDB) SubBalance(addr common.Address, wei *big.Int)

SubBalance subtracts amount from the account associated with addr.

func (*StateDB) SubRefund

func (s *StateDB) SubRefund(gas uint64)

SubRefund removes gas from the refund counter. This method will panic if the refund counter goes below zero

func (*StateDB) Suicide

func (s *StateDB) Suicide(addr common.Address) bool

Suicide marks the given account as suicided. This clears the account balance.

The account's state object is still available until the state is committed, getStateObject will return a non-nil account after Suicide.

type Storage

type Storage map[common.Hash]common.Hash

Storage represents in-memory cache/buffer of contract storage.

func (Storage) SortedKeys

func (s Storage) SortedKeys() []common.Hash

SortedKeys sort the keys for deterministic iteration

type TxConfig

type TxConfig struct {
	BlockHash gethcommon.Hash // hash of current block
	TxHash    gethcommon.Hash // hash of current tx
	TxIndex   uint            // the index of current transaction
	LogIndex  uint            // the index of next log within current block
}

TxConfig encapsulates the readonly information of current tx for `StateDB`.

func NewEmptyTxConfig

func NewEmptyTxConfig(blockHash gethcommon.Hash) TxConfig

NewEmptyTxConfig construct an empty TxConfig, used in context where there's no transaction, e.g. `eth_call`/`eth_estimateGas`.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL