Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: add ReentrancySentryOOG for SSTORE #1795

Merged
merged 3 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 4 additions & 11 deletions crates/interpreter/src/gas/calc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,28 +185,21 @@ pub const fn sload_cost(spec_id: SpecId, is_cold: bool) -> u64 {

/// `SSTORE` opcode cost calculation.
#[inline]
pub fn sstore_cost(spec_id: SpecId, vals: &SStoreResult, gas: u64, is_cold: bool) -> Option<u64> {
// EIP-1706 Disable SSTORE with gasleft lower than call stipend
if spec_id.is_enabled_in(SpecId::ISTANBUL) && gas <= CALL_STIPEND {
return None;
}

pub fn sstore_cost(spec_id: SpecId, vals: &SStoreResult, is_cold: bool) -> u64 {
if spec_id.is_enabled_in(SpecId::BERLIN) {
// Berlin specification logic
let mut gas_cost = istanbul_sstore_cost::<WARM_STORAGE_READ_COST, WARM_SSTORE_RESET>(vals);

if is_cold {
gas_cost += COLD_SLOAD_COST;
}
Some(gas_cost)
gas_cost
} else if spec_id.is_enabled_in(SpecId::ISTANBUL) {
// Istanbul logic
Some(istanbul_sstore_cost::<INSTANBUL_SLOAD_GAS, SSTORE_RESET>(
vals,
))
istanbul_sstore_cost::<INSTANBUL_SLOAD_GAS, SSTORE_RESET>(vals)
} else {
// Frontier logic
Some(frontier_sstore_cost(vals))
frontier_sstore_cost(vals)
}
}

Expand Down
7 changes: 7 additions & 0 deletions crates/interpreter/src/instruction_result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ pub enum InstructionResult {
PrecompileOOG,
/// Out of gas error encountered while calling an invalid operand.
InvalidOperandOOG,
/// Out of gas error encountered while checking for reentrancy sentry.
ReentrancySentryOOG,
/// Unknown or invalid opcode.
OpcodeNotFound,
/// Invalid `CALL` with value transfer in static context.
Expand Down Expand Up @@ -118,6 +120,7 @@ impl From<HaltReason> for InstructionResult {
OutOfGasError::Memory => Self::MemoryOOG,
OutOfGasError::MemoryLimit => Self::MemoryLimitOOG,
OutOfGasError::Precompile => Self::PrecompileOOG,
OutOfGasError::ReentrancySentry => Self::ReentrancySentryOOG,
},
HaltReason::OpcodeNotFound => Self::OpcodeNotFound,
HaltReason::InvalidFEOpcode => Self::InvalidFEOpcode,
Expand Down Expand Up @@ -176,6 +179,7 @@ macro_rules! return_error {
| InstructionResult::MemoryLimitOOG
| InstructionResult::PrecompileOOG
| InstructionResult::InvalidOperandOOG
| InstructionResult::ReentrancySentryOOG
| InstructionResult::OpcodeNotFound
| InstructionResult::CallNotAllowedInsideStatic
| InstructionResult::StateChangeDuringStaticCall
Expand Down Expand Up @@ -309,6 +313,9 @@ impl<HaltReasonT: HaltReasonTrait> From<InstructionResult> for SuccessOrHalt<Hal
InstructionResult::InvalidOperandOOG => {
Self::Halt(HaltReason::OutOfGas(OutOfGasError::InvalidOperand).into())
}
InstructionResult::ReentrancySentryOOG => {
Self::Halt(HaltReason::OutOfGas(OutOfGasError::ReentrancySentry).into())
}
InstructionResult::OpcodeNotFound | InstructionResult::ReturnContractInNotInitEOF => {
Self::Halt(HaltReason::OpcodeNotFound.into())
}
Expand Down
21 changes: 11 additions & 10 deletions crates/interpreter/src/instructions/host.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
gas::{self, warm_cold_cost, warm_cold_cost_with_delegation},
gas::{self, warm_cold_cost, warm_cold_cost_with_delegation, CALL_STIPEND},
interpreter::Interpreter,
Host, InstructionResult,
};
Expand Down Expand Up @@ -136,15 +136,16 @@ pub fn sstore<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, host:
interpreter.instruction_result = InstructionResult::FatalExternalError;
return;
};
gas_or_fail!(interpreter, {
let remaining_gas = interpreter.gas.remaining();
gas::sstore_cost(
SPEC::SPEC_ID,
&state_load.data,
remaining_gas,
state_load.is_cold,
)
});

// EIP-1706 Disable SSTORE with gasleft lower than call stipend
if SPEC::SPEC_ID.is_enabled_in(ISTANBUL) && interpreter.gas.remaining() <= CALL_STIPEND {
interpreter.instruction_result = InstructionResult::ReentrancySentryOOG;
return;
}
gas!(
interpreter,
gas::sstore_cost(SPEC::SPEC_ID, &state_load.data, state_load.is_cold)
);
refund!(
interpreter,
gas::sstore_refund(SPEC::SPEC_ID, &state_load.data)
Expand Down
2 changes: 1 addition & 1 deletion crates/interpreter/src/instructions/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ macro_rules! pop_top {
/// Pushes `B256` values onto the stack. Fails the instruction if the stack is full.
#[macro_export]
macro_rules! push_b256 {
($interp:expr, $($x:expr),* $(,)?) => ($(
($interp:expr, $($x:expr),* $(,)?) => ($(
match $interp.stack.push_b256($x) {
Ok(()) => {},
Err(e) => {
Expand Down
2 changes: 2 additions & 0 deletions crates/wiring/src/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -463,4 +463,6 @@ pub enum OutOfGasError {
// When performing something that takes a U256 and casts down to a u64, if its too large this would fire
// i.e. in `as_usize_or_fail`
InvalidOperand,
// When performing SSTORE the gasleft is less than or equal to 2300
ReentrancySentry,
}
Loading