Skip to content
This repository was archived by the owner on Nov 25, 2024. It is now read-only.

Commit 4d258ee

Browse files
committed
feat: add AUTHCALL instruction
1 parent 821d4d9 commit 4d258ee

File tree

1 file changed

+64
-4
lines changed

1 file changed

+64
-4
lines changed

crates/instructions/src/eip3074.rs

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
use crate::{context::InstructionsContext, BoxedInstructionWithOpCode};
22
use revm::{Database, Evm};
3-
use revm_interpreter::{pop, resize_memory, InstructionResult, Interpreter};
3+
use revm_interpreter::{
4+
gas, instructions::host::get_memory_input_and_out_ranges, pop, pop_address, resize_memory,
5+
CallContext, CallInputs, CallScheme, InstructionResult, Interpreter, InterpreterAction,
6+
Transfer,
7+
};
48
use revm_precompile::secp256k1::ecrecover;
5-
use revm_primitives::{alloy_primitives::B512, keccak256, Address, B256};
9+
use revm_primitives::{alloy_primitives::B512, keccak256, Address, B256, U256};
610

711
const AUTH_OPCODE: u8 = 0xF6;
812
const AUTHCALL_OPCODE: u8 = 0xF7;
@@ -120,9 +124,65 @@ fn auth_instruction<EXT, DB: Database>(
120124
fn authcall_instruction<EXT, DB: Database>(
121125
interp: &mut Interpreter,
122126
_evm: &mut Evm<'_, EXT, DB>,
123-
_ctx: &InstructionsContext,
127+
ctx: &InstructionsContext,
124128
) {
125-
interp.gas.record_cost(133);
129+
let authorized = match ctx.get(AUTORIZED_VAR_NAME) {
130+
Some(address) => Address::from_slice(&address),
131+
None => {
132+
interp.instruction_result = InstructionResult::Stop;
133+
return;
134+
}
135+
};
136+
137+
pop!(interp, local_gas_limit);
138+
pop_address!(interp, to);
139+
// max gas limit is not possible in real ethereum situation.
140+
let _local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
141+
142+
pop!(interp, value);
143+
if interp.is_static && value != U256::ZERO {
144+
interp.instruction_result = InstructionResult::CallNotAllowedInsideStatic;
145+
return;
146+
}
147+
148+
let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(interp) else {
149+
return;
150+
};
151+
152+
let Some(mut gas_limit) =
153+
// TODO: calc_call_gas requires SPEC.
154+
//calc_call_gas(interp, evm, to, value != U256::ZERO, local_gas_limit, true, true)
155+
Some(100)
156+
else {
157+
return;
158+
};
159+
160+
gas!(interp, gas_limit);
161+
162+
// add call stipend if there is value to be transferred.
163+
if value != U256::ZERO {
164+
gas_limit = gas_limit.saturating_add(gas::CALL_STIPEND);
165+
}
166+
167+
// Call host to interact with target contract
168+
interp.next_action = InterpreterAction::Call {
169+
inputs: Box::new(CallInputs {
170+
contract: to,
171+
transfer: Transfer { source: interp.contract.address, target: to, value },
172+
input,
173+
gas_limit,
174+
context: CallContext {
175+
address: to,
176+
caller: authorized,
177+
code_address: to,
178+
apparent_value: value,
179+
scheme: CallScheme::Call,
180+
},
181+
is_static: interp.is_static,
182+
return_memory_offset,
183+
}),
184+
};
185+
interp.instruction_result = InstructionResult::CallOrCreate;
126186
}
127187

128188
#[cfg(test)]

0 commit comments

Comments
 (0)