Skip to content

Commit 5b24f61

Browse files
authored
chore: add ReentrancySentryOOG for SSTORE (bluealloy#1795)
* feat: add ReentrancySentryOOG for SSTORE Signed-off-by: jsvisa <[email protected]> * sstore_cost return u64 instead of Option Signed-off-by: jsvisa <[email protected]> * fix testcase Signed-off-by: jsvisa <[email protected]> --------- Signed-off-by: jsvisa <[email protected]>
1 parent 3562d2e commit 5b24f61

File tree

5 files changed

+25
-22
lines changed

5 files changed

+25
-22
lines changed

crates/interpreter/src/gas/calc.rs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -185,28 +185,21 @@ pub const fn sload_cost(spec_id: SpecId, is_cold: bool) -> u64 {
185185

186186
/// `SSTORE` opcode cost calculation.
187187
#[inline]
188-
pub fn sstore_cost(spec_id: SpecId, vals: &SStoreResult, gas: u64, is_cold: bool) -> Option<u64> {
189-
// EIP-1706 Disable SSTORE with gasleft lower than call stipend
190-
if spec_id.is_enabled_in(SpecId::ISTANBUL) && gas <= CALL_STIPEND {
191-
return None;
192-
}
193-
188+
pub fn sstore_cost(spec_id: SpecId, vals: &SStoreResult, is_cold: bool) -> u64 {
194189
if spec_id.is_enabled_in(SpecId::BERLIN) {
195190
// Berlin specification logic
196191
let mut gas_cost = istanbul_sstore_cost::<WARM_STORAGE_READ_COST, WARM_SSTORE_RESET>(vals);
197192

198193
if is_cold {
199194
gas_cost += COLD_SLOAD_COST;
200195
}
201-
Some(gas_cost)
196+
gas_cost
202197
} else if spec_id.is_enabled_in(SpecId::ISTANBUL) {
203198
// Istanbul logic
204-
Some(istanbul_sstore_cost::<INSTANBUL_SLOAD_GAS, SSTORE_RESET>(
205-
vals,
206-
))
199+
istanbul_sstore_cost::<INSTANBUL_SLOAD_GAS, SSTORE_RESET>(vals)
207200
} else {
208201
// Frontier logic
209-
Some(frontier_sstore_cost(vals))
202+
frontier_sstore_cost(vals)
210203
}
211204
}
212205

crates/interpreter/src/instruction_result.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ pub enum InstructionResult {
5050
PrecompileOOG,
5151
/// Out of gas error encountered while calling an invalid operand.
5252
InvalidOperandOOG,
53+
/// Out of gas error encountered while checking for reentrancy sentry.
54+
ReentrancySentryOOG,
5355
/// Unknown or invalid opcode.
5456
OpcodeNotFound,
5557
/// Invalid `CALL` with value transfer in static context.
@@ -118,6 +120,7 @@ impl From<HaltReason> for InstructionResult {
118120
OutOfGasError::Memory => Self::MemoryOOG,
119121
OutOfGasError::MemoryLimit => Self::MemoryLimitOOG,
120122
OutOfGasError::Precompile => Self::PrecompileOOG,
123+
OutOfGasError::ReentrancySentry => Self::ReentrancySentryOOG,
121124
},
122125
HaltReason::OpcodeNotFound => Self::OpcodeNotFound,
123126
HaltReason::InvalidFEOpcode => Self::InvalidFEOpcode,
@@ -176,6 +179,7 @@ macro_rules! return_error {
176179
| InstructionResult::MemoryLimitOOG
177180
| InstructionResult::PrecompileOOG
178181
| InstructionResult::InvalidOperandOOG
182+
| InstructionResult::ReentrancySentryOOG
179183
| InstructionResult::OpcodeNotFound
180184
| InstructionResult::CallNotAllowedInsideStatic
181185
| InstructionResult::StateChangeDuringStaticCall
@@ -309,6 +313,9 @@ impl<HaltReasonT: HaltReasonTrait> From<InstructionResult> for SuccessOrHalt<Hal
309313
InstructionResult::InvalidOperandOOG => {
310314
Self::Halt(HaltReason::OutOfGas(OutOfGasError::InvalidOperand).into())
311315
}
316+
InstructionResult::ReentrancySentryOOG => {
317+
Self::Halt(HaltReason::OutOfGas(OutOfGasError::ReentrancySentry).into())
318+
}
312319
InstructionResult::OpcodeNotFound | InstructionResult::ReturnContractInNotInitEOF => {
313320
Self::Halt(HaltReason::OpcodeNotFound.into())
314321
}

crates/interpreter/src/instructions/host.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::{
2-
gas::{self, warm_cold_cost, warm_cold_cost_with_delegation},
2+
gas::{self, warm_cold_cost, warm_cold_cost_with_delegation, CALL_STIPEND},
33
interpreter::Interpreter,
44
Host, InstructionResult,
55
};
@@ -136,15 +136,16 @@ pub fn sstore<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, host:
136136
interpreter.instruction_result = InstructionResult::FatalExternalError;
137137
return;
138138
};
139-
gas_or_fail!(interpreter, {
140-
let remaining_gas = interpreter.gas.remaining();
141-
gas::sstore_cost(
142-
SPEC::SPEC_ID,
143-
&state_load.data,
144-
remaining_gas,
145-
state_load.is_cold,
146-
)
147-
});
139+
140+
// EIP-1706 Disable SSTORE with gasleft lower than call stipend
141+
if SPEC::SPEC_ID.is_enabled_in(ISTANBUL) && interpreter.gas.remaining() <= CALL_STIPEND {
142+
interpreter.instruction_result = InstructionResult::ReentrancySentryOOG;
143+
return;
144+
}
145+
gas!(
146+
interpreter,
147+
gas::sstore_cost(SPEC::SPEC_ID, &state_load.data, state_load.is_cold)
148+
);
148149
refund!(
149150
interpreter,
150151
gas::sstore_refund(SPEC::SPEC_ID, &state_load.data)

crates/interpreter/src/instructions/macros.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ macro_rules! pop_top {
250250
/// Pushes `B256` values onto the stack. Fails the instruction if the stack is full.
251251
#[macro_export]
252252
macro_rules! push_b256 {
253-
($interp:expr, $($x:expr),* $(,)?) => ($(
253+
($interp:expr, $($x:expr),* $(,)?) => ($(
254254
match $interp.stack.push_b256($x) {
255255
Ok(()) => {},
256256
Err(e) => {

crates/wiring/src/result.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,4 +463,6 @@ pub enum OutOfGasError {
463463
// When performing something that takes a U256 and casts down to a u64, if its too large this would fire
464464
// i.e. in `as_usize_or_fail`
465465
InvalidOperand,
466+
// When performing SSTORE the gasleft is less than or equal to 2300
467+
ReentrancySentry,
466468
}

0 commit comments

Comments
 (0)