Skip to content

Commit

Permalink
Merge pull request #225 from moonbeam-foundation/elois-storage-oog
Browse files Browse the repository at this point in the history
propagate OOG from pov and MBIP5
  • Loading branch information
librelois authored Sep 16, 2024
2 parents 9a74ea7 + 09d0188 commit 42a7a8e
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 27 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.

9 changes: 5 additions & 4 deletions frame/evm/src/runner/meter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,13 @@ impl StorageMeter {
/// Records the given amount of storage usage. The amount is added to the current usage.
/// If the limit is reached, an error is returned.
pub fn record(&mut self, amount: u64) -> Result<(), MeterError> {
let usage = self
.usage
.checked_add(amount)
.ok_or(MeterError::LimitExceeded)?;
let usage = self.usage.checked_add(amount).ok_or_else(|| {
fp_evm::set_storage_oog();
MeterError::LimitExceeded
})?;

if usage > self.limit {
fp_evm::set_storage_oog();
return Err(MeterError::LimitExceeded);
}
self.usage = usage;
Expand Down
52 changes: 29 additions & 23 deletions frame/evm/src/runner/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,6 @@ where
let fee = T::OnChargeTransaction::withdraw_fee(&source, total_fee)
.map_err(|e| RunnerError { error: e, weight })?;

// Execute the EVM call.
let vicinity = Vicinity {
gas_price: base_fee,
origin: source,
Expand All @@ -281,28 +280,34 @@ where
let state = SubstrateStackState::new(&vicinity, metadata, maybe_weight_info, storage_limit);
let mut executor = StackExecutor::new_with_precompiles(state, config, precompiles);

let (reason, retv) = f(&mut executor);

// Compute the storage gas cost based on the storage growth.
let storage_gas = match &executor.state().storage_meter {
Some(storage_meter) => storage_meter.storage_to_gas(storage_growth_ratio),
None => 0,
};

let pov_gas = match executor.state().weight_info() {
Some(weight_info) => weight_info
.proof_size_usage
.unwrap_or_default()
.saturating_mul(T::GasLimitPovSizeRatio::get()),
None => 0,
};

// Post execution.
let used_gas = executor.used_gas();
let effective_gas = U256::from(core::cmp::max(
core::cmp::max(used_gas, pov_gas),
storage_gas,
));
// Execute the EVM call.
let (reason, retv, used_gas, effective_gas) =
fp_evm::handle_storage_oog::<R, _>(gas_limit, || {
let (reason, retv) = f(&mut executor);

// Compute the storage gas cost based on the storage growth.
let storage_gas = match &executor.state().storage_meter {
Some(storage_meter) => storage_meter.storage_to_gas(storage_growth_ratio),
None => 0,
};

let pov_gas = match executor.state().weight_info() {
Some(weight_info) => weight_info
.proof_size_usage
.unwrap_or_default()
.saturating_mul(T::GasLimitPovSizeRatio::get()),
None => 0,
};

// Post execution.
let used_gas = executor.used_gas();
let effective_gas = U256::from(core::cmp::max(
core::cmp::max(used_gas, pov_gas),
storage_gas,
));

(reason, retv, used_gas, effective_gas)
});

let actual_fee = effective_gas.saturating_mul(total_fee_per_gas);
let actual_base_fee = effective_gas.saturating_mul(base_fee);
Expand Down Expand Up @@ -1138,6 +1143,7 @@ where

let actual_size = Pallet::<T>::account_code_metadata(address).size;
if actual_size > pre_size {
fp_evm::set_storage_oog();
return Err(ExitError::OutOfGas);
}
// Refund unused proof size
Expand Down
3 changes: 3 additions & 0 deletions primitives/evm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ targets = ["x86_64-unknown-linux-gnu"]

[dependencies]
evm = { workspace = true, features = ["with-codec"] }
environmental = { workspace = true }
num_enum = { workspace = true, default-features = false }
scale-codec = { package = "parity-scale-codec", workspace = true }
scale-info = { workspace = true }
serde = { workspace = true, optional = true }

# Substrate
frame-support = { workspace = true }
sp-core = { workspace = true }
Expand All @@ -26,6 +28,7 @@ default = ["std"]
std = [
"evm/std",
"evm/with-serde",
"environmental/std",
"num_enum/std",
"serde/std",
"scale-codec/std",
Expand Down
4 changes: 4 additions & 0 deletions primitives/evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
extern crate alloc;

mod precompile;
mod storage_oog;
mod validation;

use alloc::{collections::BTreeMap, vec::Vec};
Expand All @@ -43,6 +44,7 @@ pub use self::{
Precompile, PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult,
PrecompileSet, Transfer,
},
storage_oog::{handle_storage_oog, set_storage_oog},
validation::{
CheckEvmTransaction, CheckEvmTransactionConfig, CheckEvmTransactionInput,
TransactionValidationError,
Expand Down Expand Up @@ -116,6 +118,7 @@ impl WeightInfo {
fn try_consume(&self, cost: u64, limit: u64, usage: u64) -> Result<u64, ExitError> {
let usage = usage.checked_add(cost).ok_or(ExitError::OutOfGas)?;
if usage > limit {
storage_oog::set_storage_oog();
return Err(ExitError::OutOfGas);
}
Ok(usage)
Expand All @@ -140,6 +143,7 @@ impl WeightInfo {
{
let proof_size_usage = self.try_consume(cost, proof_size_limit, proof_size_usage)?;
if proof_size_usage > proof_size_limit {
storage_oog::set_storage_oog();
return Err(ExitError::OutOfGas);
}
self.proof_size_usage = Some(proof_size_usage);
Expand Down
52 changes: 52 additions & 0 deletions primitives/evm/src/storage_oog.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// This file is part of Frontier.

// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

environmental::environmental!(STORAGE_OOG: bool);

use crate::{ExitError, ExitReason};
use sp_core::U256;

pub fn handle_storage_oog<R, F>(gas_limit: u64, f: F) -> (ExitReason, R, u64, U256)
where
F: FnOnce() -> (ExitReason, R, u64, U256),
R: Default,
{
STORAGE_OOG::using_once(&mut false, || {
let (reason, retv, used_gas, effective_gas) = f();

STORAGE_OOG::with(|storage_oog| {
if *storage_oog {
(
ExitReason::Error(ExitError::OutOfGas),
Default::default(),
used_gas,
U256([gas_limit, 0, 0, 0]),
)
} else {
(reason, retv, used_gas, effective_gas)
}
})
// This should always return `Some`, but let's play it safe.
.expect("STORAGE_OOG not defined")
})
}

pub fn set_storage_oog() {
STORAGE_OOG::with(|storage_oog| {
*storage_oog = true;
});
}

0 comments on commit 42a7a8e

Please sign in to comment.