use crate::{
consts::*,
error::{
InterpreterError,
RuntimeError,
},
interpreter::{
alu,
flow::{
JumpArgs,
JumpMode,
},
ExecutableTransaction,
Interpreter,
},
state::ExecuteState,
storage::InterpreterStorage,
};
use fuel_asm::{
wideint,
Instruction,
PanicReason,
RawInstruction,
RegId,
};
use fuel_types::Word;
use std::ops::Div;
impl<S, Tx> Interpreter<S, Tx>
where
S: InterpreterStorage,
Tx: ExecutableTransaction,
{
pub fn execute(&mut self) -> Result<ExecuteState, InterpreterError> {
let [hi, lo] = self.memory[self.registers[RegId::PC] as usize..]
.chunks_exact(WORD_SIZE)
.next()
.map(|b| b.try_into().expect("Has to be correct size slice"))
.map(Word::from_be_bytes)
.map(fuel_asm::raw_instructions_from_word)
.ok_or(InterpreterError::Panic(PanicReason::MemoryOverflow))?;
let pc = self.registers[RegId::PC] + Instruction::SIZE as Word;
let state = self.instruction(hi)?;
if self.registers[RegId::PC] == pc && state.should_continue() {
self.instruction(lo)
} else {
Ok(state)
}
}
pub fn instruction<R: Into<RawInstruction> + Copy>(
&mut self,
raw: R,
) -> Result<ExecuteState, InterpreterError> {
#[cfg(feature = "debug")]
{
let debug = self.eval_debugger_state();
if !debug.should_continue() {
return Ok(debug.into())
}
}
self.instruction_inner(raw.into())
.map_err(|e| InterpreterError::from_runtime(e, raw.into()))
}
fn instruction_inner(
&mut self,
raw: RawInstruction,
) -> Result<ExecuteState, RuntimeError> {
let instruction = Instruction::try_from(raw)
.map_err(|_| RuntimeError::from(PanicReason::ErrorFlag))?;
if self.is_predicate() && !instruction.opcode().is_predicate_allowed() {
return Err(PanicReason::ContractInstructionNotAllowed.into())
}
macro_rules! r {
($id:expr) => {
self.registers[$id]
};
}
match instruction {
Instruction::ADD(add) => {
self.gas_charge(self.gas_costs.add)?;
let (a, b, c) = add.unpack();
self.alu_capture_overflow(
a.into(),
u128::overflowing_add,
r!(b).into(),
r!(c).into(),
)?;
}
Instruction::ADDI(addi) => {
self.gas_charge(self.gas_costs.addi)?;
let (a, b, imm) = addi.unpack();
self.alu_capture_overflow(
a.into(),
u128::overflowing_add,
r!(b).into(),
imm.into(),
)?;
}
Instruction::AND(and) => {
self.gas_charge(self.gas_costs.and)?;
let (a, b, c) = and.unpack();
self.alu_set(a.into(), r!(b) & r!(c))?;
}
Instruction::ANDI(andi) => {
self.gas_charge(self.gas_costs.andi)?;
let (a, b, imm) = andi.unpack();
self.alu_set(a.into(), r!(b) & Word::from(imm))?;
}
Instruction::DIV(div) => {
self.gas_charge(self.gas_costs.div)?;
let (a, b, c) = div.unpack();
let c = r!(c);
self.alu_error(a.into(), Word::div, r!(b), c, c == 0)?;
}
Instruction::DIVI(divi) => {
self.gas_charge(self.gas_costs.divi)?;
let (a, b, imm) = divi.unpack();
let imm = Word::from(imm);
self.alu_error(a.into(), Word::div, r!(b), imm, imm == 0)?;
}
Instruction::EQ(eq) => {
self.gas_charge(self.gas_costs.eq)?;
let (a, b, c) = eq.unpack();
self.alu_set(a.into(), (r!(b) == r!(c)) as Word)?;
}
Instruction::EXP(exp) => {
self.gas_charge(self.gas_costs.exp)?;
let (a, b, c) = exp.unpack();
self.alu_boolean_overflow(a.into(), alu::exp, r!(b), r!(c))?;
}
Instruction::EXPI(expi) => {
self.gas_charge(self.gas_costs.expi)?;
let (a, b, imm) = expi.unpack();
let expo = u32::from(imm);
self.alu_boolean_overflow(a.into(), Word::overflowing_pow, r!(b), expo)?;
}
Instruction::GT(gt) => {
self.gas_charge(self.gas_costs.gt)?;
let (a, b, c) = gt.unpack();
self.alu_set(a.into(), (r!(b) > r!(c)) as Word)?;
}
Instruction::LT(lt) => {
self.gas_charge(self.gas_costs.lt)?;
let (a, b, c) = lt.unpack();
self.alu_set(a.into(), (r!(b) < r!(c)) as Word)?;
}
Instruction::WDCM(wdcm) => {
self.gas_charge(self.gas_costs.wdcm)?;
let (a, b, c, imm) = wdcm.unpack();
let args = wideint::CompareArgs::from_imm(imm)
.ok_or(PanicReason::InvalidImmediateValue)?;
self.alu_wideint_cmp_u128(a.into(), r!(b), r!(c), args)?;
}
Instruction::WQCM(wdcm) => {
self.gas_charge(self.gas_costs.wqcm)?;
let (a, b, c, imm) = wdcm.unpack();
let args = wideint::CompareArgs::from_imm(imm)
.ok_or(PanicReason::InvalidImmediateValue)?;
self.alu_wideint_cmp_u256(a.into(), r!(b), r!(c), args)?;
}
Instruction::WDOP(wdop) => {
self.gas_charge(self.gas_costs.wdcm)?;
let (a, b, c, imm) = wdop.unpack();
let args = wideint::MathArgs::from_imm(imm)
.ok_or(PanicReason::InvalidImmediateValue)?;
self.alu_wideint_op_u128(r!(a), r!(b), r!(c), args)?;
}
Instruction::WQOP(wqop) => {
self.gas_charge(self.gas_costs.wqcm)?;
let (a, b, c, imm) = wqop.unpack();
let args = wideint::MathArgs::from_imm(imm)
.ok_or(PanicReason::InvalidImmediateValue)?;
self.alu_wideint_op_u256(r!(a), r!(b), r!(c), args)?;
}
Instruction::WDML(wdml) => {
self.gas_charge(self.gas_costs.wdml)?;
let (a, b, c, imm) = wdml.unpack();
let args = wideint::MulArgs::from_imm(imm)
.ok_or(PanicReason::InvalidImmediateValue)?;
self.alu_wideint_mul_u128(r!(a), r!(b), r!(c), args)?;
}
Instruction::WQML(wqml) => {
self.gas_charge(self.gas_costs.wqml)?;
let (a, b, c, imm) = wqml.unpack();
let args = wideint::MulArgs::from_imm(imm)
.ok_or(PanicReason::InvalidImmediateValue)?;
self.alu_wideint_mul_u256(r!(a), r!(b), r!(c), args)?;
}
Instruction::WDDV(wddv) => {
self.gas_charge(self.gas_costs.wddv)?;
let (a, b, c, imm) = wddv.unpack();
let args = wideint::DivArgs::from_imm(imm)
.ok_or(PanicReason::InvalidImmediateValue)?;
self.alu_wideint_div_u128(r!(a), r!(b), r!(c), args)?;
}
Instruction::WQDV(wqdv) => {
self.gas_charge(self.gas_costs.wqdv)?;
let (a, b, c, imm) = wqdv.unpack();
let args = wideint::DivArgs::from_imm(imm)
.ok_or(PanicReason::InvalidImmediateValue)?;
self.alu_wideint_div_u256(r!(a), r!(b), r!(c), args)?;
}
Instruction::WDMD(wdmd) => {
self.gas_charge(self.gas_costs.wdmd)?;
let (a, b, c, d) = wdmd.unpack();
self.alu_wideint_muldiv_u128(r!(a), r!(b), r!(c), r!(d))?;
}
Instruction::WQMD(wqmd) => {
self.gas_charge(self.gas_costs.wqmd)?;
let (a, b, c, d) = wqmd.unpack();
self.alu_wideint_muldiv_u256(r!(a), r!(b), r!(c), r!(d))?;
}
Instruction::WDAM(wdam) => {
self.gas_charge(self.gas_costs.wdam)?;
let (a, b, c, d) = wdam.unpack();
self.alu_wideint_addmod_u128(r!(a), r!(b), r!(c), r!(d))?;
}
Instruction::WQAM(wqam) => {
self.gas_charge(self.gas_costs.wqam)?;
let (a, b, c, d) = wqam.unpack();
self.alu_wideint_addmod_u256(r!(a), r!(b), r!(c), r!(d))?;
}
Instruction::WDMM(wdmm) => {
self.gas_charge(self.gas_costs.wdmm)?;
let (a, b, c, d) = wdmm.unpack();
self.alu_wideint_mulmod_u128(r!(a), r!(b), r!(c), r!(d))?;
}
Instruction::WQMM(wqmm) => {
self.gas_charge(self.gas_costs.wqmm)?;
let (a, b, c, d) = wqmm.unpack();
self.alu_wideint_mulmod_u256(r!(a), r!(b), r!(c), r!(d))?;
}
Instruction::MLOG(mlog) => {
self.gas_charge(self.gas_costs.mlog)?;
let (a, b, c) = mlog.unpack();
let (lhs, rhs) = (r!(b), r!(c));
self.alu_error(
a.into(),
|l, r| {
l.checked_ilog(r)
.expect("checked_ilog returned None for valid values")
as Word
},
lhs,
rhs,
lhs == 0 || rhs <= 1,
)?;
}
Instruction::MOD(mod_) => {
self.gas_charge(self.gas_costs.mod_op)?;
let (a, b, c) = mod_.unpack();
let rhs = r!(c);
self.alu_error(a.into(), Word::wrapping_rem, r!(b), rhs, rhs == 0)?;
}
Instruction::MODI(modi) => {
self.gas_charge(self.gas_costs.modi)?;
let (a, b, imm) = modi.unpack();
let rhs = Word::from(imm);
self.alu_error(a.into(), Word::wrapping_rem, r!(b), rhs, rhs == 0)?;
}
Instruction::MOVE(move_) => {
self.gas_charge(self.gas_costs.move_op)?;
let (a, b) = move_.unpack();
self.alu_set(a.into(), r!(b))?;
}
Instruction::MOVI(movi) => {
self.gas_charge(self.gas_costs.movi)?;
let (a, imm) = movi.unpack();
self.alu_set(a.into(), Word::from(imm))?;
}
Instruction::MROO(mroo) => {
self.gas_charge(self.gas_costs.mroo)?;
let (a, b, c) = mroo.unpack();
let (lhs, rhs) = (r!(b), r!(c));
self.alu_error(
a.into(),
|l, r| {
checked_nth_root(l, r)
.expect("checked_nth_root returned None for valid values")
as Word
},
lhs,
rhs,
rhs == 0,
)?;
}
Instruction::MUL(mul) => {
self.gas_charge(self.gas_costs.mul)?;
let (a, b, c) = mul.unpack();
self.alu_capture_overflow(
a.into(),
u128::overflowing_mul,
r!(b).into(),
r!(c).into(),
)?;
}
Instruction::MULI(muli) => {
self.gas_charge(self.gas_costs.muli)?;
let (a, b, imm) = muli.unpack();
self.alu_capture_overflow(
a.into(),
u128::overflowing_mul,
r!(b).into(),
imm.into(),
)?;
}
Instruction::MLDV(mldv) => {
self.gas_charge(self.gas_costs.mldv)?;
let (a, b, c, d) = mldv.unpack();
self.alu_muldiv(a.into(), r!(b), r!(c), r!(d))?;
}
Instruction::NOOP(_noop) => {
self.gas_charge(self.gas_costs.noop)?;
self.alu_clear()?;
}
Instruction::NOT(not) => {
self.gas_charge(self.gas_costs.not)?;
let (a, b) = not.unpack();
self.alu_set(a.into(), !r!(b))?;
}
Instruction::OR(or) => {
self.gas_charge(self.gas_costs.or)?;
let (a, b, c) = or.unpack();
self.alu_set(a.into(), r!(b) | r!(c))?;
}
Instruction::ORI(ori) => {
self.gas_charge(self.gas_costs.ori)?;
let (a, b, imm) = ori.unpack();
self.alu_set(a.into(), r!(b) | Word::from(imm))?;
}
Instruction::SLL(sll) => {
self.gas_charge(self.gas_costs.sll)?;
let (a, b, c) = sll.unpack();
self.alu_set(
a.into(),
if let Ok(c) = r!(c).try_into() {
Word::checked_shl(r!(b), c).unwrap_or_default()
} else {
0
},
)?;
}
Instruction::SLLI(slli) => {
self.gas_charge(self.gas_costs.slli)?;
let (a, b, imm) = slli.unpack();
let rhs = u32::from(imm);
self.alu_set(a.into(), r!(b).checked_shl(rhs).unwrap_or_default())?;
}
Instruction::SRL(srl) => {
self.gas_charge(self.gas_costs.srl)?;
let (a, b, c) = srl.unpack();
self.alu_set(
a.into(),
if let Ok(c) = r!(c).try_into() {
Word::checked_shr(r!(b), c).unwrap_or_default()
} else {
0
},
)?;
}
Instruction::SRLI(srli) => {
self.gas_charge(self.gas_costs.srli)?;
let (a, b, imm) = srli.unpack();
let rhs = u32::from(imm);
self.alu_set(a.into(), r!(b).checked_shr(rhs).unwrap_or_default())?;
}
Instruction::SUB(sub) => {
self.gas_charge(self.gas_costs.sub)?;
let (a, b, c) = sub.unpack();
self.alu_capture_overflow(
a.into(),
u128::overflowing_sub,
r!(b).into(),
r!(c).into(),
)?;
}
Instruction::SUBI(subi) => {
self.gas_charge(self.gas_costs.subi)?;
let (a, b, imm) = subi.unpack();
self.alu_capture_overflow(
a.into(),
u128::overflowing_sub,
r!(b).into(),
imm.into(),
)?;
}
Instruction::XOR(xor) => {
self.gas_charge(self.gas_costs.xor)?;
let (a, b, c) = xor.unpack();
self.alu_set(a.into(), r!(b) ^ r!(c))?;
}
Instruction::XORI(xori) => {
self.gas_charge(self.gas_costs.xori)?;
let (a, b, imm) = xori.unpack();
self.alu_set(a.into(), r!(b) ^ Word::from(imm))?;
}
Instruction::JI(ji) => {
self.gas_charge(self.gas_costs.ji)?;
let imm = ji.unpack();
self.jump(JumpArgs::new(JumpMode::Absolute).to_address(imm.into()))?;
}
Instruction::JNEI(jnei) => {
self.gas_charge(self.gas_costs.jnei)?;
let (a, b, imm) = jnei.unpack();
self.jump(
JumpArgs::new(JumpMode::Absolute)
.with_condition(r!(a) != r!(b))
.to_address(imm.into()),
)?;
}
Instruction::JNZI(jnzi) => {
self.gas_charge(self.gas_costs.jnzi)?;
let (a, imm) = jnzi.unpack();
self.jump(
JumpArgs::new(JumpMode::Absolute)
.with_condition(r!(a) != 0)
.to_address(imm.into()),
)?;
}
Instruction::JMP(jmp) => {
self.gas_charge(self.gas_costs.jmp)?;
let a = jmp.unpack();
self.jump(JumpArgs::new(JumpMode::Absolute).to_address(r!(a)))?;
}
Instruction::JNE(jne) => {
self.gas_charge(self.gas_costs.jne)?;
let (a, b, c) = jne.unpack();
self.jump(
JumpArgs::new(JumpMode::Absolute)
.with_condition(r!(a) != r!(b))
.to_address(r!(c)),
)?;
}
Instruction::JMPF(jmpf) => {
self.gas_charge(self.gas_costs.jmpf)?;
let (a, offset) = jmpf.unpack();
self.jump(
JumpArgs::new(JumpMode::RelativeForwards)
.to_address(r!(a))
.plus_fixed(offset.into()),
)?;
}
Instruction::JMPB(jmpb) => {
self.gas_charge(self.gas_costs.jmpb)?;
let (a, offset) = jmpb.unpack();
self.jump(
JumpArgs::new(JumpMode::RelativeBackwards)
.to_address(r!(a))
.plus_fixed(offset.into()),
)?;
}
Instruction::JNZF(jnzf) => {
self.gas_charge(self.gas_costs.jnzf)?;
let (a, b, offset) = jnzf.unpack();
self.jump(
JumpArgs::new(JumpMode::RelativeForwards)
.with_condition(r!(a) != 0)
.to_address(r!(b))
.plus_fixed(offset.into()),
)?;
}
Instruction::JNZB(jnzb) => {
self.gas_charge(self.gas_costs.jnzb)?;
let (a, b, offset) = jnzb.unpack();
self.jump(
JumpArgs::new(JumpMode::RelativeBackwards)
.with_condition(r!(a) != 0)
.to_address(r!(b))
.plus_fixed(offset.into()),
)?;
}
Instruction::JNEF(jnef) => {
self.gas_charge(self.gas_costs.jnef)?;
let (a, b, c, offset) = jnef.unpack();
self.jump(
JumpArgs::new(JumpMode::RelativeForwards)
.with_condition(r!(a) != r!(b))
.to_address(r!(c))
.plus_fixed(offset.into()),
)?;
}
Instruction::JNEB(jneb) => {
self.gas_charge(self.gas_costs.jneb)?;
let (a, b, c, offset) = jneb.unpack();
self.jump(
JumpArgs::new(JumpMode::RelativeBackwards)
.with_condition(r!(a) != r!(b))
.to_address(r!(c))
.plus_fixed(offset.into()),
)?;
}
Instruction::RET(ret) => {
self.gas_charge(self.gas_costs.ret)?;
let a = ret.unpack();
let ra = r!(a);
self.ret(ra)?;
return Ok(ExecuteState::Return(ra))
}
Instruction::RETD(retd) => {
let (a, b) = retd.unpack();
let len = r!(b);
self.dependent_gas_charge(self.gas_costs.retd, len)?;
return self.ret_data(r!(a), len).map(ExecuteState::ReturnData)
}
Instruction::RVRT(rvrt) => {
self.gas_charge(self.gas_costs.rvrt)?;
let a = rvrt.unpack();
let ra = r!(a);
self.revert(ra);
return Ok(ExecuteState::Revert(ra))
}
Instruction::SMO(smo) => {
let (a, b, c, d) = smo.unpack();
self.dependent_gas_charge(self.gas_costs.smo, r!(c))?;
self.message_output(r!(a), r!(b), r!(c), r!(d))?;
}
Instruction::ALOC(aloc) => {
self.gas_charge(self.gas_costs.aloc)?;
let a = aloc.unpack();
self.malloc(r!(a))?;
}
Instruction::CFEI(cfei) => {
self.gas_charge(self.gas_costs.cfei)?;
let imm = cfei.unpack();
self.stack_pointer_overflow(Word::overflowing_add, imm.into())?;
}
Instruction::CFE(cfe) => {
self.gas_charge(self.gas_costs.cfei)?;
let a = cfe.unpack();
self.stack_pointer_overflow(Word::overflowing_add, r!(a))?;
}
Instruction::CFSI(cfsi) => {
self.gas_charge(self.gas_costs.cfsi)?;
let imm = cfsi.unpack();
self.stack_pointer_overflow(Word::overflowing_sub, imm.into())?;
}
Instruction::CFS(cfs) => {
self.gas_charge(self.gas_costs.cfsi)?;
let a = cfs.unpack();
self.stack_pointer_overflow(Word::overflowing_sub, r!(a))?;
}
Instruction::LB(lb) => {
self.gas_charge(self.gas_costs.lb)?;
let (a, b, imm) = lb.unpack();
self.load_byte(a.into(), r!(b), imm.into())?;
}
Instruction::LW(lw) => {
self.gas_charge(self.gas_costs.lw)?;
let (a, b, imm) = lw.unpack();
self.load_word(a.into(), r!(b), imm.into())?;
}
Instruction::MCL(mcl) => {
let (a, b) = mcl.unpack();
let len = r!(b);
self.dependent_gas_charge(self.gas_costs.mcl, len)?;
self.memclear(r!(a), len)?;
}
Instruction::MCLI(mcli) => {
let (a, imm) = mcli.unpack();
let len = Word::from(imm);
self.dependent_gas_charge(self.gas_costs.mcli, len)?;
self.memclear(r!(a), len)?;
}
Instruction::MCP(mcp) => {
let (a, b, c) = mcp.unpack();
let len = r!(c);
self.dependent_gas_charge(self.gas_costs.mcp, len)?;
self.memcopy(r!(a), r!(b), len)?;
}
Instruction::MCPI(mcpi) => {
self.gas_charge(self.gas_costs.mcpi)?;
let (a, b, imm) = mcpi.unpack();
let len = imm.into();
self.memcopy(r!(a), r!(b), len)?;
}
Instruction::MEQ(meq) => {
let (a, b, c, d) = meq.unpack();
let len = r!(d);
self.dependent_gas_charge(self.gas_costs.meq, len)?;
self.memeq(a.into(), r!(b), r!(c), len)?;
}
Instruction::SB(sb) => {
self.gas_charge(self.gas_costs.sb)?;
let (a, b, imm) = sb.unpack();
self.store_byte(r!(a), r!(b), imm.into())?;
}
Instruction::SW(sw) => {
self.gas_charge(self.gas_costs.sw)?;
let (a, b, imm) = sw.unpack();
self.store_word(r!(a), r!(b), imm.into())?;
}
Instruction::BAL(bal) => {
self.gas_charge(self.gas_costs.bal)?;
let (a, b, c) = bal.unpack();
self.contract_balance(a.into(), r!(b), r!(c))?;
}
Instruction::BHEI(bhei) => {
self.gas_charge(self.gas_costs.bhei)?;
let a = bhei.unpack();
self.block_height(a.into())?;
}
Instruction::BHSH(bhsh) => {
self.gas_charge(self.gas_costs.bhsh)?;
let (a, b) = bhsh.unpack();
self.block_hash(r!(a), r!(b))?;
}
Instruction::BURN(burn) => {
self.gas_charge(self.gas_costs.burn)?;
let (a, b) = burn.unpack();
self.burn(r!(a), r!(b))?;
}
Instruction::CALL(call) => {
let (a, b, c, d) = call.unpack();
self.prepare_call(a, b, c, d)?;
}
Instruction::CB(cb) => {
self.gas_charge(self.gas_costs.cb)?;
let a = cb.unpack();
self.block_proposer(r!(a))?;
}
Instruction::CCP(ccp) => {
let (a, b, c, d) = ccp.unpack();
let len = r!(d);
self.dependent_gas_charge(self.gas_costs.ccp, len)?;
self.code_copy(r!(a), r!(b), r!(c), len)?;
}
Instruction::CROO(croo) => {
self.gas_charge(self.gas_costs.croo)?;
let (a, b) = croo.unpack();
self.code_root(r!(a), r!(b))?;
}
Instruction::CSIZ(csiz) => {
let (a, b) = csiz.unpack();
self.code_size(a.into(), r!(b))?;
}
Instruction::LDC(ldc) => {
let (a, b, c) = ldc.unpack();
self.dependent_gas_charge(self.gas_costs.ldc, r!(c))?;
self.load_contract_code(r!(a), r!(b), r!(c))?;
}
Instruction::LOG(log) => {
self.gas_charge(self.gas_costs.log)?;
let (a, b, c, d) = log.unpack();
self.log(r!(a), r!(b), r!(c), r!(d))?;
}
Instruction::LOGD(logd) => {
let (a, b, c, d) = logd.unpack();
self.dependent_gas_charge(self.gas_costs.logd, r!(d))?;
self.log_data(r!(a), r!(b), r!(c), r!(d))?;
}
Instruction::MINT(mint) => {
self.gas_charge(self.gas_costs.mint)?;
let (a, b) = mint.unpack();
self.mint(r!(a), r!(b))?;
}
Instruction::SCWQ(scwq) => {
self.gas_charge(self.gas_costs.scwq)?;
let (a, b, c) = scwq.unpack();
self.state_clear_qword(r!(a), b.into(), r!(c))?;
}
Instruction::SRW(srw) => {
self.gas_charge(self.gas_costs.srw)?;
let (a, b, c) = srw.unpack();
self.state_read_word(a.into(), b.into(), r!(c))?;
}
Instruction::SRWQ(srwq) => {
let (a, b, c, d) = srwq.unpack();
self.dependent_gas_charge(self.gas_costs.srwq, r!(d))?;
self.state_read_qword(r!(a), b.into(), r!(c), r!(d))?;
}
Instruction::SWW(sww) => {
self.gas_charge(self.gas_costs.sww)?;
let (a, b, c) = sww.unpack();
self.state_write_word(r!(a), b.into(), r!(c))?;
}
Instruction::SWWQ(swwq) => {
self.gas_charge(self.gas_costs.swwq)?;
let (a, b, c, d) = swwq.unpack();
self.state_write_qword(r!(a), b.into(), r!(c), r!(d))?;
}
Instruction::TIME(time) => {
self.gas_charge(self.gas_costs.time)?;
let (a, b) = time.unpack();
self.timestamp(a.into(), r!(b))?;
}
Instruction::ECK1(eck1) => {
self.gas_charge(self.gas_costs.eck1)?;
let (a, b, c) = eck1.unpack();
self.secp256k1_recover(r!(a), r!(b), r!(c))?;
}
Instruction::ECR1(ecr1) => {
self.gas_charge(self.gas_costs.ecr1)?;
let (a, b, c) = ecr1.unpack();
self.secp256r1_recover(r!(a), r!(b), r!(c))?;
}
Instruction::ED19(ed19) => {
self.gas_charge(self.gas_costs.ed19)?;
let (a, b, c) = ed19.unpack();
self.ed25519_verify(r!(a), r!(b), r!(c))?;
}
Instruction::K256(k256) => {
self.gas_charge(self.gas_costs.k256)?;
let (a, b, c) = k256.unpack();
self.keccak256(r!(a), r!(b), r!(c))?;
}
Instruction::S256(s256) => {
self.gas_charge(self.gas_costs.s256)?;
let (a, b, c) = s256.unpack();
self.sha256(r!(a), r!(b), r!(c))?;
}
Instruction::FLAG(flag) => {
self.gas_charge(self.gas_costs.flag)?;
let a = flag.unpack();
self.set_flag(r!(a))?;
}
Instruction::GM(gm) => {
self.gas_charge(self.gas_costs.gm)?;
let (a, imm) = gm.unpack();
self.metadata(a.into(), imm.into())?;
}
Instruction::GTF(gtf) => {
self.gas_charge(self.gas_costs.gtf)?;
let (a, b, imm) = gtf.unpack();
self.get_transaction_field(a.into(), r!(b), imm.into())?;
}
Instruction::TR(tr) => {
self.gas_charge(self.gas_costs.tr)?;
let (a, b, c) = tr.unpack();
self.transfer(r!(a), r!(b), r!(c))?;
}
Instruction::TRO(tro) => {
self.gas_charge(self.gas_costs.tro)?;
let (a, b, c, d) = tro.unpack();
self.transfer_output(r!(a), r!(b), r!(c), r!(d))?;
}
}
Ok(ExecuteState::Proceed)
}
}
fn checked_nth_root(target: u64, nth_root: u64) -> Option<u64> {
if nth_root == 0 {
return None
}
if nth_root == 1 || target <= 1 {
return Some(target)
}
if nth_root >= target || nth_root > 64 {
return Some(1)
}
let nth_root = nth_root as u32; let guess = (target as f64).powf((nth_root as f64).recip()) as u64;
debug_assert!(guess != 0, "This should never occur for {{target, n}} > 1");
let is_nth_power_below_target = |v: u64| match v.checked_pow(nth_root) {
Some(pow) => target < pow,
None => true, };
if is_nth_power_below_target(guess) {
return Some(guess - 1)
}
if is_nth_power_below_target(guess + 1) {
return Some(guess)
}
Some(guess + 1)
}
#[cfg(test)]
mod tests;