Skip to content

Commit

Permalink
feat: use storage for pending logs
Browse files Browse the repository at this point in the history
Allow outer code to inject logs for currently running ethereum transaction.
  • Loading branch information
Grigoriy Simonov committed Apr 14, 2023
1 parent 2b09a67 commit 15e9c6a
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 70 deletions.
81 changes: 44 additions & 37 deletions frame/ethereum/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ use frame_support::{
weights::Weight,
};
use frame_system::{pallet_prelude::OriginFor, CheckWeight, WeightInfo};
use pallet_evm::{BlockHashMapping, FeeCalculator, GasWeightMapping, Runner};
use pallet_evm::{BlockHashMapping, CurrentLogs, FeeCalculator, GasWeightMapping, Runner};
use sp_runtime::{
generic::DigestItem,
traits::{DispatchInfoOf, Dispatchable, One, Saturating, UniqueSaturatedInto, Zero},
Expand Down Expand Up @@ -222,6 +222,7 @@ pub mod pallet {
));
}
Pending::<T>::kill();
assert_eq!(<CurrentLogs<T>>::get().len(), 0, "fake transaction finalizer is not initialized, as some logs was left after block is finished");
}

fn on_initialize(_: T::BlockNumber) -> Weight {
Expand Down Expand Up @@ -405,7 +406,7 @@ impl<T: Config> Pallet<T> {
}
};
cumulative_gas_used = used_gas;
Self::logs_bloom(logs, &mut logs_bloom);
Self::logs_bloom(logs.iter(), &mut logs_bloom);
}

let ommers = Vec::<ethereum::Header>::new();
Expand Down Expand Up @@ -459,10 +460,10 @@ impl<T: Config> Pallet<T> {
}
}

