mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-04-08 03:01:12 -04:00
feat: refactor few stages to providers, introduce insert_block (#1474)
Co-authored-by: Georgios Konstantopoulos <me@gakonst.com>
This commit is contained in:
@@ -1,171 +0,0 @@
|
||||
use reth_db::{models::AccountBeforeTx, tables, transaction::DbTxMut, Error as DbError};
|
||||
use reth_primitives::{Account, Address, Receipt, H256, U256};
|
||||
use revm::primitives::Bytecode;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
/// Execution Result containing vector of transaction changesets
|
||||
/// and block reward if present
|
||||
#[derive(Debug)]
|
||||
pub struct ExecutionResult {
|
||||
/// Transaction changeset containing [Receipt], changed [Accounts][Account] and Storages.
|
||||
pub tx_changesets: Vec<TransactionChangeSet>,
|
||||
/// Post block account changesets. This might include block reward, uncle rewards, withdrawals
|
||||
/// or irregular state changes (DAO fork).
|
||||
pub block_changesets: BTreeMap<Address, AccountInfoChangeSet>,
|
||||
}
|
||||
|
||||
/// After transaction is executed this structure contain
|
||||
/// transaction [Receipt] every change to state ([Account], Storage, [Bytecode])
|
||||
/// that this transaction made and its old values
|
||||
/// so that history account table can be updated.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TransactionChangeSet {
|
||||
/// Transaction receipt
|
||||
pub receipt: Receipt,
|
||||
/// State change that this transaction made on state.
|
||||
pub changeset: BTreeMap<Address, AccountChangeSet>,
|
||||
/// new bytecode created as result of transaction execution.
|
||||
pub new_bytecodes: BTreeMap<H256, Bytecode>,
|
||||
}
|
||||
|
||||
/// Contains old/new account changes
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub enum AccountInfoChangeSet {
|
||||
/// The account is newly created.
|
||||
Created {
|
||||
/// The newly created account.
|
||||
new: Account,
|
||||
},
|
||||
/// An account was deleted (selfdestructed) or we have touched
|
||||
/// an empty account and we need to remove/destroy it.
|
||||
/// (Look at state clearing [EIP-158](https://eips.ethereum.org/EIPS/eip-158))
|
||||
Destroyed {
|
||||
/// The account that was destroyed.
|
||||
old: Account,
|
||||
},
|
||||
/// The account was changed.
|
||||
Changed {
|
||||
/// The account after the change.
|
||||
new: Account,
|
||||
/// The account prior to the change.
|
||||
old: Account,
|
||||
},
|
||||
/// Nothing was changed for the account (nonce/balance).
|
||||
NoChange,
|
||||
}
|
||||
|
||||
impl AccountInfoChangeSet {
|
||||
/// Apply the changes from the changeset to a database transaction.
|
||||
pub fn apply_to_db<'a, TX: DbTxMut<'a>>(
|
||||
self,
|
||||
tx: &TX,
|
||||
address: Address,
|
||||
tx_index: u64,
|
||||
has_state_clear_eip: bool,
|
||||
) -> Result<(), DbError> {
|
||||
match self {
|
||||
AccountInfoChangeSet::Changed { old, new } => {
|
||||
// insert old account in AccountChangeSet
|
||||
// check for old != new was already done
|
||||
tx.put::<tables::AccountChangeSet>(
|
||||
tx_index,
|
||||
AccountBeforeTx { address, info: Some(old) },
|
||||
)?;
|
||||
tx.put::<tables::PlainAccountState>(address, new)?;
|
||||
}
|
||||
AccountInfoChangeSet::Created { new } => {
|
||||
// Ignore account that are created empty and state clear (SpuriousDragon) hardfork
|
||||
// is activated.
|
||||
if has_state_clear_eip && new.is_empty() {
|
||||
return Ok(())
|
||||
}
|
||||
tx.put::<tables::AccountChangeSet>(
|
||||
tx_index,
|
||||
AccountBeforeTx { address, info: None },
|
||||
)?;
|
||||
tx.put::<tables::PlainAccountState>(address, new)?;
|
||||
}
|
||||
AccountInfoChangeSet::Destroyed { old } => {
|
||||
tx.delete::<tables::PlainAccountState>(address, None)?;
|
||||
tx.put::<tables::AccountChangeSet>(
|
||||
tx_index,
|
||||
AccountBeforeTx { address, info: Some(old) },
|
||||
)?;
|
||||
}
|
||||
AccountInfoChangeSet::NoChange => {
|
||||
// do nothing storage account didn't change
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Diff change set that is needed for creating history index and updating current world state.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AccountChangeSet {
|
||||
/// Old and New account account change.
|
||||
pub account: AccountInfoChangeSet,
|
||||
/// Storage containing key -> (OldValue,NewValue). in case that old value is not existing
|
||||
/// we can expect to have U256::ZERO, same with new value.
|
||||
pub storage: BTreeMap<U256, (U256, U256)>,
|
||||
/// Just to make sure that we are taking selfdestruct cleaning we have this field that wipes
|
||||
/// storage. There are instances where storage is changed but account is not touched, so we
|
||||
/// can't take into account that if new account is None that it is selfdestruct.
|
||||
pub wipe_storage: bool,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::sync::Arc;
|
||||
|
||||
use reth_db::{
|
||||
database::Database,
|
||||
mdbx::{test_utils, Env, EnvKind, WriteMap},
|
||||
transaction::DbTx,
|
||||
};
|
||||
use reth_primitives::H160;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn apply_account_info_changeset() {
|
||||
let db: Arc<Env<WriteMap>> = test_utils::create_test_db(EnvKind::RW);
|
||||
let address = H160::zero();
|
||||
let tx_num = 0;
|
||||
let acc1 = Account { balance: U256::from(1), nonce: 2, bytecode_hash: Some(H256::zero()) };
|
||||
let acc2 = Account { balance: U256::from(3), nonce: 4, bytecode_hash: Some(H256::zero()) };
|
||||
|
||||
let tx = db.tx_mut().unwrap();
|
||||
|
||||
// check Changed changeset
|
||||
AccountInfoChangeSet::Changed { new: acc1, old: acc2 }
|
||||
.apply_to_db(&tx, address, tx_num, true)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
tx.get::<tables::AccountChangeSet>(tx_num),
|
||||
Ok(Some(AccountBeforeTx { address, info: Some(acc2) }))
|
||||
);
|
||||
assert_eq!(tx.get::<tables::PlainAccountState>(address), Ok(Some(acc1)));
|
||||
|
||||
AccountInfoChangeSet::Created { new: acc1 }
|
||||
.apply_to_db(&tx, address, tx_num, true)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
tx.get::<tables::AccountChangeSet>(tx_num),
|
||||
Ok(Some(AccountBeforeTx { address, info: None }))
|
||||
);
|
||||
assert_eq!(tx.get::<tables::PlainAccountState>(address), Ok(Some(acc1)));
|
||||
|
||||
// delete old value, as it is dupsorted
|
||||
tx.delete::<tables::AccountChangeSet>(tx_num, None).unwrap();
|
||||
|
||||
AccountInfoChangeSet::Destroyed { old: acc2 }
|
||||
.apply_to_db(&tx, address, tx_num, true)
|
||||
.unwrap();
|
||||
assert_eq!(tx.get::<tables::PlainAccountState>(address), Ok(None));
|
||||
assert_eq!(
|
||||
tx.get::<tables::AccountChangeSet>(tx_num),
|
||||
Ok(Some(AccountBeforeTx { address, info: Some(acc2) }))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
pub mod eth_dao_fork;
|
||||
|
||||
/// Execution result types
|
||||
pub mod execution_result;
|
||||
/// Execution result types.
|
||||
pub use reth_provider::execution_result;
|
||||
/// Executor
|
||||
pub mod executor;
|
||||
|
||||
Reference in New Issue
Block a user