1use crate::{
2 constraints::reg_key::ProgramRegistersSegment,
3 error::{
4 InterpreterError,
5 IoResult,
6 RuntimeError,
7 },
8 interpreter::{
9 alu,
10 flow::{
11 JumpArgs,
12 JumpMode,
13 },
14 EcalHandler,
15 ExecutableTransaction,
16 Interpreter,
17 Memory,
18 },
19 state::ExecuteState,
20 storage::InterpreterStorage,
21};
22
23use fuel_asm::{
24 wideint,
25 Instruction,
26 PanicInstruction,
27 PanicReason,
28 RawInstruction,
29 RegId,
30};
31use fuel_types::Word;
32
33use core::ops::Div;
34
35impl<M, S, Tx, Ecal> Interpreter<M, S, Tx, Ecal>
36where
37 M: Memory,
38 S: InterpreterStorage,
39 Tx: ExecutableTransaction,
40 Ecal: EcalHandler,
41{
42 pub fn execute(&mut self) -> Result<ExecuteState, InterpreterError<S::DataError>> {
44 let raw_instruction = self.fetch_instruction()?;
45 self.instruction(raw_instruction)
46 }
47
48 fn fetch_instruction(
51 &self,
52 ) -> Result<RawInstruction, InterpreterError<S::DataError>> {
53 let pc = self.registers[RegId::PC];
54 let instruction = RawInstruction::from_be_bytes(
55 self.memory().read_bytes(pc).map_err(|reason| {
56 InterpreterError::PanicInstruction(PanicInstruction::error(
57 reason,
58 0, ))
60 })?,
61 );
62 if pc < self.registers[RegId::IS] || pc >= self.registers[RegId::SSP] {
63 return Err(InterpreterError::PanicInstruction(PanicInstruction::error(
64 PanicReason::MemoryNotExecutable,
65 instruction,
66 )))
67 }
68 Ok(instruction)
69 }
70
71 pub fn instruction<R: Into<RawInstruction> + Copy>(
73 &mut self,
74 raw: R,
75 ) -> Result<ExecuteState, InterpreterError<S::DataError>> {
76 if self.debugger.is_active() {
77 let debug = self.eval_debugger_state();
78 if !debug.should_continue() {
79 return Ok(debug.into())
80 }
81 }
82
83 self.instruction_inner(raw.into())
84 .map_err(|e| InterpreterError::from_runtime(e, raw.into()))
85 }
86
87 fn instruction_inner(
88 &mut self,
89 raw: RawInstruction,
90 ) -> IoResult<ExecuteState, S::DataError> {
91 let instruction = Instruction::try_from(raw)
92 .map_err(|_| RuntimeError::from(PanicReason::InvalidInstruction))?;
93
94 if self.is_predicate() && !instruction.opcode().is_predicate_allowed() {
97 return Err(PanicReason::ContractInstructionNotAllowed.into())
98 }
99
100 macro_rules! r {
103 ($id:expr) => {
104 self.registers[$id]
105 };
106 }
107
108 match instruction {
109 Instruction::ADD(add) => {
110 self.gas_charge(self.gas_costs().add())?;
111 let (a, b, c) = add.unpack();
112 self.alu_capture_overflow(
113 a.into(),
114 u128::overflowing_add,
115 r!(b).into(),
116 r!(c).into(),
117 )?;
118 }
119
120 Instruction::ADDI(addi) => {
121 self.gas_charge(self.gas_costs().addi())?;
122 let (a, b, imm) = addi.unpack();
123 self.alu_capture_overflow(
124 a.into(),
125 u128::overflowing_add,
126 r!(b).into(),
127 imm.into(),
128 )?;
129 }
130
131 Instruction::AND(and) => {
132 self.gas_charge(self.gas_costs().and())?;
133 let (a, b, c) = and.unpack();
134 self.alu_set(a.into(), r!(b) & r!(c))?;
135 }
136
137 Instruction::ANDI(andi) => {
138 self.gas_charge(self.gas_costs().andi())?;
139 let (a, b, imm) = andi.unpack();
140 self.alu_set(a.into(), r!(b) & Word::from(imm))?;
141 }
142
143 Instruction::DIV(div) => {
144 self.gas_charge(self.gas_costs().div())?;
145 let (a, b, c) = div.unpack();
146 let c = r!(c);
147 self.alu_error(a.into(), Word::div, r!(b), c, c == 0)?;
148 }
149
150 Instruction::DIVI(divi) => {
151 self.gas_charge(self.gas_costs().divi())?;
152 let (a, b, imm) = divi.unpack();
153 let imm = Word::from(imm);
154 self.alu_error(a.into(), Word::div, r!(b), imm, imm == 0)?;
155 }
156
157 Instruction::EQ(eq) => {
158 self.gas_charge(self.gas_costs().eq_())?;
159 let (a, b, c) = eq.unpack();
160 self.alu_set(a.into(), (r!(b) == r!(c)) as Word)?;
161 }
162
163 Instruction::EXP(exp) => {
164 self.gas_charge(self.gas_costs().exp())?;
165 let (a, b, c) = exp.unpack();
166 self.alu_boolean_overflow(a.into(), alu::exp, r!(b), r!(c))?;
167 }
168
169 Instruction::EXPI(expi) => {
170 self.gas_charge(self.gas_costs().expi())?;
171 let (a, b, imm) = expi.unpack();
172 let expo = u32::from(imm);
173 self.alu_boolean_overflow(a.into(), Word::overflowing_pow, r!(b), expo)?;
174 }
175
176 Instruction::GT(gt) => {
177 self.gas_charge(self.gas_costs().gt())?;
178 let (a, b, c) = gt.unpack();
179 self.alu_set(a.into(), (r!(b) > r!(c)) as Word)?;
180 }
181
182 Instruction::LT(lt) => {
183 self.gas_charge(self.gas_costs().lt())?;
184 let (a, b, c) = lt.unpack();
185 self.alu_set(a.into(), (r!(b) < r!(c)) as Word)?;
186 }
187
188 Instruction::WDCM(wdcm) => {
189 self.gas_charge(self.gas_costs().wdcm())?;
190 let (a, b, c, imm) = wdcm.unpack();
191 let args = wideint::CompareArgs::from_imm(imm)
192 .ok_or(PanicReason::InvalidImmediateValue)?;
193 self.alu_wideint_cmp_u128(a.into(), r!(b), r!(c), args)?;
194 }
195
196 Instruction::WQCM(wqcm) => {
197 self.gas_charge(self.gas_costs().wqcm())?;
198 let (a, b, c, imm) = wqcm.unpack();
199 let args = wideint::CompareArgs::from_imm(imm)
200 .ok_or(PanicReason::InvalidImmediateValue)?;
201 self.alu_wideint_cmp_u256(a.into(), r!(b), r!(c), args)?;
202 }
203
204 Instruction::WDOP(wdop) => {
205 self.gas_charge(self.gas_costs().wdop())?;
206 let (a, b, c, imm) = wdop.unpack();
207 let args = wideint::MathArgs::from_imm(imm)
208 .ok_or(PanicReason::InvalidImmediateValue)?;
209 self.alu_wideint_op_u128(r!(a), r!(b), r!(c), args)?;
210 }
211
212 Instruction::WQOP(wqop) => {
213 self.gas_charge(self.gas_costs().wqop())?;
214 let (a, b, c, imm) = wqop.unpack();
215 let args = wideint::MathArgs::from_imm(imm)
216 .ok_or(PanicReason::InvalidImmediateValue)?;
217 self.alu_wideint_op_u256(r!(a), r!(b), r!(c), args)?;
218 }
219
220 Instruction::WDML(wdml) => {
221 self.gas_charge(self.gas_costs().wdml())?;
222 let (a, b, c, imm) = wdml.unpack();
223 let args = wideint::MulArgs::from_imm(imm)
224 .ok_or(PanicReason::InvalidImmediateValue)?;
225 self.alu_wideint_mul_u128(r!(a), r!(b), r!(c), args)?;
226 }
227
228 Instruction::WQML(wqml) => {
229 self.gas_charge(self.gas_costs().wqml())?;
230 let (a, b, c, imm) = wqml.unpack();
231 let args = wideint::MulArgs::from_imm(imm)
232 .ok_or(PanicReason::InvalidImmediateValue)?;
233 self.alu_wideint_mul_u256(r!(a), r!(b), r!(c), args)?;
234 }
235
236 Instruction::WDDV(wddv) => {
237 self.gas_charge(self.gas_costs().wddv())?;
238 let (a, b, c, imm) = wddv.unpack();
239 let args = wideint::DivArgs::from_imm(imm)
240 .ok_or(PanicReason::InvalidImmediateValue)?;
241 self.alu_wideint_div_u128(r!(a), r!(b), r!(c), args)?;
242 }
243
244 Instruction::WQDV(wqdv) => {
245 self.gas_charge(self.gas_costs().wqdv())?;
246 let (a, b, c, imm) = wqdv.unpack();
247 let args = wideint::DivArgs::from_imm(imm)
248 .ok_or(PanicReason::InvalidImmediateValue)?;
249 self.alu_wideint_div_u256(r!(a), r!(b), r!(c), args)?;
250 }
251
252 Instruction::WDMD(wdmd) => {
253 self.gas_charge(self.gas_costs().wdmd())?;
254 let (a, b, c, d) = wdmd.unpack();
255 self.alu_wideint_muldiv_u128(r!(a), r!(b), r!(c), r!(d))?;
256 }
257
258 Instruction::WQMD(wqmd) => {
259 self.gas_charge(self.gas_costs().wqmd())?;
260 let (a, b, c, d) = wqmd.unpack();
261 self.alu_wideint_muldiv_u256(r!(a), r!(b), r!(c), r!(d))?;
262 }
263
264 Instruction::WDAM(wdam) => {
265 self.gas_charge(self.gas_costs().wdam())?;
266 let (a, b, c, d) = wdam.unpack();
267 self.alu_wideint_addmod_u128(r!(a), r!(b), r!(c), r!(d))?;
268 }
269 Instruction::WQAM(wqam) => {
270 self.gas_charge(self.gas_costs().wqam())?;
271 let (a, b, c, d) = wqam.unpack();
272 self.alu_wideint_addmod_u256(r!(a), r!(b), r!(c), r!(d))?;
273 }
274 Instruction::WDMM(wdmm) => {
275 self.gas_charge(self.gas_costs().wdmm())?;
276 let (a, b, c, d) = wdmm.unpack();
277 self.alu_wideint_mulmod_u128(r!(a), r!(b), r!(c), r!(d))?;
278 }
279 Instruction::WQMM(wqmm) => {
280 self.gas_charge(self.gas_costs().wqmm())?;
281 let (a, b, c, d) = wqmm.unpack();
282 self.alu_wideint_mulmod_u256(r!(a), r!(b), r!(c), r!(d))?;
283 }
284
285 Instruction::MLOG(mlog) => {
286 self.gas_charge(self.gas_costs().mlog())?;
287 let (a, b, c) = mlog.unpack();
288 let (lhs, rhs) = (r!(b), r!(c));
289 self.alu_error(
290 a.into(),
291 |l, r| {
292 l.checked_ilog(r)
293 .expect("checked_ilog returned None for valid values")
294 as Word
295 },
296 lhs,
297 rhs,
298 lhs == 0 || rhs <= 1,
299 )?;
300 }
301
302 Instruction::MOD(mod_) => {
303 self.gas_charge(self.gas_costs().mod_op())?;
304 let (a, b, c) = mod_.unpack();
305 let rhs = r!(c);
306 self.alu_error(a.into(), Word::wrapping_rem, r!(b), rhs, rhs == 0)?;
307 }
308
309 Instruction::MODI(modi) => {
310 self.gas_charge(self.gas_costs().modi())?;
311 let (a, b, imm) = modi.unpack();
312 let rhs = Word::from(imm);
313 self.alu_error(a.into(), Word::wrapping_rem, r!(b), rhs, rhs == 0)?;
314 }
315
316 Instruction::MOVE(move_) => {
317 self.gas_charge(self.gas_costs().move_op())?;
318 let (a, b) = move_.unpack();
319 self.alu_set(a.into(), r!(b))?;
320 }
321
322 Instruction::MOVI(movi) => {
323 self.gas_charge(self.gas_costs().movi())?;
324 let (a, imm) = movi.unpack();
325 self.alu_set(a.into(), Word::from(imm))?;
326 }
327
328 Instruction::MROO(mroo) => {
329 self.gas_charge(self.gas_costs().mroo())?;
330 let (a, b, c) = mroo.unpack();
331 let (lhs, rhs) = (r!(b), r!(c));
332 self.alu_error(
333 a.into(),
334 |l, r| {
335 checked_nth_root(l, r)
336 .expect("checked_nth_root returned None for valid values")
337 as Word
338 },
339 lhs,
340 rhs,
341 rhs == 0,
342 )?;
343 }
344
345 Instruction::MUL(mul) => {
346 self.gas_charge(self.gas_costs().mul())?;
347 let (a, b, c) = mul.unpack();
348 self.alu_capture_overflow(
349 a.into(),
350 u128::overflowing_mul,
351 r!(b).into(),
352 r!(c).into(),
353 )?;
354 }
355
356 Instruction::MULI(muli) => {
357 self.gas_charge(self.gas_costs().muli())?;
358 let (a, b, imm) = muli.unpack();
359 self.alu_capture_overflow(
360 a.into(),
361 u128::overflowing_mul,
362 r!(b).into(),
363 imm.into(),
364 )?;
365 }
366
367 Instruction::MLDV(mldv) => {
368 self.gas_charge(self.gas_costs().mldv())?;
369 let (a, b, c, d) = mldv.unpack();
370 self.alu_muldiv(a.into(), r!(b), r!(c), r!(d))?;
371 }
372
373 Instruction::NOOP(_noop) => {
374 self.gas_charge(self.gas_costs().noop())?;
375 self.alu_clear()?;
376 }
377
378 Instruction::NOT(not) => {
379 self.gas_charge(self.gas_costs().not())?;
380 let (a, b) = not.unpack();
381 self.alu_set(a.into(), !r!(b))?;
382 }
383
384 Instruction::OR(or) => {
385 self.gas_charge(self.gas_costs().or())?;
386 let (a, b, c) = or.unpack();
387 self.alu_set(a.into(), r!(b) | r!(c))?;
388 }
389
390 Instruction::ORI(ori) => {
391 self.gas_charge(self.gas_costs().ori())?;
392 let (a, b, imm) = ori.unpack();
393 self.alu_set(a.into(), r!(b) | Word::from(imm))?;
394 }
395
396 Instruction::SLL(sll) => {
397 self.gas_charge(self.gas_costs().sll())?;
398 let (a, b, c) = sll.unpack();
399
400 self.alu_set(
401 a.into(),
402 if let Ok(c) = r!(c).try_into() {
403 Word::checked_shl(r!(b), c).unwrap_or_default()
404 } else {
405 0
406 },
407 )?;
408 }
409
410 Instruction::SLLI(slli) => {
411 self.gas_charge(self.gas_costs().slli())?;
412 let (a, b, imm) = slli.unpack();
413 let rhs = u32::from(imm);
414 self.alu_set(a.into(), r!(b).checked_shl(rhs).unwrap_or_default())?;
415 }
416
417 Instruction::SRL(srl) => {
418 self.gas_charge(self.gas_costs().srl())?;
419 let (a, b, c) = srl.unpack();
420 self.alu_set(
421 a.into(),
422 if let Ok(c) = r!(c).try_into() {
423 Word::checked_shr(r!(b), c).unwrap_or_default()
424 } else {
425 0
426 },
427 )?;
428 }
429
430 Instruction::SRLI(srli) => {
431 self.gas_charge(self.gas_costs().srli())?;
432 let (a, b, imm) = srli.unpack();
433 let rhs = u32::from(imm);
434 self.alu_set(a.into(), r!(b).checked_shr(rhs).unwrap_or_default())?;
435 }
436
437 Instruction::SUB(sub) => {
438 self.gas_charge(self.gas_costs().sub())?;
439 let (a, b, c) = sub.unpack();
440 self.alu_capture_overflow(
441 a.into(),
442 u128::overflowing_sub,
443 r!(b).into(),
444 r!(c).into(),
445 )?;
446 }
447
448 Instruction::SUBI(subi) => {
449 self.gas_charge(self.gas_costs().subi())?;
450 let (a, b, imm) = subi.unpack();
451 self.alu_capture_overflow(
452 a.into(),
453 u128::overflowing_sub,
454 r!(b).into(),
455 imm.into(),
456 )?;
457 }
458
459 Instruction::XOR(xor) => {
460 self.gas_charge(self.gas_costs().xor())?;
461 let (a, b, c) = xor.unpack();
462 self.alu_set(a.into(), r!(b) ^ r!(c))?;
463 }
464
465 Instruction::XORI(xori) => {
466 self.gas_charge(self.gas_costs().xori())?;
467 let (a, b, imm) = xori.unpack();
468 self.alu_set(a.into(), r!(b) ^ Word::from(imm))?;
469 }
470
471 Instruction::JI(ji) => {
472 self.gas_charge(self.gas_costs().ji())?;
473 let imm = ji.unpack();
474 self.jump(JumpArgs::new(JumpMode::Absolute).to_address(imm.into()))?;
475 }
476
477 Instruction::JNEI(jnei) => {
478 self.gas_charge(self.gas_costs().jnei())?;
479 let (a, b, imm) = jnei.unpack();
480 self.jump(
481 JumpArgs::new(JumpMode::Absolute)
482 .with_condition(r!(a) != r!(b))
483 .to_address(imm.into()),
484 )?;
485 }
486
487 Instruction::JNZI(jnzi) => {
488 self.gas_charge(self.gas_costs().jnzi())?;
489 let (a, imm) = jnzi.unpack();
490 self.jump(
491 JumpArgs::new(JumpMode::Absolute)
492 .with_condition(r!(a) != 0)
493 .to_address(imm.into()),
494 )?;
495 }
496
497 Instruction::JMP(jmp) => {
498 self.gas_charge(self.gas_costs().jmp())?;
499 let a = jmp.unpack();
500 self.jump(JumpArgs::new(JumpMode::Absolute).to_address(r!(a)))?;
501 }
502
503 Instruction::JNE(jne) => {
504 self.gas_charge(self.gas_costs().jne())?;
505 let (a, b, c) = jne.unpack();
506 self.jump(
507 JumpArgs::new(JumpMode::Absolute)
508 .with_condition(r!(a) != r!(b))
509 .to_address(r!(c)),
510 )?;
511 }
512
513 Instruction::JMPF(jmpf) => {
514 self.gas_charge(self.gas_costs().jmpf())?;
515 let (a, offset) = jmpf.unpack();
516 self.jump(
517 JumpArgs::new(JumpMode::RelativeForwards)
518 .to_address(r!(a))
519 .plus_fixed(offset.into()),
520 )?;
521 }
522
523 Instruction::JMPB(jmpb) => {
524 self.gas_charge(self.gas_costs().jmpb())?;
525 let (a, offset) = jmpb.unpack();
526 self.jump(
527 JumpArgs::new(JumpMode::RelativeBackwards)
528 .to_address(r!(a))
529 .plus_fixed(offset.into()),
530 )?;
531 }
532
533 Instruction::JNZF(jnzf) => {
534 self.gas_charge(self.gas_costs().jnzf())?;
535 let (a, b, offset) = jnzf.unpack();
536 self.jump(
537 JumpArgs::new(JumpMode::RelativeForwards)
538 .with_condition(r!(a) != 0)
539 .to_address(r!(b))
540 .plus_fixed(offset.into()),
541 )?;
542 }
543
544 Instruction::JNZB(jnzb) => {
545 self.gas_charge(self.gas_costs().jnzb())?;
546 let (a, b, offset) = jnzb.unpack();
547 self.jump(
548 JumpArgs::new(JumpMode::RelativeBackwards)
549 .with_condition(r!(a) != 0)
550 .to_address(r!(b))
551 .plus_fixed(offset.into()),
552 )?;
553 }
554
555 Instruction::JNEF(jnef) => {
556 self.gas_charge(self.gas_costs().jnef())?;
557 let (a, b, c, offset) = jnef.unpack();
558 self.jump(
559 JumpArgs::new(JumpMode::RelativeForwards)
560 .with_condition(r!(a) != r!(b))
561 .to_address(r!(c))
562 .plus_fixed(offset.into()),
563 )?;
564 }
565
566 Instruction::JNEB(jneb) => {
567 self.gas_charge(self.gas_costs().jneb())?;
568 let (a, b, c, offset) = jneb.unpack();
569 self.jump(
570 JumpArgs::new(JumpMode::RelativeBackwards)
571 .with_condition(r!(a) != r!(b))
572 .to_address(r!(c))
573 .plus_fixed(offset.into()),
574 )?;
575 }
576
577 Instruction::RET(ret) => {
578 self.gas_charge(self.gas_costs().ret())?;
579 let a = ret.unpack();
580 let ra = r!(a);
581 self.ret(ra)?;
582 return Ok(ExecuteState::Return(ra))
583 }
584
585 Instruction::RETD(retd) => {
586 let (a, b) = retd.unpack();
587 let len = r!(b);
588 self.dependent_gas_charge(self.gas_costs().retd(), len)?;
589 return Ok(self.ret_data(r!(a), len).map(ExecuteState::ReturnData)?)
590 }
591
592 Instruction::RVRT(rvrt) => {
593 self.gas_charge(self.gas_costs().rvrt())?;
594 let a = rvrt.unpack();
595 let ra = r!(a);
596 self.revert(ra)?;
597 return Ok(ExecuteState::Revert(ra))
598 }
599
600 Instruction::SMO(smo) => {
601 let (a, b, c, d) = smo.unpack();
602 self.dependent_gas_charge(self.gas_costs().smo(), r!(c))?;
603 self.message_output(r!(a), r!(b), r!(c), r!(d))?;
604 }
605
606 Instruction::ALOC(aloc) => {
607 let a = aloc.unpack();
608 let number_of_bytes = r!(a);
609 self.dependent_gas_charge(self.gas_costs().aloc(), number_of_bytes)?;
610 self.malloc(number_of_bytes)?;
611 }
612
613 Instruction::CFEI(cfei) => {
614 let number_of_bytes = cfei.unpack().into();
615 self.dependent_gas_charge(self.gas_costs().cfei(), number_of_bytes)?;
616 self.stack_pointer_overflow(Word::overflowing_add, number_of_bytes)?;
617 }
618
619 Instruction::CFE(cfe) => {
620 let a = cfe.unpack();
621 let number_of_bytes = r!(a);
622 self.dependent_gas_charge(self.gas_costs().cfe(), number_of_bytes)?;
623 self.stack_pointer_overflow(Word::overflowing_add, number_of_bytes)?;
624 }
625
626 Instruction::CFSI(cfsi) => {
627 self.gas_charge(self.gas_costs().cfsi())?;
628 let imm = cfsi.unpack();
629 self.stack_pointer_overflow(Word::overflowing_sub, imm.into())?;
630 }
631
632 Instruction::CFS(cfs) => {
633 self.gas_charge(self.gas_costs().cfsi())?;
634 let a = cfs.unpack();
635 self.stack_pointer_overflow(Word::overflowing_sub, r!(a))?;
636 }
637
638 Instruction::PSHL(pshl) => {
639 self.gas_charge(self.gas_costs().pshl())?;
640 let bitmask = pshl.unpack();
641 self.push_selected_registers(ProgramRegistersSegment::Low, bitmask)?;
642 }
643
644 Instruction::PSHH(pshh) => {
645 self.gas_charge(self.gas_costs().pshh())?;
646 let bitmask = pshh.unpack();
647 self.push_selected_registers(ProgramRegistersSegment::High, bitmask)?;
648 }
649
650 Instruction::POPL(popl) => {
651 self.gas_charge(self.gas_costs().popl())?;
652 let bitmask = popl.unpack();
653 self.pop_selected_registers(ProgramRegistersSegment::Low, bitmask)?;
654 }
655
656 Instruction::POPH(poph) => {
657 self.gas_charge(self.gas_costs().poph())?;
658 let bitmask = poph.unpack();
659 self.pop_selected_registers(ProgramRegistersSegment::High, bitmask)?;
660 }
661
662 Instruction::LB(lb) => {
663 self.gas_charge(self.gas_costs().lb())?;
664 let (a, b, imm) = lb.unpack();
665 self.load_byte(a.into(), r!(b), imm.into())?;
666 }
667
668 Instruction::LW(lw) => {
669 self.gas_charge(self.gas_costs().lw())?;
670 let (a, b, imm) = lw.unpack();
671 self.load_word(a.into(), r!(b), imm)?;
672 }
673
674 Instruction::MCL(mcl) => {
675 let (a, b) = mcl.unpack();
676 let len = r!(b);
677 self.dependent_gas_charge(self.gas_costs().mcl(), len)?;
678 self.memclear(r!(a), len)?;
679 }
680
681 Instruction::MCLI(mcli) => {
682 let (a, imm) = mcli.unpack();
683 let len = Word::from(imm);
684 self.dependent_gas_charge(self.gas_costs().mcli(), len)?;
685 self.memclear(r!(a), len)?;
686 }
687
688 Instruction::MCP(mcp) => {
689 let (a, b, c) = mcp.unpack();
690 let len = r!(c);
691 self.dependent_gas_charge(self.gas_costs().mcp(), len)?;
692 self.memcopy(r!(a), r!(b), len)?;
693 }
694
695 Instruction::MCPI(mcpi) => {
696 let (a, b, imm) = mcpi.unpack();
697 let len = imm.into();
698 self.dependent_gas_charge(self.gas_costs().mcpi(), len)?;
699 self.memcopy(r!(a), r!(b), len)?;
700 }
701
702 Instruction::MEQ(meq) => {
703 let (a, b, c, d) = meq.unpack();
704 let len = r!(d);
705 self.dependent_gas_charge(self.gas_costs().meq(), len)?;
706 self.memeq(a.into(), r!(b), r!(c), len)?;
707 }
708
709 Instruction::SB(sb) => {
710 self.gas_charge(self.gas_costs().sb())?;
711 let (a, b, imm) = sb.unpack();
712 self.store_byte(r!(a), r!(b), imm.into())?;
713 }
714
715 Instruction::SW(sw) => {
716 self.gas_charge(self.gas_costs().sw())?;
717 let (a, b, imm) = sw.unpack();
718 self.store_word(r!(a), r!(b), imm)?;
719 }
720
721 Instruction::BAL(bal) => {
722 self.gas_charge(self.gas_costs().bal())?;
723 let (a, b, c) = bal.unpack();
724 self.contract_balance(a.into(), r!(b), r!(c))?;
725 }
726
727 Instruction::BHEI(bhei) => {
728 self.gas_charge(self.gas_costs().bhei())?;
729 let a = bhei.unpack();
730 self.block_height(a.into())?;
731 }
732
733 Instruction::BHSH(bhsh) => {
734 self.gas_charge(self.gas_costs().bhsh())?;
735 let (a, b) = bhsh.unpack();
736 self.block_hash(r!(a), r!(b))?;
737 }
738
739 Instruction::BURN(burn) => {
740 self.gas_charge(self.gas_costs().burn())?;
741 let (a, b) = burn.unpack();
742 self.burn(r!(a), r!(b))?;
743 }
744
745 Instruction::CALL(call) => {
746 let (a, b, c, d) = call.unpack();
748
749 self.prepare_call(a, b, c, d)?;
751 }
752
753 Instruction::CB(cb) => {
754 self.gas_charge(self.gas_costs().cb())?;
755 let a = cb.unpack();
756 self.block_proposer(r!(a))?;
757 }
758
759 Instruction::CCP(ccp) => {
760 let (a, b, c, d) = ccp.unpack();
761 self.code_copy(r!(a), r!(b), r!(c), r!(d))?;
762 }
763
764 Instruction::CROO(croo) => {
765 let (a, b) = croo.unpack();
766 self.code_root(r!(a), r!(b))?;
767 }
768
769 Instruction::CSIZ(csiz) => {
770 let (a, b) = csiz.unpack();
772 self.code_size(a.into(), r!(b))?;
773 }
774
775 Instruction::LDC(ldc) => {
776 let (a, b, c, mode) = ldc.unpack();
778 self.load_contract_code(r!(a), r!(b), r!(c), mode)?;
779 }
780
781 Instruction::LOG(log) => {
782 self.gas_charge(self.gas_costs().log())?;
783 let (a, b, c, d) = log.unpack();
784 self.log(r!(a), r!(b), r!(c), r!(d))?;
785 }
786
787 Instruction::LOGD(logd) => {
788 let (a, b, c, d) = logd.unpack();
789 self.dependent_gas_charge(self.gas_costs().logd(), r!(d))?;
790 self.log_data(r!(a), r!(b), r!(c), r!(d))?;
791 }
792
793 Instruction::MINT(mint) => {
794 self.gas_charge(self.gas_costs().mint())?;
795 let (a, b) = mint.unpack();
796 self.mint(r!(a), r!(b))?;
797 }
798
799 Instruction::SCWQ(scwq) => {
800 let (a, b, c) = scwq.unpack();
801 self.dependent_gas_charge(self.gas_costs().scwq(), r!(c))?;
802 self.state_clear_qword(r!(a), b.into(), r!(c))?;
803 }
804
805 Instruction::SRW(srw) => {
806 self.gas_charge(self.gas_costs().srw())?;
807 let (a, b, c) = srw.unpack();
808 self.state_read_word(a.into(), b.into(), r!(c))?;
809 }
810
811 Instruction::SRWQ(srwq) => {
812 let (a, b, c, d) = srwq.unpack();
813 self.dependent_gas_charge(self.gas_costs().srwq(), r!(d))?;
814 self.state_read_qword(r!(a), b.into(), r!(c), r!(d))?;
815 }
816
817 Instruction::SWW(sww) => {
818 self.gas_charge(self.gas_costs().sww())?;
819 let (a, b, c) = sww.unpack();
820 self.state_write_word(r!(a), b.into(), r!(c))?;
821 }
822
823 Instruction::SWWQ(swwq) => {
824 let (a, b, c, d) = swwq.unpack();
825 self.dependent_gas_charge(self.gas_costs().swwq(), r!(d))?;
826 self.state_write_qword(r!(a), b.into(), r!(c), r!(d))?;
827 }
828
829 Instruction::TIME(time) => {
830 self.gas_charge(self.gas_costs().time())?;
831 let (a, b) = time.unpack();
832 self.timestamp(a.into(), r!(b))?;
833 }
834
835 Instruction::ECK1(eck1) => {
836 self.gas_charge(self.gas_costs().eck1())?;
837 let (a, b, c) = eck1.unpack();
838 self.secp256k1_recover(r!(a), r!(b), r!(c))?;
839 }
840
841 Instruction::ECR1(ecr1) => {
842 self.gas_charge(self.gas_costs().ecr1())?;
843 let (a, b, c) = ecr1.unpack();
844 self.secp256r1_recover(r!(a), r!(b), r!(c))?;
845 }
846
847 Instruction::ED19(ed19) => {
848 let (a, b, c, len) = ed19.unpack();
849 let mut len = r!(len);
850
851 if len == 0 {
853 len = 32;
854 }
855
856 self.dependent_gas_charge(self.gas_costs().ed19(), len)?;
857 self.ed25519_verify(r!(a), r!(b), r!(c), len)?;
858 }
859
860 Instruction::K256(k256) => {
861 let (a, b, c) = k256.unpack();
862 let len = r!(c);
863 self.dependent_gas_charge(self.gas_costs().k256(), len)?;
864 self.keccak256(r!(a), r!(b), len)?;
865 }
866
867 Instruction::S256(s256) => {
868 let (a, b, c) = s256.unpack();
869 let len = r!(c);
870 self.dependent_gas_charge(self.gas_costs().s256(), len)?;
871 self.sha256(r!(a), r!(b), len)?;
872 }
873
874 Instruction::FLAG(flag) => {
875 self.gas_charge(self.gas_costs().flag())?;
876 let a = flag.unpack();
877 self.set_flag(r!(a))?;
878 }
879
880 Instruction::GM(gm) => {
881 self.gas_charge(self.gas_costs().gm())?;
882 let (a, imm) = gm.unpack();
883 self.metadata(a.into(), imm.into())?;
884 }
885
886 Instruction::GTF(gtf) => {
887 self.gas_charge(self.gas_costs().gtf())?;
888 let (a, b, imm) = gtf.unpack();
889 self.get_transaction_field(a.into(), r!(b), imm.into())?;
890 }
891
892 Instruction::TR(tr) => {
893 self.gas_charge(self.gas_costs().tr())?;
894 let (a, b, c) = tr.unpack();
895 self.transfer(r!(a), r!(b), r!(c))?;
896 }
897
898 Instruction::TRO(tro) => {
899 self.gas_charge(self.gas_costs().tro())?;
900 let (a, b, c, d) = tro.unpack();
901 self.transfer_output(r!(a), r!(b), r!(c), r!(d))?;
902 }
903
904 Instruction::ECAL(ecal) => {
905 let (a, b, c, d) = ecal.unpack();
906 self.external_call(a, b, c, d)?;
907 }
908
909 Instruction::BSIZ(bsiz) => {
910 let (a, b) = bsiz.unpack();
912 self.blob_size(a.into(), r!(b))?;
913 }
914
915 Instruction::BLDD(bldd) => {
916 let (a, b, c, d) = bldd.unpack();
918 self.blob_load_data(r!(a), r!(b), r!(c), r!(d))?;
919 }
920
921 Instruction::ECOP(ecop) => {
922 self.gas_charge(self.gas_costs().ecop().map_err(PanicReason::from)?)?;
923 let (a, b, c, d) = ecop.unpack();
924 self.ec_operation(r!(a), r!(b), r!(c), r!(d))?;
925 }
926
927 Instruction::EPAR(epar) => {
928 let (a, b, c, d) = epar.unpack();
929 let len = r!(c);
930 self.dependent_gas_charge(
931 self.gas_costs().epar().map_err(PanicReason::from)?,
932 len,
933 )?;
934 self.ec_pairing(a.into(), r!(b), len, r!(d))?;
935 }
936 }
937
938 Ok(ExecuteState::Proceed)
939 }
940}
941
942fn checked_nth_root(target: u64, nth_root: u64) -> Option<u64> {
946 if nth_root == 0 {
947 return None
949 }
950
951 if nth_root == 1 || target <= 1 {
952 return Some(target)
954 }
955
956 if nth_root >= target || nth_root > 64 {
957 return Some(1)
960 }
961
962 let nth_root = u32::try_from(nth_root).expect("Never loses bits, checked above");
963
964 #[cfg(feature = "std")]
968 let powf = f64::powf;
969 #[cfg(not(feature = "std"))]
970 let powf = libm::pow;
971
972 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
973 let guess = powf(target as f64, (nth_root as f64).recip()) as u64;
974
975 debug_assert!(guess != 0, "This should never occur for {{target, n}} > 1");
976
977 let is_nth_power_below_target = |v: u64| match v.checked_pow(nth_root) {
980 Some(pow) => target < pow,
981 None => true, };
983
984 if is_nth_power_below_target(guess) {
988 return Some(guess.saturating_sub(1))
989 }
990
991 let guess_plus_one = guess.checked_add(1).expect(
993 "Guess cannot be u64::MAX, as we have taken a root > 2 of a value to get it",
994 );
995 if is_nth_power_below_target(guess_plus_one) {
996 return Some(guess)
997 }
998
999 Some(guess_plus_one)
1001}
1002
1003#[cfg(test)]
1004mod tests;