Skip to content

Commit

Permalink
Fix the proof_size over limit case
Browse files Browse the repository at this point in the history
  • Loading branch information
boundless-forest committed Aug 6, 2024
1 parent 94c5e3f commit 36c7b29
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 64 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 12 additions & 9 deletions frame/ethereum/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,11 @@ impl<T: Config> Pallet<T> {
true,
);
let proof_size_pre_execution = cumulus_primitives_storage_weight_reclaim::get_proof_size();
TransactionPov::new(weight_limit, extrinsics_len, proof_size_pre_execution)
Some(TransactionPov::new(
weight_limit,
extrinsics_len,
proof_size_pre_execution,
))
}

fn recover_signer(transaction: &Transaction) -> Option<H160> {
Expand Down Expand Up @@ -513,8 +517,7 @@ impl<T: Config> Pallet<T> {
is_transactional: true,
},
transaction_data.clone().into(),
weight_limit,
proof_size_base_cost,
transaction_pov,
)
.validate_in_pool_for(&who)
.and_then(|v| v.with_chain_id())
Expand Down Expand Up @@ -808,8 +811,7 @@ impl<T: Config> Pallet<T> {
access_list,
is_transactional,
validate,
weight_limit,
proof_size_base_cost,
transaction_pov,
config.as_ref().unwrap_or_else(|| T::config()),
) {
Ok(res) => res,
Expand Down Expand Up @@ -838,8 +840,7 @@ impl<T: Config> Pallet<T> {
access_list,
is_transactional,
validate,
weight_limit,
proof_size_base_cost,
transaction_pov,
config.as_ref().unwrap_or_else(|| T::config()),
) {
Ok(res) => res,
Expand Down Expand Up @@ -881,8 +882,7 @@ impl<T: Config> Pallet<T> {
is_transactional: true,
},
transaction_data.into(),
weight_limit,
proof_size_base_cost,
transaction_pov,
)
.validate_in_block_for(&who)
.and_then(|v| v.with_chain_id())
Expand Down Expand Up @@ -996,6 +996,9 @@ pub struct InvalidTransactionWrapper(InvalidTransaction);
impl From<TransactionValidationError> for InvalidTransactionWrapper {
fn from(validation_error: TransactionValidationError) -> Self {
match validation_error {
TransactionValidationError::ProofLimitTooLow => InvalidTransactionWrapper(
InvalidTransaction::Custom(TransactionValidationError::ProofLimitTooLow as u8),
),
TransactionValidationError::GasLimitTooLow => InvalidTransactionWrapper(
InvalidTransaction::Custom(TransactionValidationError::GasLimitTooLow as u8),
),
Expand Down
52 changes: 27 additions & 25 deletions frame/evm/src/runner/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,33 +226,17 @@ where
origin: source,
};
let metadata = StackSubstateMetadata::new(gas_limit, config);
let state = SubstrateStackState::new(&vicinity, metadata);
let state = SubstrateStackState::new(&vicinity, metadata, transaction_pov);
let mut executor = StackExecutor::new_with_precompiles(state, config, precompiles);
let (reason, retv) = f(&mut executor);

// Post execution.
let opcode_used_gas = executor.used_gas();

let proof_size_used_gas = if let Some(mut pov) = transaction_pov {
let proof_size_post_execution =
cumulus_primitives_storage_weight_reclaim::get_proof_size().unwrap_or_default();
let proof_size_used = proof_size_post_execution
.saturating_sub(pov.proof_size_pre_execution.unwrap_or_default())
.saturating_add(pov.extrinsics_len);

// If the proof size used is greater than the weight limit, we skip the storage apply and return early.
if proof_size_used > pov.weight_limit.proof_size() {
return Err(RunnerError {
error: Error::<T>::ProofLimitTooLow,
weight,
});
}

pov.proof_size_used = proof_size_used;
proof_size_used.saturating_mul(T::GasLimitPovSizeRatio::get())
} else {
0
};
let proof_size_used_gas = transaction_pov.map_or(0, |mut pov| {
pov.proof_size_used = pov.proof_size_used();
pov.proof_size_used
.saturating_mul(T::GasLimitPovSizeRatio::get())
});
let used_gas = U256::from(core::cmp::max(opcode_used_gas, proof_size_used_gas));

let fee = used_gas.saturating_mul(total_fee_per_gas);
Expand Down Expand Up @@ -642,12 +626,17 @@ pub struct SubstrateStackState<'vicinity, 'config, T> {
vicinity: &'vicinity Vicinity,
substate: SubstrateStackSubstate<'config>,
original_storage: BTreeMap<(H160, H256), H256>,
transaction_pov: Option<TransactionPov>,
_marker: PhantomData<T>,
}

impl<'vicinity, 'config, T: Config> SubstrateStackState<'vicinity, 'config, T> {
/// Create a new backend with given vicinity.
pub fn new(vicinity: &'vicinity Vicinity, metadata: StackSubstateMetadata<'config>) -> Self {
pub fn new(
vicinity: &'vicinity Vicinity,
metadata: StackSubstateMetadata<'config>,
transaction_pov: Option<TransactionPov>,
) -> Self {
Self {
vicinity,
substate: SubstrateStackSubstate {
Expand All @@ -656,8 +645,9 @@ impl<'vicinity, 'config, T: Config> SubstrateStackState<'vicinity, 'config, T> {
logs: Vec::new(),
parent: None,
},
_marker: PhantomData,
original_storage: BTreeMap::new(),
transaction_pov,
_marker: PhantomData,
}
}
}
Expand Down Expand Up @@ -765,7 +755,19 @@ where
}

fn exit_commit(&mut self) -> Result<(), ExitError> {
self.substate.exit_commit()
match self.transaction_pov {
Some(pov) if pov.proof_size_used > pov.weight_limit.proof_size() => {
log::debug!(
target: "evm",
"Exceeded proof size limit. Proof size used: {}, proof size limit: {}",
pov.proof_size_used,
pov.weight_limit.proof_size()
);
self.substate.exit_discard()?;
Err(ExitError::OutOfGas)
}
_ => self.substate.exit_commit(),
}
}

fn exit_revert(&mut self) -> Result<(), ExitError> {
Expand Down
2 changes: 2 additions & 0 deletions primitives/evm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ num_enum = { workspace = true, default-features = false }
scale-codec = { package = "parity-scale-codec", workspace = true }
scale-info = { workspace = true }
serde = { workspace = true, optional = true }
cumulus-primitives-storage-weight-reclaim = { workspace = true }
# Substrate
frame-support = { workspace = true }
sp-core = { workspace = true }
Expand All @@ -32,6 +33,7 @@ std = [
# Substrate
"frame-support/std",
"sp-core/std",
"cumulus-primitives-storage-weight-reclaim/std",
"sp-runtime/std",
]
serde = [
Expand Down
21 changes: 21 additions & 0 deletions primitives/evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,27 @@ impl TransactionPov {
proof_size_used: extrinsics_len,
}
}

pub fn proof_size_used(&self) -> u64 {
// if we don't have proof_size_pre_execution, that means that we don't care about the tx proof size
let Some(proof_size_pre_execution) = self.proof_size_pre_execution else {
return 0;
};

// If proof_size_pre_execution is enable, but the proof_size_post_execution is disable, maybe the proof_size host function
// doesn't work.
let Some(proof_size_post_execution) =
cumulus_primitives_storage_weight_reclaim::get_proof_size()
else {
return self.proof_size_used;
};

let proof_size_used = proof_size_post_execution
.saturating_sub(proof_size_pre_execution)
.saturating_add(self.extrinsics_len);

proof_size_used
}
}

#[derive(Clone, Copy, Eq, PartialEq, Debug, Encode, Decode, TypeInfo)]
Expand Down
39 changes: 9 additions & 30 deletions template/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ use pallet_transaction_payment::{ConstFeeMultiplier, FungibleAdapter};
use sp_genesis_builder::PresetId;
// Frontier
use fp_account::EthereumSignature;
use fp_evm::weight_per_gas;
use fp_evm::{weight_per_gas, TransactionPov};
use fp_rpc::TransactionStatus;
use pallet_ethereum::{Call::transact, PostLogContent, Transaction as EthereumTransaction};
use pallet_evm::{
Expand Down Expand Up @@ -833,19 +833,10 @@ impl_runtime_apis! {
} else {
gas_limit.low_u64()
};
let without_base_extrinsic_weight = true;

let (weight_limit, proof_size_base_cost) =
match <Runtime as pallet_evm::Config>::GasWeightMapping::gas_to_weight(
gas_limit,
without_base_extrinsic_weight
) {
weight_limit if weight_limit.proof_size() > 0 => {
(Some(weight_limit), Some(estimated_transaction_len as u64))
}
_ => (None, None),
};

let weight_limit = <Runtime as pallet_evm::Config>::GasWeightMapping::gas_to_weight(gas_limit, true);
let proof_size_pre_execution = cumulus_primitives_storage_weight_reclaim::get_proof_size();
let transaction_pov = TransactionPov::new(weight_limit, estimated_transaction_len as u64, proof_size_pre_execution);
<Runtime as pallet_evm::Config>::Runner::call(
from,
to,
Expand All @@ -858,8 +849,7 @@ impl_runtime_apis! {
access_list.unwrap_or_default(),
false,
true,
weight_limit,
proof_size_base_cost,
Some(transaction_pov),
config.as_ref().unwrap_or(<Runtime as pallet_evm::Config>::config()),
).map_err(|err| err.error.into())
}
Expand Down Expand Up @@ -912,19 +902,9 @@ impl_runtime_apis! {
} else {
gas_limit.low_u64()
};
let without_base_extrinsic_weight = true;

let (weight_limit, proof_size_base_cost) =
match <Runtime as pallet_evm::Config>::GasWeightMapping::gas_to_weight(
gas_limit,
without_base_extrinsic_weight
) {
weight_limit if weight_limit.proof_size() > 0 => {
(Some(weight_limit), Some(estimated_transaction_len as u64))
}
_ => (None, None),
};

let weight_limit = <Runtime as pallet_evm::Config>::GasWeightMapping::gas_to_weight(gas_limit, true);
let proof_size_pre_execution = cumulus_primitives_storage_weight_reclaim::get_proof_size();
let transaction_pov = TransactionPov::new(weight_limit, estimated_transaction_len as u64, proof_size_pre_execution);
<Runtime as pallet_evm::Config>::Runner::create(
from,
data,
Expand All @@ -936,8 +916,7 @@ impl_runtime_apis! {
access_list.unwrap_or_default(),
false,
true,
weight_limit,
proof_size_base_cost,
Some(transaction_pov),
config.as_ref().unwrap_or(<Runtime as pallet_evm::Config>::config()),
).map_err(|err| err.error.into())
}
Expand Down

0 comments on commit 36c7b29

Please sign in to comment.