It defines the EVM struct which is quite generic over a DB
database that implements one of the following traits:
Database
DatabaseRef
Database + DatabaseCommit
pub struct EVM<DB> {
pub env: Env,
pub db: Option<DB>,
}
Example of usage:
let evm: EVM<SomeDatabase> = EVM::new();
The Env
type is another struct, defined in this way:
pub struct Env {
pub cfg: CfgEnv,
pub block: BlockEnv,
pub tx: TxEnv,
}
It represents the environment where the EVM works.
The EVM
struct implements some interesting functions:
preverify_transaction
/// Do checks that could make transaction fail before call/create
pub fn preverify_transaction(&mut self) -> Result<(), EVMError<DB::Error>> {
if let Some(db) = self.db.as_mut() {
let mut noop = NoOpInspector {};
let out = evm_inner::<DB, false>(&mut self.env, db, &mut noop).preverify_transaction();
out
} else {
panic!("Database needs to be set");
}
}
This function performs a lot of validation based on the current environment and state, such as block data, tx data, nonce and gas.
transact_preverified
/// Skip preverification steps and execute transaction
/// without writing to DB, return change state.
pub fn transact_preverified(&mut self) -> EVMResult<DB::Error> {
if let Some(db) = self.db.as_mut() {
let mut noop = NoOpInspector {};
let out = evm_inner::<DB, false>(&mut self.env, db, &mut noop).transact_preverified();
out
} else {
panic!("Database needs to be set");
}
}
This function skips preverification and immediately execute the transaction without writing to the database, returning the change state.
transact
/// Execute transaction without writing to DB, return change state.
pub fn transact(&mut self) -> EVMResult<DB::Error> {
if let Some(db) = self.db.as_mut() {
let mut noop = NoOpInspector {};
let out = evm_inner::<DB, false>(&mut self.env, db, &mut noop).transact();
out
} else {
panic!("Database needs to be set");
}
}
It is like the one before but before actually executing the tx it does preverification
inspect
/// Execute transaction with given inspector, without wring to DB. Return change state.
pub fn inspect<INSP: Inspector<DB>>(&mut self, mut inspector: INSP) -> EVMResult<DB::Error> {
if let Some(db) = self.db.as_mut() {
evm_inner::<DB, true>(&mut self.env, db, &mut inspector).transact()
} else {
panic!("Database needs to be set");
}
}
Like the one before but it uses the given inspector. This is useful for debugging.
Then it have the same functions but using a type for DB that implements DatabaseRef
. The difference is that it works with a reference of the database. It’s useful if you only have a reference on the state and you don't want to update anything on it.