use alloc::vec::Vec;
use sha3::{Digest, Keccak256};
#[allow(unused_imports)]
use crate::uint::{H256, U256, U256Ext};
use crate::{
Control, ExitException, ExitFatal, ExitSucceed, Machine,
runtime::{GasState, Log, RuntimeBackend, RuntimeEnvironment, RuntimeState, Transfer},
};
#[allow(deprecated)]
pub fn sha3<S: AsRef<RuntimeState>, Tr>(machine: &mut Machine<S>) -> Control<Tr> {
pop_u256!(machine, from, len);
try_or_fail!(machine.memory.resize_offset(from, len));
let data = if len == U256::ZERO {
Vec::new()
} else {
let from = as_usize_or_fail!(from);
let len = as_usize_or_fail!(len);
machine.memory.get(from, len)
};
let ret = Keccak256::digest(data.as_slice());
push_h256!(machine, H256::from_slice(ret.as_slice()));
Control::Continue(1)
}
pub fn chainid<S: AsRef<RuntimeState>, H: RuntimeEnvironment + RuntimeBackend, Tr>(
machine: &mut Machine<S>,
handler: &H,
) -> Control<Tr> {
push_u256!(machine, handler.chain_id());
Control::Continue(1)
}
pub fn address<S: AsRef<RuntimeState>, Tr>(machine: &mut Machine<S>) -> Control<Tr> {
let ret = H256::from(machine.state.as_ref().context.address);
push_h256!(machine, ret);
Control::Continue(1)
}
pub fn balance<S: AsRef<RuntimeState>, H: RuntimeEnvironment + RuntimeBackend, Tr>(
machine: &mut Machine<S>,
handler: &mut H,
) -> Control<Tr> {
pop_h256!(machine, address);
push_u256!(machine, handler.balance(address.into()));
Control::Continue(1)
}
pub fn selfbalance<S: AsRef<RuntimeState>, H: RuntimeEnvironment + RuntimeBackend, Tr>(
machine: &mut Machine<S>,
handler: &H,
) -> Control<Tr> {
push_u256!(
machine,
handler.balance(machine.state.as_ref().context.address)
);
Control::Continue(1)
}
pub fn origin<S: AsRef<RuntimeState>, H: RuntimeEnvironment + RuntimeBackend, Tr>(
machine: &mut Machine<S>,
_handler: &H,
) -> Control<Tr> {
let ret = H256::from(machine.state.as_ref().transaction_context.origin);
push_h256!(machine, ret);
Control::Continue(1)
}
pub fn caller<S: AsRef<RuntimeState>, Tr>(machine: &mut Machine<S>) -> Control<Tr> {
let ret = H256::from(machine.state.as_ref().context.caller);
push_h256!(machine, ret);
Control::Continue(1)
}
pub fn callvalue<S: AsRef<RuntimeState>, Tr>(machine: &mut Machine<S>) -> Control<Tr> {
let ret = machine.state.as_ref().context.apparent_value;
push_u256!(machine, ret);
Control::Continue(1)
}
pub fn gasprice<S: AsRef<RuntimeState>, H: RuntimeEnvironment + RuntimeBackend, Tr>(
machine: &mut Machine<S>,
_handler: &H,
) -> Control<Tr> {
let ret = machine.state.as_ref().transaction_context.gas_price;
push_u256!(machine, ret);
Control::Continue(1)
}
pub fn basefee<S: AsRef<RuntimeState>, H: RuntimeEnvironment + RuntimeBackend, Tr>(
machine: &mut Machine<S>,
handler: &H,
) -> Control<Tr> {
let ret = handler.block_base_fee_per_gas();
push_u256!(machine, ret);
Control::Continue(1)
}
pub fn blobhash<S: AsRef<RuntimeState>, H: RuntimeEnvironment + RuntimeBackend, Tr>(
machine: &mut Machine<S>,
handler: &H,
) -> Control<Tr> {
pop_u256!(machine, index);
let hash = handler.blob_versioned_hash(index);
push_h256!(machine, hash);
Control::Continue(1)
}
pub fn blobbasefee<S: AsRef<RuntimeState>, H: RuntimeEnvironment + RuntimeBackend, Tr>(
machine: &mut Machine<S>,
handler: &H,
) -> Control<Tr> {
let blob_basefee = handler.blob_base_fee_per_gas();
push_u256!(machine, blob_basefee);
Control::Continue(1)
}
pub fn extcodesize<S: AsRef<RuntimeState>, H: RuntimeEnvironment + RuntimeBackend, Tr>(
machine: &mut Machine<S>,
handler: &mut H,
) -> Control<Tr> {
pop_h256!(machine, address);
let code_size = handler.code_size(address.into());
push_u256!(machine, code_size);
Control::Continue(1)
}
pub fn extcodehash<S: AsRef<RuntimeState>, H: RuntimeEnvironment + RuntimeBackend, Tr>(
machine: &mut Machine<S>,
handler: &mut H,
) -> Control<Tr> {
pop_h256!(machine, address);
let code_hash = handler.code_hash(address.into());
push_h256!(machine, code_hash);
Control::Continue(1)
}
pub fn extcodecopy<S: AsRef<RuntimeState>, H: RuntimeEnvironment + RuntimeBackend, Tr>(
machine: &mut Machine<S>,
handler: &mut H,
) -> Control<Tr> {
pop_h256!(machine, address);
pop_u256!(machine, memory_offset, code_offset, len);
try_or_fail!(machine.memory.resize_offset(memory_offset, len));
let code = handler.code(address.into());
match machine
.memory
.copy_large(memory_offset, code_offset, len, &code)
{
Ok(()) => (),
Err(e) => return Control::Exit(e.into()),
};
Control::Continue(1)
}
pub fn returndatasize<S: AsRef<RuntimeState>, Tr>(machine: &mut Machine<S>) -> Control<Tr> {
let size = U256::from_usize(machine.state.as_ref().retbuf.len());
push_u256!(machine, size);
Control::Continue(1)
}
pub fn returndatacopy<S: AsRef<RuntimeState>, Tr>(machine: &mut Machine<S>) -> Control<Tr> {
pop_u256!(machine, memory_offset, data_offset, len);
try_or_fail!(machine.memory.resize_offset(memory_offset, len));
if data_offset
.checked_add(len)
.is_none_or(|l| l > U256::from_usize(machine.state.as_ref().retbuf.len()))
{
return Control::Exit(ExitException::OutOfOffset.into());
}
match machine.memory.copy_large(
memory_offset,
data_offset,
len,
&machine.state.as_ref().retbuf,
) {
Ok(()) => Control::Continue(1),
Err(e) => Control::Exit(e.into()),
}
}
pub fn blockhash<S: AsRef<RuntimeState>, H: RuntimeEnvironment + RuntimeBackend, Tr>(
machine: &mut Machine<S>,
handler: &H,
) -> Control<Tr> {
pop_u256!(machine, number);
push_h256!(machine, handler.block_hash(number));
Control::Continue(1)
}
pub fn coinbase<S: AsRef<RuntimeState>, H: RuntimeEnvironment + RuntimeBackend, Tr>(
machine: &mut Machine<S>,
handler: &H,
) -> Control<Tr> {
push_h256!(machine, handler.block_coinbase().into());
Control::Continue(1)
}
pub fn timestamp<S: AsRef<RuntimeState>, H: RuntimeEnvironment + RuntimeBackend, Tr>(
machine: &mut Machine<S>,
handler: &H,
) -> Control<Tr> {
push_u256!(machine, handler.block_timestamp());
Control::Continue(1)
}
pub fn number<S: AsRef<RuntimeState>, H: RuntimeEnvironment + RuntimeBackend, Tr>(
machine: &mut Machine<S>,
handler: &H,
) -> Control<Tr> {
push_u256!(machine, handler.block_number());
Control::Continue(1)
}
pub fn difficulty<S: AsRef<RuntimeState>, H: RuntimeEnvironment + RuntimeBackend, Tr>(
machine: &mut Machine<S>,
handler: &H,
) -> Control<Tr> {
push_u256!(machine, handler.block_difficulty());
Control::Continue(1)
}
pub fn prevrandao<S: AsRef<RuntimeState>, H: RuntimeEnvironment + RuntimeBackend, Tr>(
machine: &mut Machine<S>,
handler: &H,
) -> Control<Tr> {
if let Some(rand) = handler.block_randomness() {
push_h256!(machine, rand);
Control::Continue(1)
} else {
difficulty(machine, handler)
}
}
pub fn gaslimit<S: AsRef<RuntimeState>, H: RuntimeEnvironment + RuntimeBackend, Tr>(
machine: &mut Machine<S>,
handler: &H,
) -> Control<Tr> {
push_u256!(machine, handler.block_gas_limit());
Control::Continue(1)
}
pub fn sload<S: AsRef<RuntimeState>, H: RuntimeEnvironment + RuntimeBackend, Tr>(
machine: &mut Machine<S>,
handler: &mut H,
) -> Control<Tr> {
pop_h256!(machine, index);
let value = handler.storage(machine.state.as_ref().context.address, index);
push_h256!(machine, value);
Control::Continue(1)
}
pub fn sstore<S: AsRef<RuntimeState>, H: RuntimeEnvironment + RuntimeBackend, Tr>(
machine: &mut Machine<S>,
handler: &mut H,
) -> Control<Tr> {
pop_h256!(machine, index, value);
match handler.set_storage(machine.state.as_ref().context.address, index, value) {
Ok(()) => Control::Continue(1),
Err(e) => Control::Exit(e.into()),
}
}
pub fn gas<S: GasState, H: RuntimeEnvironment + RuntimeBackend, Tr>(
machine: &mut Machine<S>,
_handler: &H,
) -> Control<Tr> {
push_u256!(machine, machine.state.gas());
Control::Continue(1)
}
pub fn tload<S: AsRef<RuntimeState>, H: RuntimeEnvironment + RuntimeBackend, Tr>(
machine: &mut Machine<S>,
handler: &mut H,
) -> Control<Tr> {
pop_h256!(machine, index);
let value = handler.transient_storage(machine.state.as_ref().context.address, index);
push_h256!(machine, value);
Control::Continue(1)
}
pub fn tstore<S: AsRef<RuntimeState>, H: RuntimeEnvironment + RuntimeBackend, Tr>(
machine: &mut Machine<S>,
handler: &mut H,
) -> Control<Tr> {
pop_h256!(machine, index, value);
match handler.set_transient_storage(machine.state.as_ref().context.address, index, value) {
Ok(()) => Control::Continue(1),
Err(e) => Control::Exit(e.into()),
}
}
pub fn log<S: AsRef<RuntimeState>, H: RuntimeEnvironment + RuntimeBackend, Tr>(
machine: &mut Machine<S>,
n: u8,
handler: &mut H,
) -> Control<Tr> {
pop_u256!(machine, offset, len);
try_or_fail!(machine.memory.resize_offset(offset, len));
let data = if len == U256::ZERO {
Vec::new()
} else {
let offset = as_usize_or_fail!(offset);
let len = as_usize_or_fail!(len);
machine.memory.get(offset, len)
};
let mut topics = Vec::new();
for _ in 0..(n as usize) {
match machine.stack.pop() {
Ok(value) => {
topics.push(value.to_h256());
}
Err(e) => return Control::Exit(e.into()),
}
}
match handler.log(Log {
address: machine.state.as_ref().context.address,
topics,
data,
}) {
Ok(()) => Control::Continue(1),
Err(e) => Control::Exit(e.into()),
}
}
pub fn suicide<S: AsRef<RuntimeState>, H: RuntimeEnvironment + RuntimeBackend, Tr>(
machine: &mut Machine<S>,
handler: &mut H,
) -> Control<Tr> {
let address = machine.state.as_ref().context.address;
match machine.stack.perform_pop1_push0(|target| {
let balance = handler.balance(address);
handler.transfer(Transfer {
source: address,
target: target.to_h160(),
value: balance,
})?;
handler.mark_delete_reset(address);
Ok(((), ()))
}) {
Ok(()) => Control::Exit(ExitSucceed::Suicided.into()),
Err(e) => Control::Exit(Err(e)),
}
}