macro_rules! pop {
( $machine:expr, $( $x:ident ),* ) => (
$(
let $x = $machine.stack.pop().unwrap();
)*
);
( $machine:expr, $( $x:ident : $t: ty ),* ) => (
$(
let $x: $t = $machine.stack.pop().unwrap().into();
)*
);
}
macro_rules! push {
( $machine:expr, $( $x:expr ),* ) => (
$(
$machine.stack.push($x).unwrap();
)*
)
}
macro_rules! op2 {
( $machine:expr, $op:ident ) => {{
pop!($machine, op1, op2);
push!($machine, op1.$op(op2).into());
}};
( $machine:expr, $op:ident, $t:ty ) => {{
pop!($machine, op1: $t, op2: $t);
push!($machine, op1.$op(op2).into());
}};
}
macro_rules! op2_ref {
( $machine:expr, $op:ident ) => {{
pop!($machine, op1, op2);
push!($machine, op1.$op(&op2).into());
}};
( $machine:expr, $op:ident, $t:ty ) => {{
pop!($machine, op1: $t, op2: $t);
push!($machine, op1.$op(&op2).into());
}};
}
mod arithmetic;
mod bitwise;
mod environment;
mod flow;
mod system;
#[cfg(not(feature = "std"))]
use alloc::rc::Rc;
#[cfg(feature = "std")]
use std::rc::Rc;
use super::util::{copy_from_memory, copy_into_memory};
use super::{Control, Runtime, State};
use crate::{Instruction, Memory, Patch};
use bigint::{Address, Gas, M256, MI256, U256};
#[cfg(not(feature = "std"))]
use core::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Rem, Sub};
#[cfg(feature = "std")]
use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Rem, Sub};
#[allow(unused_variables)]
pub fn run_opcode<M: Memory, P: Patch>(
pc: (Instruction, usize),
state: &mut State<M, P>,
runtime: &Runtime,
stipend_gas: Gas,
after_gas: Gas,
) -> Option<Control> {
match pc.0 {
Instruction::STOP => Some(Control::Stop),
Instruction::ADD => {
op2!(state, add);
None
}
Instruction::MUL => {
op2!(state, mul);
None
}
Instruction::SUB => {
op2!(state, sub);
None
}
Instruction::DIV => {
op2!(state, div);
None
}
Instruction::SDIV => {
op2!(state, div, MI256);
None
}
Instruction::MOD => {
op2!(state, rem);
None
}
Instruction::SMOD => {
op2!(state, rem, MI256);
None
}
Instruction::ADDMOD => {
arithmetic::addmod(state);
None
}
Instruction::MULMOD => {
arithmetic::mulmod(state);
None
}
Instruction::EXP => {
arithmetic::exp(state);
None
}
Instruction::SIGNEXTEND => {
arithmetic::signextend(state);
None
}
Instruction::LT => {
op2_ref!(state, lt);
None
}
Instruction::GT => {
op2_ref!(state, gt);
None
}
Instruction::SLT => {
op2_ref!(state, lt, MI256);
None
}
Instruction::SGT => {
op2_ref!(state, gt, MI256);
None
}
Instruction::EQ => {
op2_ref!(state, eq);
None
}
Instruction::ISZERO => {
bitwise::iszero(state);
None
}
Instruction::AND => {
op2!(state, bitand);
None
}
Instruction::OR => {
op2!(state, bitor);
None
}
Instruction::XOR => {
op2!(state, bitxor);
None
}
Instruction::NOT => {
bitwise::not(state);
None
}
Instruction::BYTE => {
bitwise::byte(state);
None
}
Instruction::SHL => {
bitwise::shl(state);
None
}
Instruction::SHR => {
bitwise::shr(state);
None
}
Instruction::SAR => {
bitwise::sar(state);
None
}
Instruction::SHA3 => {
system::sha3(state);
None
}
Instruction::ADDRESS => {
push!(state, state.context.address.into());
None
}
Instruction::BALANCE => {
pop!(state, address: Address);
push!(state, state.account_state.balance(address).unwrap().into());
None
}
Instruction::ORIGIN => {
push!(state, state.context.origin.into());
None
}
Instruction::CALLER => {
push!(state, state.context.caller.into());
None
}
Instruction::CALLVALUE => {
push!(state, state.context.apprent_value.into());
None
}
Instruction::CALLDATALOAD => {
environment::calldataload(state);
None
}
Instruction::CALLDATASIZE => {
push!(state, state.context.data.len().into());
None
}
Instruction::CALLDATACOPY => {
pop!(state, memory_index: U256, data_index: U256, len: U256);
copy_into_memory(
&mut state.memory,
state.context.data.as_slice(),
memory_index,
data_index,
len,
);
None
}
Instruction::CODESIZE => {
push!(state, state.context.code.len().into());
None
}
Instruction::CODECOPY => {
pop!(state, memory_index: U256, code_index: U256, len: U256);
copy_into_memory(
&mut state.memory,
state.context.code.as_slice(),
memory_index,
code_index,
len,
);
None
}
Instruction::GASPRICE => {
push!(state, state.context.gas_price.into());
None
}
Instruction::EXTCODESIZE => {
pop!(state, address: Address);
push!(state, state.account_state.code(address).unwrap().len().into());
None
}
Instruction::EXTCODECOPY => {
pop!(state, address: Address);
pop!(state, memory_index: U256, code_index: U256, len: U256);
copy_into_memory(
&mut state.memory,
&state.account_state.code(address).unwrap(),
memory_index,
code_index,
len,
);
None
}
Instruction::EXTCODEHASH => {
environment::extcodehash(state);
None
}
Instruction::RETURNDATASIZE => {
push!(state, state.ret.len().into());
None
}
Instruction::RETURNDATACOPY => {
pop!(state, memory_index: U256, data_index: U256, len: U256);
copy_into_memory(&mut state.memory, state.ret.as_slice(), memory_index, data_index, len);
None
}
Instruction::BLOCKHASH => {
pop!(state, number: U256);
let current_number = runtime.block.number;
if !(number >= current_number || current_number - number > U256::from(256u64)) {
push!(state, M256::from(runtime.blockhash_state.get(number).unwrap()));
} else {
push!(state, M256::zero());
}
None
}
Instruction::COINBASE => {
push!(state, M256::from(runtime.block.beneficiary));
None
}
Instruction::TIMESTAMP => {
push!(state, M256::from(runtime.block.timestamp));
None
}
Instruction::NUMBER => {
push!(state, M256::from(runtime.block.number));
None
}
Instruction::DIFFICULTY => {
push!(state, M256::from(runtime.block.difficulty));
None
}
Instruction::GASLIMIT => {
push!(state, runtime.block.gas_limit.into());
None
}
Instruction::POP => {
state.stack.pop().unwrap();
None
}
Instruction::MLOAD => {
flow::mload(state);
None
}
Instruction::MSTORE => {
flow::mstore(state);
None
}
Instruction::MSTORE8 => {
flow::mstore8(state);
None
}
Instruction::SLOAD => {
flow::sload(state);
None
}
Instruction::SSTORE => {
flow::sstore(state);
None
}
Instruction::JUMP => {
pop!(state, dest);
Some(Control::Jump(dest))
}
Instruction::JUMPI => {
pop!(state, dest, value);
if value != M256::zero() {
Some(Control::Jump(dest))
} else {
None
}
}
Instruction::PC => {
push!(state, pc.1.into());
None
}
Instruction::MSIZE => {
push!(state, (state.memory_cost * Gas::from(32u64)).into());
None
}
Instruction::GAS => {
push!(state, after_gas.into());
None
}
Instruction::JUMPDEST => None,
Instruction::PUSH(v) => {
push!(state, v);
None
}
Instruction::DUP(v) => {
let val = state.stack.peek(v - 1).unwrap();
push!(state, val);
None
}
Instruction::SWAP(v) => {
let val1 = state.stack.peek(0).unwrap();
let val2 = state.stack.peek(v).unwrap();
state.stack.set(0, val2).unwrap();
state.stack.set(v, val1).unwrap();
None
}
Instruction::LOG(v) => {
system::log(state, v);
None
}
Instruction::CREATE => system::create::<M, P>(state, after_gas, false),
Instruction::CREATE2 => system::create::<M, P>(state, after_gas, true),
Instruction::CALL => system::call::<M, P>(state, stipend_gas, after_gas, false),
Instruction::CALLCODE => system::call::<M, P>(state, stipend_gas, after_gas, true),
Instruction::DELEGATECALL => system::delegate_call::<M, P>(state, after_gas),
Instruction::STATICCALL => system::static_call::<M, P>(state, stipend_gas, after_gas),
Instruction::RETURN => {
pop!(state, start: U256, len: U256);
state.out = Rc::new(copy_from_memory(&state.memory, start, len));
Some(Control::Stop)
}
Instruction::REVERT => {
pop!(state, start: U256, len: U256);
state.out = Rc::new(copy_from_memory(&state.memory, start, len));
Some(Control::Revert)
}
Instruction::SUICIDE => {
system::suicide(state);
Some(Control::Stop)
}
}
}