Skip to content
Merged
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
57 changes: 54 additions & 3 deletions rust/kona/bin/client/src/fpvm_evm/precompiles/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,17 @@ where
} else {
InstructionResult::PrecompileError
};
} else {
let underflow = result.gas.record_regular_cost(output.gas_used);
assert!(underflow, "Gas underflow is not possible");
} else if result.gas.record_regular_cost(output.gas_used) {
result.result = InstructionResult::Return;
result.output = output.bytes;
} else {
// Mirror revm's `EthPrecompiles::run`: a precompile reporting more gas than the
// call limit gracefully out-of-gases instead of panicking. Unreachable for the
// registered precompile set (each checks cost <= gas_limit before returning `Ok`),
// but matching upstream keeps the FPVM and op-reth aligned by construction and
// avoids halting the fault-proof program on a future precompile that omits the check.
result.gas.spend_all();
result.result = InstructionResult::PrecompileOOG;
}

Ok(Some(result))
Expand Down Expand Up @@ -396,6 +402,51 @@ mod test {
assert_eq!(interpreter_result.output.as_ref(), b"mock");
}

/// A mock accelerated precompile that reports spending more gas than the call limit.
fn overspending_accelerated_precompile<H, O>(
_input: &[u8],
gas_limit: u64,
_hint_writer: &H,
_oracle_reader: &O,
) -> EthPrecompileResult
where
H: HintWriterClient + Send + Sync,
O: PreimageOracleClient + Send + Sync,
{
Ok(revm::precompile::EthPrecompileOutput::new(
gas_limit.saturating_add(1),
Bytes::from_static(b"overspend"),
))
}

#[test]
fn test_run_overspending_precompile_oogs_without_panicking() {
let (hint_chan, preimage_chan) = (
kona_preimage::BidirectionalChannel::new().unwrap(),
kona_preimage::BidirectionalChannel::new().unwrap(),
);
let hint_writer = kona_preimage::HintWriter::new(hint_chan.client);
let oracle_reader = kona_preimage::OracleReader::new(preimage_chan.client);

let mut ctx = create_test_context();

let mut precompiles =
OpFpvmPrecompiles::new_with_spec(OpSpecId::BEDROCK, hint_writer, oracle_reader);

// A precompile that reports gas_used > gas_limit must gracefully OOG, matching
// revm's `EthPrecompiles::run`, rather than panicking the fault-proof program.
precompiles
.accelerated_precompiles
.insert(ECRECOVER_ADDR, overspending_accelerated_precompile);

let call_inputs = create_call_inputs(ECRECOVER_ADDR, Bytes::from_static(b"test"), 1000);

let result = precompiles.run(&mut ctx, &call_inputs).unwrap().unwrap();
assert_eq!(result.result, InstructionResult::PrecompileOOG);
assert!(result.output.is_empty());
assert_eq!(result.gas.remaining(), 0);
}

#[test]
fn test_run_default_precompile_sha256() {
let (hint_chan, preimage_chan) = (
Expand Down
Loading