fn logs_bloom(logs: Vec<Log>, bloom: &mut Bloom) {
fn logs_bloom<'a>(logs: impl IntoIterator<Item = &'a Log>, bloom: &'a mut Bloom) {
for log in logs {
bloom.accrue(BloomInput::Raw(&log.address[..]));
for topic in log.topics {
for topic in &log.topics {
bloom.accrue(BloomInput::Raw(&topic[..]));
}
}
Expand Down Expand Up @@ -546,42 +547,48 @@ impl<T: Config> Pallet<T> {
let transaction_index = pending.len() as u32;

let (reason, status, used_gas, dest) = match info {
CallOrCreateInfo::Call(info) => (
info.exit_reason,
TransactionStatus {
transaction_hash,
transaction_index,
from: source,
to,
contract_address: None,
logs: info.logs.clone(),
logs_bloom: {
let mut bloom: Bloom = Bloom::default();
Self::logs_bloom(info.logs, &mut bloom);
bloom
CallOrCreateInfo::Call(info) => {
let logs = <CurrentLogs<T>>::take();
(
info.exit_reason,
TransactionStatus {
transaction_hash,
transaction_index,
from: source,
to,
contract_address: None,
logs_bloom: {
let mut bloom: Bloom = Bloom::default();
Self::logs_bloom(logs.iter(), &mut bloom);
bloom
},
logs,
},
},
info.used_gas,
to,
),
CallOrCreateInfo::Create(info) => (
info.exit_reason,
TransactionStatus {
transaction_hash,
transaction_index,
from: source,
info.used_gas,
to,
contract_address: Some(info.value),
logs: info.logs.clone(),
logs_bloom: {
let mut bloom: Bloom = Bloom::default();
Self::logs_bloom(info.logs, &mut bloom);
bloom
)
}
CallOrCreateInfo::Create(info) => {
let logs = <CurrentLogs<T>>::take();
(
info.exit_reason,
TransactionStatus {
transaction_hash,
transaction_index,
from: source,
to,
contract_address: Some(info.value),
logs_bloom: {
let mut bloom: Bloom = Bloom::default();
Self::logs_bloom(logs.iter(), &mut bloom);
bloom
},
logs,
},
},
info.used_gas,
Some(info.value),
),
info.used_gas,
Some(info.value),
)
}
};

let receipt = {
Expand Down
20 changes: 20 additions & 0 deletions frame/evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,11 @@ pub mod pallet {
#[pallet::getter(fn account_storages)]
pub type AccountStorages<T: Config> =
StorageDoubleMap<_, Blake2_128Concat, H160, Blake2_128Concat, H256, H256, ValueQuery>;

/// Written on log, reset after transaction
/// Should be empty between transactions
#[pallet::storage]
pub type CurrentLogs<T: Config> = StorageValue<_, Vec<Log>, ValueQuery>;
}

/// Type alias for currency balance.
Expand Down Expand Up @@ -733,6 +738,21 @@ impl<T: Config> Pallet<T> {
<AccountCodes<T>>::insert(address, code);
}

/// Add log to be injected in either real or fake ethereum transaction
pub fn deposit_log(log: Log) {
log::trace!(
target: "evm",
"Inserting mirrored log for {:?}, topics ({}) {:?}, data ({}): {:?}]",
log.address,
log.topics.len(),
log.topics,
log.data.len(),
log.data
);
<CurrentLogs<T>>::append(log);
// Log event is not emitted here, as these logs belong to pallets, which will emit pallet-specific logs on substrate side by themselves
}

/// Get the account basic in EVM format.
pub fn account_basic(address: &H160) -> (Account, frame_support::weights::Weight) {
let account_id = T::AddressMapping::into_account_id(*address);
Expand Down
54 changes: 22 additions & 32 deletions frame/evm/src/runner/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@

use crate::{
runner::Runner as RunnerT, AccountCodes, AccountStorages, AddressMapping, BalanceOf,
BlockHashMapping, Config, Error, Event, FeeCalculator, OnChargeEVMTransaction, OnCreate,
Pallet, RunnerError,
BlockHashMapping, Config, CurrentLogs, Error, Event, FeeCalculator, OnChargeEVMTransaction,
OnCreate, Pallet, RunnerError,
};
use evm::{
backend::Backend as BackendT,
Expand Down Expand Up @@ -261,30 +261,10 @@ where
Pallet::<T>::remove_account(&address)
}

for log in &state.substate.logs {
log::trace!(
target: "evm",
"Inserting log for {:?}, topics ({}) {:?}, data ({}): {:?}]",
log.address,
log.topics.len(),
log.topics,
log.data.len(),
log.data
);
Pallet::<T>::deposit_event(Event::<T>::Log {
log: Log {
address: log.address,
topics: log.topics.clone(),
data: log.data.clone(),
},
});
}

Ok(ExecutionInfo {
value: retv,
exit_reason: reason,
used_gas,
logs: state.substate.logs,
})
}
}
Expand Down Expand Up @@ -486,14 +466,14 @@ where
}
}

struct SubstrateStackSubstate<'config> {
struct SubstrateStackSubstate<'config, T> {
metadata: StackSubstateMetadata<'config>,
deletes: BTreeSet<H160>,
logs: Vec<Log>,
parent: Option<Box<SubstrateStackSubstate<'config>>>,
parent: Option<Box<SubstrateStackSubstate<'config, T>>>,
_marker: PhantomData<T>,
}

impl<'config> SubstrateStackSubstate<'config> {
impl<'config, T: Config> SubstrateStackSubstate<'config, T> {
pub fn metadata(&self) -> &StackSubstateMetadata<'config> {
&self.metadata
}
Expand All @@ -507,7 +487,7 @@ impl<'config> SubstrateStackSubstate<'config> {
metadata: self.metadata.spit_child(gas_limit, is_static),
parent: None,
deletes: BTreeSet::new(),
logs: Vec::new(),
_marker: PhantomData,
};
mem::swap(&mut entering, self);

Expand All @@ -521,7 +501,6 @@ impl<'config> SubstrateStackSubstate<'config> {
mem::swap(&mut exited, self);

self.metadata.swallow_commit(exited.metadata)?;
self.logs.append(&mut exited.logs);
self.deletes.append(&mut exited.deletes);

sp_io::storage::commit_transaction();
Expand Down Expand Up @@ -563,11 +542,22 @@ impl<'config> SubstrateStackSubstate<'config> {
}

pub fn log(&mut self, address: H160, topics: Vec<H256>, data: Vec<u8>) {
self.logs.push(Log {
let log = Log {
address,
topics,
data,
});
};
log::trace!(
target: "evm",
"Inserting log for {:?}, topics ({}) {:?}, data ({}): {:?}]",
log.address,
log.topics.len(),
log.topics,
log.data.len(),
log.data
);
<CurrentLogs<T>>::append(&log);
<Pallet<T>>::deposit_event(Event::<T>::Log { log });
}

fn recursive_is_cold<F: Fn(&Accessed) -> bool>(&self, f: &F) -> bool {
Expand All @@ -586,7 +576,7 @@ impl<'config> SubstrateStackSubstate<'config> {
/// Substrate backend for EVM.
pub struct SubstrateStackState<'vicinity, 'config, T> {
vicinity: &'vicinity Vicinity,
substate: SubstrateStackSubstate<'config>,
substate: SubstrateStackSubstate<'config, T>,
original_storage: BTreeMap<(H160, H256), H256>,
_marker: PhantomData<T>,
}
Expand All @@ -599,8 +589,8 @@ impl<'vicinity, 'config, T: Config> SubstrateStackState<'vicinity, 'config, T> {
substate: SubstrateStackSubstate {
metadata,
deletes: BTreeSet::new(),
logs: Vec::new(),
parent: None,
_marker: PhantomData,
},
_marker: PhantomData,
original_storage: BTreeMap::new(),
Expand Down
1 change: 0 additions & 1 deletion primitives/evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ pub struct ExecutionInfo<T> {
pub exit_reason: ExitReason,
pub value: T,
pub used_gas: U256,
pub logs: Vec<Log>,
}

pub type CallInfo = ExecutionInfo<Vec<u8>>;
Expand Down

0 comments on commit 15e9c6a

Please sign in to comment.