use std::cmp;
use ethereum_types::{Address, BigEndianHash, H256, U256, U512};
use log::debug;
use crate::evm::common;
use crate::evm::err;
use crate::evm::ext;
use crate::evm::memory;
use crate::evm::opcodes;
use crate::evm::stack;
#[derive(Clone, Debug, Default)]
pub struct Context {
pub gas_limit: u64,
pub coinbase: Address,
pub number: U256,
pub timestamp: u64,
pub difficulty: U256,
}
#[derive(Clone, Debug)]
pub struct Log(pub Address, pub Vec<H256>, pub Vec<u8>);
#[derive(Clone, Debug)]
pub enum InterpreterResult {
Normal(Vec<u8>, u64, Vec<Log>),
Revert(Vec<u8>, u64),
Create(Vec<u8>, u64, Vec<Log>, Address),
}
#[derive(Clone, Debug)]
pub struct InterpreterConf {
pub no_empty: bool,
pub eip1283: bool,
pub stack_limit: u64,
pub max_create_code_size: u64, pub max_call_depth: u64,
pub gas_tier_step: [u64; 8],
pub gas_exp: u64, pub gas_exp_byte: u64, pub gas_sha3: u64, pub gas_sha3_word: u64, pub gas_balance: u64, pub gas_memory: u64, pub gas_sload: u64, pub gas_sstore_noop: u64, pub gas_sstore_init: u64, pub gas_sstore_clear_refund: u64, pub gas_sstore_clean: u64, pub gas_sstore_dirty: u64, pub gas_sstore_reset_clear_refund: u64, pub gas_sstore_reset_refund: u64, pub gas_sstore_set: u64, pub gas_sstore_clear: u64, pub gas_sstore_reset: u64, pub gas_sstore_refund: u64, pub gas_log: u64, pub gas_log_data: u64, pub gas_log_topic: u64, pub gas_create: u64, pub gas_jumpdest: u64, pub gas_copy: u64, pub gas_call: u64, pub gas_call_value_transfer: u64, pub gas_call_stipend: u64, pub gas_self_destruct: u64, pub gas_self_destruct_refund: u64, pub gas_extcode: u64, pub gas_call_new_account: u64, pub gas_self_destruct_new_account: u64, pub gas_ext_code_hash: u64, pub gas_chain_id: u64, pub gas_self_balance: u64, }
impl Default for InterpreterConf {
fn default() -> Self {
InterpreterConf {
no_empty: false,
eip1283: false,
stack_limit: 1024,
max_create_code_size: std::u64::MAX,
max_call_depth: 1024,
gas_tier_step: [0, 2, 3, 5, 8, 10, 20, 0],
gas_exp: 10,
gas_exp_byte: 10, gas_sha3: 30,
gas_sha3_word: 6,
gas_balance: 20, gas_memory: 3,
gas_sload: 50, gas_sstore_noop: 200,
gas_sstore_init: 20000,
gas_sstore_clear_refund: 15000,
gas_sstore_clean: 5000,
gas_sstore_dirty: 200,
gas_sstore_reset_clear_refund: 19800,
gas_sstore_reset_refund: 4800,
gas_sstore_set: 20000,
gas_sstore_clear: 5000,
gas_sstore_reset: 5000,
gas_sstore_refund: 15000,
gas_log: 375,
gas_log_data: 8,
gas_log_topic: 375,
gas_create: 32000,
gas_jumpdest: 1,
gas_copy: 3,
gas_call: 40, gas_call_value_transfer: 9000,
gas_call_stipend: 2300,
gas_self_destruct: 0, gas_self_destruct_refund: 24000,
gas_extcode: 20, gas_call_new_account: 25000,
gas_self_destruct_new_account: 0, gas_ext_code_hash: 400,
gas_chain_id: 2,
gas_self_balance: 5,
}
}
}
#[derive(Clone, Debug, Default)]
pub struct Contract {
pub code_address: Address,
pub code_data: Vec<u8>,
}
#[derive(Clone, Debug, Default)]
pub struct InterpreterParams {
pub origin: Address, pub sender: Address, pub receiver: Address, pub address: Address,
pub value: U256,
pub input: Vec<u8>,
pub nonce: U256,
pub gas_limit: u64,
pub gas_price: U256,
pub base_fee: U256,
pub read_only: bool,
pub contract: Contract,
pub extra: H256,
pub is_create: bool,
pub disable_transfer_value: bool,
pub depth: u64,
}
pub struct Interpreter {
pub context: Context,
pub cfg: InterpreterConf,
pub data_provider: Box<dyn ext::DataProvider>,
pub params: InterpreterParams,
gas: u64,
stack: stack::Stack<U256>,
mem: memory::Memory,
logs: Vec<Log>,
return_data: Vec<u8>,
mem_gas: u64,
gas_tmp: u64,
}
impl Interpreter {
pub fn new(
context: Context,
cfg: InterpreterConf,
data_provider: Box<dyn ext::DataProvider>,
params: InterpreterParams,
) -> Self {
let gas = params.gas_limit;
Interpreter {
context,
cfg,
data_provider,
params,
gas,
stack: stack::Stack::with_capacity(1024),
mem: memory::Memory::default(),
logs: Vec::new(),
return_data: Vec::new(),
mem_gas: 0,
gas_tmp: 0,
}
}
#[allow(clippy::cognitive_complexity)]
pub fn run(&mut self) -> Result<InterpreterResult, err::Error> {
let mut pc = 0;
while let Some(op) = self.get_op(pc)? {
pc += 1;
self.trace(&op, pc);
let stack_require = op.stack_require();
if !self.stack.require(stack_require as usize) {
return Err(err::Error::StackUnderflow);
}
if self.stack.len() as u64 - op.stack_require() + op.stack_returns() > self.cfg.stack_limit {
return Err(err::Error::OutOfStack);
}
if self.params.read_only && op.state_changes() {
return Err(err::Error::MutableCallInStaticContext);
}
let op_gas = self.cfg.gas_tier_step[op.gas_price_tier().idx()];
self.use_gas(op_gas)?;
match op {
opcodes::OpCode::EXP => {
let expon = self.stack.back(1);
let bytes = ((expon.bits() + 7) / 8) as u64;
let gas = self.cfg.gas_exp + self.cfg.gas_exp_byte * bytes;
self.use_gas(gas)?;
}
opcodes::OpCode::SHA3 => {
let mem_offset = self.stack.back(0);
let mem_len = self.stack.back(1);
self.mem_gas_work(mem_offset, mem_len)?;
self.use_gas(self.cfg.gas_sha3)?;
self.use_gas(common::to_word_size(mem_len.low_u64()) * self.cfg.gas_sha3_word)?;
}
opcodes::OpCode::BALANCE => {
self.use_gas(self.cfg.gas_balance)?;
}
opcodes::OpCode::SELFBALANCE => {
self.use_gas(self.cfg.gas_self_balance)?;
}
opcodes::OpCode::CHAINID => {
self.use_gas(self.cfg.gas_chain_id)?;
}
opcodes::OpCode::CALLDATACOPY => {
let mem_offset = self.stack.back(0);
let mem_len = self.stack.back(2);
self.mem_gas_work(mem_offset, mem_len)?;
let gas = common::to_word_size(mem_len.low_u64()) * self.cfg.gas_copy;
self.use_gas(gas)?;
}
opcodes::OpCode::CODECOPY => {
let mem_offset = self.stack.back(0);
let mem_len = self.stack.back(2);
self.mem_gas_work(mem_offset, mem_len)?;
let gas = common::to_word_size(mem_len.low_u64()) * self.cfg.gas_copy;
self.use_gas(gas)?;
}
opcodes::OpCode::EXTCODESIZE => {
self.use_gas(self.cfg.gas_extcode)?;
}
opcodes::OpCode::EXTCODECOPY => {
let mem_offset = self.stack.back(1);
let mem_len = self.stack.back(3);
self.use_gas(self.cfg.gas_extcode)?;
self.mem_gas_work(mem_offset, mem_len)?;
let gas = common::to_word_size(mem_len.low_u64()) * self.cfg.gas_copy;
self.use_gas(gas)?;
}
opcodes::OpCode::EXTCODEHASH => {
self.use_gas(self.cfg.gas_ext_code_hash)?;
}
opcodes::OpCode::RETURNDATACOPY => {
let mem_offset = self.stack.back(0);
let size = self.stack.back(2);
self.mem_gas_work(mem_offset, size)?;
let size_min = cmp::min(self.return_data.len() as u64, size.low_u64());
let gas = common::to_word_size(size_min) * self.cfg.gas_copy;
self.use_gas(gas)?;
}
opcodes::OpCode::MLOAD => {
let mem_offset = self.stack.back(0);
let mem_len = U256::from(32);
self.mem_gas_work(mem_offset, mem_len)?;
}
opcodes::OpCode::MSTORE => {
let mem_offset = self.stack.back(0);
let mem_len = U256::from(32);
self.mem_gas_work(mem_offset, mem_len)?;
}
opcodes::OpCode::MSTORE8 => {
let mem_offset = self.stack.back(0);
self.mem_gas_work(mem_offset, U256::one())?;
}
opcodes::OpCode::SLOAD => {
self.use_gas(self.cfg.gas_sload)?;
}
opcodes::OpCode::SSTORE => {
let address = H256::from_uint(&self.stack.back(0));
let current_value = U256::from(
self.data_provider
.get_storage(&self.params.address, &address)
.as_bytes(),
);
let new_value = self.stack.back(1);
let original_value = U256::from(
self.data_provider
.get_storage_origin(&self.params.address, &address)
.as_bytes(),
);
let gas: u64 = {
if self.cfg.eip1283 {
if current_value == new_value {
self.cfg.gas_sstore_noop
} else if original_value == current_value {
if original_value.is_zero() {
self.cfg.gas_sstore_init
} else {
if new_value.is_zero() {
self.data_provider
.add_refund(&self.params.origin, self.cfg.gas_sstore_clear_refund);
}
self.cfg.gas_sstore_clean
}
} else {
if !original_value.is_zero() {
if current_value.is_zero() {
self.data_provider
.sub_refund(&self.params.origin, self.cfg.gas_sstore_clear_refund);
} else if new_value.is_zero() {
self.data_provider
.add_refund(&self.params.origin, self.cfg.gas_sstore_clear_refund);
}
}
if original_value == new_value {
if original_value.is_zero() {
self.data_provider
.add_refund(&self.params.origin, self.cfg.gas_sstore_reset_clear_refund);
} else {
self.data_provider
.add_refund(&self.params.origin, self.cfg.gas_sstore_reset_refund);
}
}
self.cfg.gas_sstore_dirty
}
} else if current_value.is_zero() && !new_value.is_zero() {
self.cfg.gas_sstore_set
} else if !current_value.is_zero() && new_value.is_zero() {
self.data_provider
.add_refund(&self.params.origin, self.cfg.gas_sstore_refund);
self.cfg.gas_sstore_clear
} else {
self.cfg.gas_sstore_reset
}
};
self.use_gas(gas)?;
}
opcodes::OpCode::JUMPDEST => {
self.use_gas(self.cfg.gas_jumpdest)?;
}
opcodes::OpCode::LOG0
| opcodes::OpCode::LOG1
| opcodes::OpCode::LOG2
| opcodes::OpCode::LOG3
| opcodes::OpCode::LOG4 => {
let n = op.clone() as u8 - opcodes::OpCode::LOG0 as u8;
let mem_offset = self.stack.back(0);
let mem_len = self.stack.back(1);
self.mem_gas_work(mem_offset, mem_len)?;
let gas = self.cfg.gas_log
+ self.cfg.gas_log_topic * u64::from(n)
+ self.cfg.gas_log_data * mem_len.low_u64();
self.use_gas(gas)?;
}
opcodes::OpCode::CREATE => {
let mem_offset = self.stack.back(1);
let mem_len = self.stack.back(2);
if mem_len > U256::from(self.cfg.max_create_code_size) {
return Err(err::Error::ExccedMaxCodeSize);
}
self.mem_gas_work(mem_offset, mem_len)?;
self.use_gas(self.cfg.gas_create)?;
self.gas_tmp = self.gas - self.gas / 64;
self.use_gas(self.gas_tmp)?;
}
opcodes::OpCode::CALL | opcodes::OpCode::CALLCODE => {
let gas_req = self.stack.back(0);
let address = common::u256_to_address(&self.stack.back(1));
let value = self.stack.back(2);
let mem_offset = self.stack.back(3);
let mem_len = self.stack.back(4);
let out_offset = self.stack.back(5);
let out_len = self.stack.back(6);
self.use_gas(self.cfg.gas_call)?;
let is_value_transfer = !value.is_zero();
if op == opcodes::OpCode::CALL
&& (!self.cfg.no_empty && !self.data_provider.exist(&address)
|| (self.cfg.no_empty && is_value_transfer && self.data_provider.is_empty(&address)))
{
self.use_gas(self.cfg.gas_call_new_account)?;
}
if is_value_transfer {
self.use_gas(self.cfg.gas_call_value_transfer)?;
}
self.mem_gas_work(mem_offset, mem_len)?;
self.mem_gas_work(out_offset, out_len)?;
self.gas_tmp = cmp::min(self.gas - self.gas / 64, gas_req.low_u64());
self.use_gas(self.gas_tmp)?;
}
opcodes::OpCode::RETURN => {
let mem_offset = self.stack.back(0);
let mem_len = self.stack.back(1);
self.mem_gas_work(mem_offset, mem_len)?;
}
opcodes::OpCode::DELEGATECALL | opcodes::OpCode::STATICCALL => {
let gas_req = self.stack.back(0);
let mem_offset = self.stack.back(2);
let mem_len = self.stack.back(3);
let out_offset = self.stack.back(4);
let out_len = self.stack.back(5);
self.use_gas(self.cfg.gas_call)?;
self.mem_gas_work(mem_offset, mem_len)?;
self.mem_gas_work(out_offset, out_len)?;
self.gas_tmp = cmp::min(self.gas - self.gas / 64, gas_req.low_u64());
self.use_gas(self.gas_tmp)?;
}
opcodes::OpCode::CREATE2 => {
let mem_offset = self.stack.back(1);
let mem_len = self.stack.back(2);
if mem_len > U256::from(self.cfg.max_create_code_size) {
return Err(err::Error::ExccedMaxCodeSize);
}
self.mem_gas_work(mem_offset, mem_len)?;
self.use_gas(self.cfg.gas_create)?;
self.use_gas(common::to_word_size(mem_len.low_u64()) * self.cfg.gas_sha3_word)?;
self.gas_tmp = self.gas - self.gas / 64;
self.use_gas(self.gas_tmp)?;
}
opcodes::OpCode::REVERT => {
let mem_offset = self.stack.back(0);
let mem_len = self.stack.back(1);
self.mem_gas_work(mem_offset, mem_len)?;
}
opcodes::OpCode::SELFDESTRUCT => {
let address = self.stack.peek();
self.use_gas(self.cfg.gas_self_destruct)?;
if !self.data_provider.get_balance(&self.params.address).is_zero()
&& self.data_provider.is_empty(&common::u256_to_address(&address))
{
self.use_gas(self.cfg.gas_self_destruct_new_account)?;
}
self.data_provider
.add_refund(&self.params.origin, self.cfg.gas_self_destruct_refund);
}
_ => {}
}
match op {
opcodes::OpCode::STOP => break,
opcodes::OpCode::ADD => {
let a = self.stack.pop();
let b = self.stack.pop();
self.stack.push(a.overflowing_add(b).0);
}
opcodes::OpCode::MUL => {
let a = self.stack.pop();
let b = self.stack.pop();
self.stack.push(a.overflowing_mul(b).0);
}
opcodes::OpCode::SUB => {
let a = self.stack.pop();
let b = self.stack.pop();
self.stack.push(a.overflowing_sub(b).0);
}
opcodes::OpCode::DIV => {
let a = self.stack.pop();
let b = self.stack.pop();
self.stack.push(if b.is_zero() { U256::zero() } else { a / b })
}
opcodes::OpCode::SDIV => {
let (a, neg_a) = common::get_sign(self.stack.pop());
let (b, neg_b) = common::get_sign(self.stack.pop());
let min = (U256::one() << 255) - U256::one();
self.stack.push(if b.is_zero() {
U256::zero()
} else if a == min && b == !U256::one() {
min
} else {
common::set_sign(a / b, neg_a ^ neg_b)
})
}
opcodes::OpCode::MOD => {
let a = self.stack.pop();
let b = self.stack.pop();
self.stack.push(if !b.is_zero() { a % b } else { U256::zero() });
}
opcodes::OpCode::SMOD => {
let ua = self.stack.pop();
let ub = self.stack.pop();
let (a, sign_a) = common::get_sign(ua);
let b = common::get_sign(ub).0;
self.stack.push(if !b.is_zero() {
let c = a % b;
common::set_sign(c, sign_a)
} else {
U256::zero()
});
}
opcodes::OpCode::ADDMOD => {
let a = self.stack.pop();
let b = self.stack.pop();
let c = self.stack.pop();
self.stack.push(if !c.is_zero() {
let res = U512::from(a);
let res = res.overflowing_add(U512::from(b)).0;
let res = res % U512::from(c);
let ret: [u64; 4] = [res.0[0], res.0[1], res.0[2], res.0[3]];
U256(ret)
} else {
U256::zero()
});
}
opcodes::OpCode::MULMOD => {
let a = self.stack.pop();
let b = self.stack.pop();
let c = self.stack.pop();
self.stack.push(if !c.is_zero() {
let res = U512::from(a);
let res = res.overflowing_mul(U512::from(b)).0;
let res = res % U512::from(c);
let ret: [u64; 4] = [res.0[0], res.0[1], res.0[2], res.0[3]];
U256(ret)
} else {
U256::zero()
});
}
opcodes::OpCode::EXP => {
let base = self.stack.pop();
let expon = self.stack.pop();
let res = base.overflowing_pow(expon).0;
self.stack.push(res);
}
opcodes::OpCode::SIGNEXTEND => {
let bit = self.stack.pop();
if bit < U256::from(32) {
let number = self.stack.pop();
let bit_position = (bit.low_u64() * 8 + 7) as usize;
let bit = number.bit(bit_position);
let mask = (U256::one() << bit_position) - U256::one();
self.stack.push(if bit { number | !mask } else { number & mask });
}
}
opcodes::OpCode::LT => {
let a = self.stack.pop();
let b = self.stack.pop();
self.stack.push(common::bool_to_u256(a < b));
}
opcodes::OpCode::GT => {
let a = self.stack.pop();
let b = self.stack.pop();
self.stack.push(common::bool_to_u256(a > b));
}
opcodes::OpCode::SLT => {
let (a, neg_a) = common::get_sign(self.stack.pop());
let (b, neg_b) = common::get_sign(self.stack.pop());
let is_positive_lt = a < b && !(neg_a | neg_b);
let is_negative_lt = a > b && (neg_a & neg_b);
let has_different_signs = neg_a && !neg_b;
self.stack.push(common::bool_to_u256(
is_positive_lt | is_negative_lt | has_different_signs,
));
}
opcodes::OpCode::SGT => {
let (a, neg_a) = common::get_sign(self.stack.pop());
let (b, neg_b) = common::get_sign(self.stack.pop());
let is_positive_gt = a > b && !(neg_a | neg_b);
let is_negative_gt = a < b && (neg_a & neg_b);
let has_different_signs = !neg_a && neg_b;
self.stack.push(common::bool_to_u256(
is_positive_gt | is_negative_gt | has_different_signs,
));
}
opcodes::OpCode::EQ => {
let a = self.stack.pop();
let b = self.stack.pop();
self.stack.push(common::bool_to_u256(a == b));
}
opcodes::OpCode::ISZERO => {
let a = self.stack.pop();
self.stack.push(common::bool_to_u256(a.is_zero()));
}
opcodes::OpCode::AND => {
let a = self.stack.pop();
let b = self.stack.pop();
self.stack.push(a & b);
}
opcodes::OpCode::OR => {
let a = self.stack.pop();
let b = self.stack.pop();
self.stack.push(a | b);
}
opcodes::OpCode::XOR => {
let a = self.stack.pop();
let b = self.stack.pop();
self.stack.push(a ^ b);
}
opcodes::OpCode::NOT => {
let a = self.stack.pop();
self.stack.push(!a);
}
opcodes::OpCode::BYTE => {
let word = self.stack.pop();
let val = self.stack.pop();
let byte = if word < U256::from(32) {
(val >> (8 * (31 - word.low_u64() as usize))) & U256::from(0xff)
} else {
U256::zero()
};
self.stack.push(byte);
}
opcodes::OpCode::SHL => {
const CONST_256: U256 = U256([256, 0, 0, 0]);
let shift = self.stack.pop();
let value = self.stack.pop();
let result = if shift >= CONST_256 {
U256::zero()
} else {
value << (shift.as_u32() as usize)
};
self.stack.push(result);
}
opcodes::OpCode::SHR => {
const CONST_256: U256 = U256([256, 0, 0, 0]);
let shift = self.stack.pop();
let value = self.stack.pop();
let result = if shift >= CONST_256 {
U256::zero()
} else {
value >> (shift.as_u32() as usize)
};
self.stack.push(result);
}
opcodes::OpCode::SAR => {
const CONST_256: U256 = U256([256, 0, 0, 0]);
const CONST_HIBIT: U256 = U256([0, 0, 0, 0x8000_0000_0000_0000]);
let shift = self.stack.pop();
let value = self.stack.pop();
let sign = value & CONST_HIBIT != U256::zero();
let result = if shift >= CONST_256 {
if sign {
U256::max_value()
} else {
U256::zero()
}
} else {
let shift = shift.as_u32() as usize;
let mut shifted = value >> shift;
if sign {
shifted = shifted | (U256::max_value() << (256 - shift));
}
shifted
};
self.stack.push(result);
}
opcodes::OpCode::SHA3 => {
let mem_offset = self.stack.pop();
let mem_len = self.stack.pop();
let k = self
.data_provider
.sha3(self.mem.get(mem_offset.low_u64() as usize, mem_len.low_u64() as usize));
self.stack.push(U256::from(k.as_bytes()));
}
opcodes::OpCode::ADDRESS => {
self.stack.push(common::address_to_u256(self.params.address));
}
opcodes::OpCode::BALANCE => {
let address = common::u256_to_address(&self.stack.pop());
let balance = self.data_provider.get_balance(&address);
self.stack.push(balance);
}
opcodes::OpCode::SELFBALANCE => {
let balance = self.data_provider.get_balance(&self.params.receiver);
self.stack.push(balance);
}
opcodes::OpCode::CHAINID => {
self.stack.push(1.into());
}
opcodes::OpCode::ORIGIN => {
self.stack.push(common::address_to_u256(self.params.origin));
}
opcodes::OpCode::CALLER => {
self.stack.push(common::address_to_u256(self.params.sender));
}
opcodes::OpCode::CALLVALUE => {
self.stack.push(self.params.value);
}
opcodes::OpCode::CALLDATALOAD => {
let big_id = self.stack.pop();
let id = big_id.low_u64() as usize;
let max = id.wrapping_add(32);
if !self.params.input.is_empty() {
let bound = cmp::min(self.params.input.len(), max);
if id < bound && big_id < U256::from(self.params.input.len()) {
let mut v = [0u8; 32];
v[0..bound - id].clone_from_slice(&self.params.input[id..bound]);
self.stack.push(U256::from(&v[..]))
} else {
self.stack.push(U256::zero())
}
} else {
self.stack.push(U256::zero())
}
}
opcodes::OpCode::CALLDATASIZE => {
self.stack.push(U256::from(self.params.input.len()));
}
opcodes::OpCode::CALLDATACOPY => {
let mem_offset = self.stack.pop();
let raw_offset = self.stack.pop();
let size = self.stack.pop();
let data = common::copy_data(self.params.input.as_slice(), raw_offset, size);
self.mem.set(mem_offset.as_usize(), data.as_slice());
}
opcodes::OpCode::CODESIZE => {
self.stack.push(U256::from(self.params.contract.code_data.len()));
}
opcodes::OpCode::CODECOPY => {
let mem_offset = self.stack.pop();
let raw_offset = self.stack.pop();
let size = self.stack.pop();
let data = common::copy_data(self.params.contract.code_data.as_slice(), raw_offset, size);
self.mem.set(mem_offset.as_usize(), data.as_slice());
}
opcodes::OpCode::GASPRICE => {
self.stack.push(self.params.gas_price);
}
opcodes::OpCode::EXTCODESIZE => {
let address = common::u256_to_address(&self.stack.pop());
let len = self.data_provider.get_code_size(&address);
self.stack.push(U256::from(len));
}
opcodes::OpCode::EXTCODECOPY => {
let address = common::u256_to_address(&self.stack.pop());
let mem_offset = self.stack.pop();
let code_offset = self.stack.pop();
let size = self.stack.pop();
let code = self.data_provider.get_code(&address);
let data = common::copy_data(code.as_slice(), code_offset, size);
self.mem.set(mem_offset.as_usize(), data.as_slice())
}
opcodes::OpCode::RETURNDATASIZE => self.stack.push(U256::from(self.return_data.len())),
opcodes::OpCode::RETURNDATACOPY => {
let mem_offset = self.stack.pop();
let raw_offset = self.stack.pop();
let size = self.stack.pop();
let return_data_len = U256::from(self.return_data.len());
if raw_offset.saturating_add(size) > return_data_len {
return Err(err::Error::OutOfBounds);
}
let data = common::copy_data(&self.return_data, raw_offset, size);
self.mem.set(mem_offset.as_usize(), data.as_slice())
}
opcodes::OpCode::EXTCODEHASH => {
let address = common::u256_to_address(&self.stack.pop());
let hash = self.data_provider.get_code_hash(&address);
self.stack.push(U256::from(hash.as_bytes()));
}
opcodes::OpCode::BLOCKHASH => {
let block_number = self.stack.pop();
let block_hash = self.data_provider.get_block_hash(&block_number);
self.stack.push(U256::from(block_hash.as_bytes()));
}
opcodes::OpCode::COINBASE => {
self.stack.push(common::address_to_u256(self.context.coinbase));
}
opcodes::OpCode::TIMESTAMP => {
self.stack.push(U256::from(self.context.timestamp));
}
opcodes::OpCode::NUMBER => {
self.stack.push(self.context.number);
}
opcodes::OpCode::DIFFICULTY => {
self.stack.push(self.context.difficulty);
}
opcodes::OpCode::GASLIMIT => {
self.stack.push(U256::from(self.context.gas_limit));
}
opcodes::OpCode::BASEFEE => {
self.stack.push(self.params.base_fee);
}
opcodes::OpCode::POP => {
self.stack.pop();
}
opcodes::OpCode::MLOAD => {
let offset = self.stack.pop().as_u64();
let word = self.mem.get(offset as usize, 32);
self.stack.push(U256::from(word));
}
opcodes::OpCode::MSTORE => {
let offset = self.stack.pop();
let word = self.stack.pop();
let word = &<[u8; 32]>::from(word)[..];
self.mem.set(offset.low_u64() as usize, word);
}
opcodes::OpCode::MSTORE8 => {
let offset = self.stack.pop();
let word = self.stack.pop();
self.mem.set(offset.low_u64() as usize, &[word.low_u64() as u8]);
}
opcodes::OpCode::SLOAD => {
let key = H256::from_uint(&self.stack.pop());
let word = U256::from(self.data_provider.get_storage(&self.params.address, &key).as_bytes());
self.stack.push(word);
}
opcodes::OpCode::SSTORE => {
let address = H256::from_uint(&self.stack.pop());
let value = self.stack.pop();
self.data_provider
.set_storage(&self.params.address, address, H256::from_uint(&value));
}
opcodes::OpCode::JUMP => {
let jump = self.stack.pop();
self.pre_jump(jump)?;
pc = jump.low_u64();
}
opcodes::OpCode::JUMPI => {
let jump = self.stack.pop();
let condition = self.stack.pop();
if !condition.is_zero() {
self.pre_jump(jump)?;
pc = jump.low_u64();
}
}
opcodes::OpCode::PC => {
self.stack.push(U256::from(pc - 1));
}
opcodes::OpCode::MSIZE => {
self.stack.push(U256::from(self.mem.len()));
}
opcodes::OpCode::GAS => {
self.stack.push(U256::from(self.gas));
}
opcodes::OpCode::JUMPDEST => {}
opcodes::OpCode::PUSH1
| opcodes::OpCode::PUSH2
| opcodes::OpCode::PUSH3
| opcodes::OpCode::PUSH4
| opcodes::OpCode::PUSH5
| opcodes::OpCode::PUSH6
| opcodes::OpCode::PUSH7
| opcodes::OpCode::PUSH8
| opcodes::OpCode::PUSH9
| opcodes::OpCode::PUSH10
| opcodes::OpCode::PUSH11
| opcodes::OpCode::PUSH12
| opcodes::OpCode::PUSH13
| opcodes::OpCode::PUSH14
| opcodes::OpCode::PUSH15
| opcodes::OpCode::PUSH16
| opcodes::OpCode::PUSH17
| opcodes::OpCode::PUSH18
| opcodes::OpCode::PUSH19
| opcodes::OpCode::PUSH20
| opcodes::OpCode::PUSH21
| opcodes::OpCode::PUSH22
| opcodes::OpCode::PUSH23
| opcodes::OpCode::PUSH24
| opcodes::OpCode::PUSH25
| opcodes::OpCode::PUSH26
| opcodes::OpCode::PUSH27
| opcodes::OpCode::PUSH28
| opcodes::OpCode::PUSH29
| opcodes::OpCode::PUSH30
| opcodes::OpCode::PUSH31
| opcodes::OpCode::PUSH32 => {
let n = op as u8 - opcodes::OpCode::PUSH1 as u8 + 1;
let e = pc + u64::from(n);
let e = cmp::min(e, self.params.contract.code_data.len() as u64);
let r = U256::from(&self.params.contract.code_data[pc as usize..e as usize]);
pc = e;
self.stack.push(r);
}
opcodes::OpCode::DUP1
| opcodes::OpCode::DUP2
| opcodes::OpCode::DUP3
| opcodes::OpCode::DUP4
| opcodes::OpCode::DUP5
| opcodes::OpCode::DUP6
| opcodes::OpCode::DUP7
| opcodes::OpCode::DUP8
| opcodes::OpCode::DUP9
| opcodes::OpCode::DUP10
| opcodes::OpCode::DUP11
| opcodes::OpCode::DUP12
| opcodes::OpCode::DUP13
| opcodes::OpCode::DUP14
| opcodes::OpCode::DUP15
| opcodes::OpCode::DUP16 => {
let p = op as u8 - opcodes::OpCode::DUP1 as u8;
self.stack.dup(p as usize);
}
opcodes::OpCode::SWAP1
| opcodes::OpCode::SWAP2
| opcodes::OpCode::SWAP3
| opcodes::OpCode::SWAP4
| opcodes::OpCode::SWAP5
| opcodes::OpCode::SWAP6
| opcodes::OpCode::SWAP7
| opcodes::OpCode::SWAP8
| opcodes::OpCode::SWAP9
| opcodes::OpCode::SWAP10
| opcodes::OpCode::SWAP11
| opcodes::OpCode::SWAP12
| opcodes::OpCode::SWAP13
| opcodes::OpCode::SWAP14
| opcodes::OpCode::SWAP15
| opcodes::OpCode::SWAP16 => {
let p = op as u8 - opcodes::OpCode::SWAP1 as u8 + 1;
self.stack.swap(p as usize);
}
opcodes::OpCode::LOG0
| opcodes::OpCode::LOG1
| opcodes::OpCode::LOG2
| opcodes::OpCode::LOG3
| opcodes::OpCode::LOG4 => {
let n = op as u8 - opcodes::OpCode::LOG0 as u8;
let mem_offset = self.stack.pop();
let mem_len = self.stack.pop();
let mut topics: Vec<H256> = Vec::new();
for _ in 0..n {
let r = H256::from_uint(&self.stack.pop());
topics.push(r);
}
let data = self.mem.get(mem_offset.low_u64() as usize, mem_len.low_u64() as usize);
self.logs.push(Log(self.params.address, topics, Vec::from(data)));
}
opcodes::OpCode::CREATE | opcodes::OpCode::CREATE2 => {
self.return_data = vec![];
let value = self.stack.pop();
let mem_offset = self.stack.pop();
let mem_len = self.stack.pop();
let salt = H256::from_uint(&{
match op {
opcodes::OpCode::CREATE => U256::zero(),
opcodes::OpCode::CREATE2 => self.stack.pop(),
_ => panic!("instruction can only be CREATE/CREATE2 checked above"),
}
});
let data = self.mem.get(mem_offset.low_u64() as usize, mem_len.low_u64() as usize);
if value > self.data_provider.get_balance(&self.params.address) {
self.gas += self.gas_tmp;
self.stack.push(U256::zero());
continue;
}
if self.params.depth >= self.cfg.max_call_depth {
self.gas += self.gas_tmp;
self.stack.push(U256::zero());
continue;
}
let mut params = InterpreterParams::default();
params.origin = self.params.origin;
params.sender = self.params.address;
params.gas_limit = self.gas_tmp;
params.gas_price = self.params.gas_price;
params.input = Vec::from(data);
params.value = value;
params.extra = salt;
params.depth = self.params.depth + 1;
let r = self.data_provider.call(op, params);
match r {
Ok(data) => match data {
InterpreterResult::Create(_, gas, logs, add) => {
self.stack.push(common::address_to_u256(add));
self.gas += gas;
self.logs.extend(logs);
}
InterpreterResult::Revert(ret, gas) => {
self.stack.push(U256::zero());
self.gas += gas;
self.return_data = ret;
}
_ => {}
},
Err(_) => {
self.stack.push(U256::zero());
}
}
}
opcodes::OpCode::CALL
| opcodes::OpCode::CALLCODE
| opcodes::OpCode::DELEGATECALL
| opcodes::OpCode::STATICCALL => {
let _ = self.stack.pop();
let address = common::u256_to_address(&self.stack.pop());
let value = {
if op == opcodes::OpCode::CALL || op == opcodes::OpCode::CALLCODE {
self.stack.pop()
} else {
U256::zero()
}
};
let mem_offset = self.stack.pop();
let mem_len = self.stack.pop();
let out_offset = self.stack.pop();
let out_len = self.stack.pop();
if op == opcodes::OpCode::CALL && self.params.read_only && !value.is_zero() {
return Err(err::Error::MutableCallInStaticContext);
}
self.return_data = vec![];
let mut gas = self.gas_tmp;
if !value.is_zero() {
gas += self.cfg.gas_call_stipend;
}
if value > self.data_provider.get_balance(&self.params.address) {
self.gas += gas;
self.stack.push(U256::zero());
continue;
}
if self.params.depth >= self.cfg.max_call_depth {
self.gas += gas;
self.stack.push(U256::zero());
continue;
}
let data = self.mem.get(mem_offset.low_u64() as usize, mem_len.low_u64() as usize);
let mut params = InterpreterParams::default();
params.origin = self.params.origin;
params.gas_limit = gas;
params.gas_price = self.params.gas_price;
params.contract.code_address = address;
params.contract.code_data = self.data_provider.get_code(¶ms.contract.code_address).to_vec();
params.input = Vec::from(data);
params.depth = self.params.depth + 1;
params.read_only = self.params.read_only;
match op {
opcodes::OpCode::CALL => {
params.sender = self.params.address;
params.receiver = address;
params.address = address;
params.value = value;
}
opcodes::OpCode::CALLCODE => {
params.sender = self.params.address;
params.receiver = self.params.address;
params.address = self.params.address;
params.value = value;
}
opcodes::OpCode::DELEGATECALL => {
params.sender = self.params.sender;
params.receiver = self.params.address;
params.address = self.params.address;
params.value = self.params.value;
params.disable_transfer_value = true;
}
opcodes::OpCode::STATICCALL => {
params.sender = self.params.address;
params.receiver = address;
params.address = address;
params.read_only = true;
}
_ => {}
}
let r = self.data_provider.call(op, params);
match r {
Ok(data) => match data {
InterpreterResult::Normal(mut ret, gas, logs) => {
self.stack.push(U256::one());
self.return_data = ret.clone();
if ret.len() > out_len.low_u64() as usize {
ret.resize(out_len.low_u64() as usize, 0u8);
}
self.mem.set(out_offset.low_u64() as usize, ret.as_slice());
self.gas += gas;
self.logs.extend(logs);
}
InterpreterResult::Revert(mut ret, gas) => {
self.stack.push(U256::zero());
self.return_data = ret.clone();
if ret.len() > out_len.low_u64() as usize {
ret.resize(out_len.low_u64() as usize, 0u8);
}
self.mem.set(out_offset.low_u64() as usize, ret.as_slice());
self.gas += gas;
}
_ => {}
},
Err(_) => {
self.stack.push(U256::zero());
}
}
}
opcodes::OpCode::RETURN => {
let mem_offset = self.stack.pop();
let mem_len = self.stack.pop();
let r = self.mem.get(mem_offset.low_u64() as usize, mem_len.low_u64() as usize);
let return_data = Vec::from(r);
return Ok(InterpreterResult::Normal(return_data, self.gas, self.logs.clone()));
}
opcodes::OpCode::REVERT => {
let mem_offset = self.stack.pop();
let mem_len = self.stack.pop();
let r = self.mem.get(mem_offset.low_u64() as usize, mem_len.low_u64() as usize);
let return_data = Vec::from(r);
return Ok(InterpreterResult::Revert(return_data, self.gas));
}
opcodes::OpCode::SELFDESTRUCT => {
let address = self.stack.pop();
let b = self
.data_provider
.selfdestruct(&self.params.address, &common::u256_to_address(&address));
if !b {
self.data_provider
.sub_refund(&self.params.origin, self.cfg.gas_self_destruct_refund);
}
break;
}
}
debug!("");
}
Ok(InterpreterResult::Normal(vec![], self.gas, self.logs.clone()))
}
fn use_gas(&mut self, gas: u64) -> Result<(), err::Error> {
debug!("[Gas] - {}", gas);
if self.gas < gas {
return Err(err::Error::OutOfGas);
}
self.gas -= gas;
Ok(())
}
fn mem_gas_cost(&mut self, size: u64) -> u64 {
let goc = common::mem_gas_cost(size, self.cfg.gas_memory);
if goc > self.mem_gas {
let fee = goc - self.mem_gas;
self.mem_gas = goc;
fee
} else {
0
}
}
fn mem_gas_work(&mut self, mem_offset: U256, mem_len: U256) -> Result<(), err::Error> {
if mem_len.is_zero() {
return Ok(());
}
let (mem_sum, b) = mem_offset.overflowing_add(mem_len);
if b || mem_sum.bits() > 64 || mem_sum.low_u64() > 1024 * 1024 * 1024 {
return Err(err::Error::OutOfGas);
}
let gas = self.mem_gas_cost(mem_sum.low_u64());
self.use_gas(gas)?;
self.mem.expand(mem_sum.low_u64() as usize);
Ok(())
}
fn get_byte(&self, n: u64) -> Option<u8> {
if n < self.params.contract.code_data.len() as u64 {
return Some(self.params.contract.code_data[n as usize]);
}
None
}
fn get_op(&self, n: u64) -> Result<Option<opcodes::OpCode>, err::Error> {
match self.get_byte(n) {
Some(a) => match opcodes::OpCode::from_u8(a) {
Some(b) => Ok(Some(b)),
None => Err(err::Error::InvalidOpcode),
},
None => Ok(None),
}
}
fn pre_jump(&self, n: U256) -> Result<(), err::Error> {
if n.bits() > 63 {
return Err(err::Error::InvalidJumpDestination);
}
let n = n.low_u64() as usize;
if n >= self.params.contract.code_data.len() {
return Err(err::Error::InvalidJumpDestination);
}
if self.params.contract.code_data[n] != opcodes::OpCode::JUMPDEST as u8 {
return Err(err::Error::InvalidJumpDestination);
}
Ok(())
}
fn trace(&self, op: &opcodes::OpCode, pc: u64) {
if *op >= opcodes::OpCode::PUSH1 && *op <= opcodes::OpCode::PUSH32 {
let n = op.clone() as u8 - opcodes::OpCode::PUSH1 as u8 + 1;
let r = {
if pc + u64::from(n) > self.params.contract.code_data.len() as u64 {
U256::zero()
} else {
U256::from(&self.params.contract.code_data[pc as usize..(pc + u64::from(n)) as usize])
}
};
debug!("[OP] {} {:#x} gas={}", op, r, self.gas);
} else {
debug!("[OP] {} gas={}", op, self.gas);
}
debug!("[STACK]");
let l = self.stack.data().len();
for i in 0..l {
debug!("[{}] {:#x}", i, self.stack.back(i));
}
debug!("[MEM] len={}", self.mem.len());
}
}
#[cfg(test)]
mod tests {
use super::super::extmock;
use super::*;
fn default_interpreter() -> Interpreter {
let mut it = Interpreter::new(
Context::default(),
InterpreterConf::default(),
Box::new(extmock::DataProviderMock::default()),
InterpreterParams::default(),
);
it.context.gas_limit = 1_000_000;
it.params.gas_limit = 1_000_000;
it.gas = 1_000_000;
it
}
#[test]
fn test_op_byte() {
let data = vec![
(
"ABCDEF0908070605040302010000000000000000000000000000000000000000",
"0",
"AB",
),
(
"ABCDEF0908070605040302010000000000000000000000000000000000000000",
"1",
"CD",
),
(
"00CDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff",
"0",
"00",
),
(
"ABCDEF0908070605040302010000000000000000000000000000000000000000",
"1",
"CD",
),
(
"00CDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff",
"0",
"00",
),
(
"00CDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff",
"1",
"CD",
),
(
"0000000000000000000000000000000000000000000000000000000000102030",
"31",
"30",
),
(
"0000000000000000000000000000000000000000000000000000000000102030",
"30",
"20",
),
(
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"32",
"00",
),
(
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"4294967295",
"00",
),
];
for (val, th, expected) in data {
let mut it = default_interpreter();
it.stack
.push_n(&[U256::from(val), U256::from(th.parse::<u64>().unwrap())]);
it.params.contract.code_data = vec![opcodes::OpCode::BYTE as u8];
it.run().unwrap();
assert_eq!(it.stack.pop(), U256::from(expected));
}
}
#[test]
fn test_op_shl() {
let data = vec![
(
"0000000000000000000000000000000000000000000000000000000000000001",
"00",
"0000000000000000000000000000000000000000000000000000000000000001",
),
(
"0000000000000000000000000000000000000000000000000000000000000001",
"01",
"0000000000000000000000000000000000000000000000000000000000000002",
),
(
"0000000000000000000000000000000000000000000000000000000000000001",
"ff",
"8000000000000000000000000000000000000000000000000000000000000000",
),
(
"0000000000000000000000000000000000000000000000000000000000000001",
"0100",
"0000000000000000000000000000000000000000000000000000000000000000",
),
(
"0000000000000000000000000000000000000000000000000000000000000001",
"0101",
"0000000000000000000000000000000000000000000000000000000000000000",
),
(
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"00",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
),
(
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"01",
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe",
),
(
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"ff",
"8000000000000000000000000000000000000000000000000000000000000000",
),
(
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0100",
"0000000000000000000000000000000000000000000000000000000000000000",
),
(
"0000000000000000000000000000000000000000000000000000000000000000",
"01",
"0000000000000000000000000000000000000000000000000000000000000000",
),
(
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"01",
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe",
),
];
for (x, y, expected) in data {
let mut it = default_interpreter();
it.stack.push_n(&[U256::from(x), U256::from(y)]);
it.params.contract.code_data = vec![opcodes::OpCode::SHL as u8];
it.run().unwrap();
assert_eq!(it.stack.pop(), U256::from(expected));
}
}
#[test]
fn test_op_shr() {
let data = vec![
(
"0000000000000000000000000000000000000000000000000000000000000001",
"00",
"0000000000000000000000000000000000000000000000000000000000000001",
),
(
"0000000000000000000000000000000000000000000000000000000000000001",
"01",
"0000000000000000000000000000000000000000000000000000000000000000",
),
(
"8000000000000000000000000000000000000000000000000000000000000000",
"01",
"4000000000000000000000000000000000000000000000000000000000000000",
),
(
"8000000000000000000000000000000000000000000000000000000000000000",
"ff",
"0000000000000000000000000000000000000000000000000000000000000001",
),
(
"8000000000000000000000000000000000000000000000000000000000000000",
"0100",
"0000000000000000000000000000000000000000000000000000000000000000",
),
(
"8000000000000000000000000000000000000000000000000000000000000000",
"0101",
"0000000000000000000000000000000000000000000000000000000000000000",
),
(
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"00",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
),
(
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"01",
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
),
(
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"ff",
"0000000000000000000000000000000000000000000000000000000000000001",
),
(
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0100",
"0000000000000000000000000000000000000000000000000000000000000000",
),
(
"0000000000000000000000000000000000000000000000000000000000000000",
"01",
"0000000000000000000000000000000000000000000000000000000000000000",
),
];
for (x, y, expected) in data {
let mut it = default_interpreter();
it.stack.push_n(&[U256::from(x), U256::from(y)]);
it.params.contract.code_data = vec![opcodes::OpCode::SHR as u8];
it.run().unwrap();
assert_eq!(it.stack.pop(), U256::from(expected));
}
}
#[test]
fn test_op_sar() {
let data = vec![
(
"0000000000000000000000000000000000000000000000000000000000000001",
"00",
"0000000000000000000000000000000000000000000000000000000000000001",
),
(
"0000000000000000000000000000000000000000000000000000000000000001",
"01",
"0000000000000000000000000000000000000000000000000000000000000000",
),
(
"8000000000000000000000000000000000000000000000000000000000000000",
"01",
"c000000000000000000000000000000000000000000000000000000000000000",
),
(
"8000000000000000000000000000000000000000000000000000000000000000",
"ff",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
),
(
"8000000000000000000000000000000000000000000000000000000000000000",
"0100",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
),
(
"8000000000000000000000000000000000000000000000000000000000000000",
"0101",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
),
(
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"00",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
),
(
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"01",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
),
(
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"ff",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
),
(
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0100",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
),
(
"0000000000000000000000000000000000000000000000000000000000000000",
"01",
"0000000000000000000000000000000000000000000000000000000000000000",
),
(
"4000000000000000000000000000000000000000000000000000000000000000",
"fe",
"0000000000000000000000000000000000000000000000000000000000000001",
),
(
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"f8",
"000000000000000000000000000000000000000000000000000000000000007f",
),
(
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"fe",
"0000000000000000000000000000000000000000000000000000000000000001",
),
(
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"ff",
"0000000000000000000000000000000000000000000000000000000000000000",
),
(
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0100",
"0000000000000000000000000000000000000000000000000000000000000000",
),
];
for (x, y, expected) in data {
let mut it = default_interpreter();
it.stack.push_n(&[U256::from(x), U256::from(y)]);
it.params.contract.code_data = vec![opcodes::OpCode::SAR as u8];
it.run().unwrap();
assert_eq!(it.stack.pop(), U256::from(expected));
}
}
#[test]
fn test_op_chain_id() {
let mut it = default_interpreter();
it.params.contract.code_data = vec![opcodes::OpCode::CHAINID as u8];
it.run().unwrap();
assert_eq!(it.stack.pop(), U256::from(1));
}
#[test]
fn test_op_sgt() {
let data = vec![
(
"0000000000000000000000000000000000000000000000000000000000000001",
"0000000000000000000000000000000000000000000000000000000000000001",
"0000000000000000000000000000000000000000000000000000000000000000",
),
(
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0000000000000000000000000000000000000000000000000000000000000000",
),
(
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0000000000000000000000000000000000000000000000000000000000000000",
),
(
"0000000000000000000000000000000000000000000000000000000000000001",
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0000000000000000000000000000000000000000000000000000000000000001",
),
(
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0000000000000000000000000000000000000000000000000000000000000001",
"0000000000000000000000000000000000000000000000000000000000000000",
),
(
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0000000000000000000000000000000000000000000000000000000000000001",
"0000000000000000000000000000000000000000000000000000000000000001",
),
(
"0000000000000000000000000000000000000000000000000000000000000001",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0000000000000000000000000000000000000000000000000000000000000000",
),
(
"8000000000000000000000000000000000000000000000000000000000000001",
"8000000000000000000000000000000000000000000000000000000000000001",
"0000000000000000000000000000000000000000000000000000000000000000",
),
(
"8000000000000000000000000000000000000000000000000000000000000001",
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0000000000000000000000000000000000000000000000000000000000000001",
),
(
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"8000000000000000000000000000000000000000000000000000000000000001",
"0000000000000000000000000000000000000000000000000000000000000000",
),
(
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb",
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd",
"0000000000000000000000000000000000000000000000000000000000000001",
),
(
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd",
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb",
"0000000000000000000000000000000000000000000000000000000000000000",
),
];
for (x, y, expected) in data {
let mut it = default_interpreter();
it.stack.push_n(&[U256::from(x), U256::from(y)]);
it.params.contract.code_data = vec![opcodes::OpCode::SGT as u8];
it.run().unwrap();
assert_eq!(it.stack.pop(), U256::from(expected));
}
}
#[test]
fn test_op_slt() {
let data = vec![
(
"0000000000000000000000000000000000000000000000000000000000000001",
"0000000000000000000000000000000000000000000000000000000000000001",
"0000000000000000000000000000000000000000000000000000000000000000",
),
(
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0000000000000000000000000000000000000000000000000000000000000000",
),
(
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0000000000000000000000000000000000000000000000000000000000000000",
),
(
"0000000000000000000000000000000000000000000000000000000000000001",
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0000000000000000000000000000000000000000000000000000000000000000",
),
(
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0000000000000000000000000000000000000000000000000000000000000001",
"0000000000000000000000000000000000000000000000000000000000000001",
),
(
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0000000000000000000000000000000000000000000000000000000000000001",
"0000000000000000000000000000000000000000000000000000000000000000",
),
(
"0000000000000000000000000000000000000000000000000000000000000001",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0000000000000000000000000000000000000000000000000000000000000001",
),
(
"8000000000000000000000000000000000000000000000000000000000000001",
"8000000000000000000000000000000000000000000000000000000000000001",
"0000000000000000000000000000000000000000000000000000000000000000",
),
(
"8000000000000000000000000000000000000000000000000000000000000001",
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0000000000000000000000000000000000000000000000000000000000000000",
),
(
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"8000000000000000000000000000000000000000000000000000000000000001",
"0000000000000000000000000000000000000000000000000000000000000001",
),
(
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb",
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd",
"0000000000000000000000000000000000000000000000000000000000000000",
),
(
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd",
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb",
"0000000000000000000000000000000000000000000000000000000000000001",
),
];
for (x, y, expected) in data {
let mut it = default_interpreter();
it.stack.push_n(&[U256::from(x), U256::from(y)]);
it.params.contract.code_data = vec![opcodes::OpCode::SLT as u8];
it.run().unwrap();
assert_eq!(it.stack.pop(), U256::from(expected));
}
}
#[test]
fn test_op_mstore() {
let mut it = default_interpreter();
let v = "abcdef00000000000000abba000000000deaf000000c0de00100000000133700";
it.stack.push_n(&[U256::from(v), U256::zero()]);
it.params.contract.code_data = vec![opcodes::OpCode::MSTORE as u8];
it.run().unwrap();
assert_eq!(it.mem.get(0, 32), hex::decode(v).unwrap().as_slice());
it.stack.push_n(&[U256::one(), U256::zero()]);
it.params.contract.code_data = vec![opcodes::OpCode::MSTORE as u8];
it.run().unwrap();
assert_eq!(
it.mem.get(0, 32),
hex::decode("0000000000000000000000000000000000000000000000000000000000000001")
.unwrap()
.as_slice()
);
}
#[test]
fn test_op_sstore_eip_1283() {
let data = vec![
("60006000556000600055", 412, 0, 0),
("60006000556001600055", 20212, 0, 0),
("60016000556000600055", 20212, 19800, 0),
("60016000556002600055", 20212, 0, 0),
("60016000556001600055", 20212, 0, 0),
("60006000556000600055", 5212, 15000, 1),
("60006000556001600055", 5212, 4800, 1),
("60006000556002600055", 5212, 0, 1),
("60026000556000600055", 5212, 15000, 1),
("60026000556003600055", 5212, 0, 1),
("60026000556001600055", 5212, 4800, 1),
("60026000556002600055", 5212, 0, 1),
("60016000556000600055", 5212, 15000, 1),
("60016000556002600055", 5212, 0, 1),
("60016000556001600055", 412, 0, 1),
("600160005560006000556001600055", 40218, 19800, 0),
("600060005560016000556000600055", 10218, 19800, 1),
];
for (code, use_gas, refund, origin) in data {
let mut it = default_interpreter();
it.cfg.eip1283 = true;
assert_eq!(it.gas, it.context.gas_limit);
it.data_provider
.set_storage_origin(&it.params.contract.code_address, H256::zero(), H256::from(origin));
it.data_provider
.set_storage(&it.params.contract.code_address, H256::zero(), H256::from(origin));
it.params.contract.code_data = hex::decode(code).unwrap();
it.run().unwrap();
assert_eq!(it.gas, it.context.gas_limit - use_gas);
assert_eq!(it.data_provider.get_refund(&Address::zero()), refund);
}
}
#[test]
fn test_op_invalid() {
let mut it = default_interpreter();
it.params.contract.code_data = hex::decode("fb").unwrap();
let r = it.run();
assert!(r.is_err());
assert_eq!(r.err(), Some(err::Error::InvalidOpcode))
}
}