openvm_circuit/arch/execution_mode/
metered_cost.rs1use getset::WithSetters;
2use openvm_instructions::riscv::RV32_IMM_AS;
3
4use crate::{
5 arch::{
6 execution_mode::metered::segment_ctx::DEFAULT_MAX_MEMORY as DEFAULT_SEGMENT_MAX_MEMORY,
7 ExecutionCtxTrait, MeteredExecutionCtxTrait, VmExecState,
8 },
9 system::memory::online::GuestMemory,
10};
11
12const DEFAULT_MAX_SEGMENTS: u64 = 100;
13pub const DEFAULT_MAX_COST: u64 = DEFAULT_MAX_SEGMENTS * DEFAULT_SEGMENT_MAX_MEMORY as u64;
14
15#[derive(Clone, Debug, WithSetters)]
16pub struct MeteredCostCtx {
17 pub widths: Vec<usize>,
18 #[getset(set_with = "pub")]
19 pub max_execution_cost: u64,
20 pub cost: u64,
22 pub instret: u64,
24}
25
26impl MeteredCostCtx {
27 pub fn new(widths: Vec<usize>) -> Self {
28 Self {
29 widths,
30 max_execution_cost: DEFAULT_MAX_COST,
31 cost: 0,
32 instret: 0,
33 }
34 }
35
36 #[cold]
37 fn panic_cost_exceeded(&self) -> ! {
38 panic!(
39 "Execution cost {} exceeded maximum allowed cost of {}",
40 self.cost,
41 2 * DEFAULT_MAX_COST
42 );
43 }
44}
45
46impl ExecutionCtxTrait for MeteredCostCtx {
47 #[inline(always)]
48 fn on_memory_operation(&mut self, address_space: u32, _ptr: u32, size: u32) {
49 debug_assert!(
50 address_space != RV32_IMM_AS,
51 "address space must not be immediate"
52 );
53 debug_assert!(size > 0, "size must be greater than 0, got {size}");
54 debug_assert!(
55 size.is_power_of_two(),
56 "size must be a power of 2, got {size}"
57 );
58 if self.cost > 2 * std::cmp::max(self.max_execution_cost, DEFAULT_MAX_COST) {
60 self.panic_cost_exceeded();
61 }
62 }
63
64 #[inline(always)]
65 fn should_suspend<F>(exec_state: &mut VmExecState<F, GuestMemory, Self>) -> bool {
66 if exec_state.ctx.cost > exec_state.ctx.max_execution_cost {
67 true
68 } else {
69 exec_state.ctx.instret += 1;
70 false
71 }
72 }
73}
74
75impl MeteredExecutionCtxTrait for MeteredCostCtx {
76 #[inline(always)]
77 fn on_height_change(&mut self, chip_idx: usize, height_delta: u32) {
78 debug_assert!(chip_idx < self.widths.len(), "chip_idx out of bounds");
79 let width = unsafe { *self.widths.get_unchecked(chip_idx) };
81 self.cost += (height_delta as u64) * (width as u64);
82 }
83}