1mod dimension;
2mod limits;
3mod model;
4mod util;
5mod wasmi_helper;
6
7pub(crate) use limits::DepthLimiter;
8pub use limits::{DEFAULT_HOST_DEPTH_LIMIT, DEFAULT_XDR_RW_LIMITS};
9pub use model::{MeteredCostComponent, ScaledU64};
10pub(crate) use wasmi_helper::{get_wasmi_config, load_calibrated_fuel_costs};
11
12use std::{
13 cell::{RefCell, RefMut},
14 fmt::{Debug, Display},
15 rc::Rc,
16};
17
18use crate::{
19 host::error::TryBorrowOrErr,
20 xdr::{ContractCostParams, ContractCostType, ScErrorCode, ScErrorType},
21 Error, Host, HostError,
22};
23
24use dimension::{BudgetDimension, IsCpu, IsShadowMode};
25
26#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord)]
27pub struct CostTracker {
28 pub iterations: u64,
29 pub inputs: Option<u64>,
30 pub cpu: u64,
31 pub mem: u64,
32}
33
34#[derive(Clone)]
35struct BudgetTracker {
36 cost_trackers: [CostTracker; ContractCostType::variants().len()],
38 meter_count: u32,
40 #[cfg(any(test, feature = "testutils", feature = "bench"))]
41 wasm_memory: u64,
42 time_tracker: [u64; ContractCostType::variants().len()],
44}
45
46impl Default for BudgetTracker {
47 fn default() -> Self {
48 let mut mt = Self {
49 cost_trackers: [CostTracker::default(); ContractCostType::variants().len()],
50 meter_count: 0,
51 #[cfg(any(test, feature = "testutils", feature = "bench"))]
52 wasm_memory: 0,
53 time_tracker: [0; ContractCostType::variants().len()],
54 };
55 for (ct, tracker) in ContractCostType::variants()
56 .iter()
57 .zip(mt.cost_trackers.iter_mut())
58 {
59 let mut init_input = || tracker.inputs = Some(0);
64 match ct {
65 ContractCostType::WasmInsnExec => (),
66 ContractCostType::MemAlloc => init_input(), ContractCostType::MemCpy => init_input(), ContractCostType::MemCmp => init_input(), ContractCostType::DispatchHostFunction => (),
70 ContractCostType::VisitObject => (),
71 ContractCostType::ValSer => init_input(), ContractCostType::ValDeser => init_input(), ContractCostType::ComputeSha256Hash => init_input(), ContractCostType::ComputeEd25519PubKey => (),
82 ContractCostType::VerifyEd25519Sig => init_input(), ContractCostType::VmInstantiation => init_input(), ContractCostType::VmCachedInstantiation => init_input(), ContractCostType::InvokeVmFunction => (),
86 ContractCostType::ComputeKeccak256Hash => init_input(), ContractCostType::DecodeEcdsaCurve256Sig => (),
88 ContractCostType::RecoverEcdsaSecp256k1Key => (),
89 ContractCostType::Int256AddSub => (),
90 ContractCostType::Int256Mul => (),
91 ContractCostType::Int256Div => (),
92 ContractCostType::Int256Pow => (),
93 ContractCostType::Int256Shift => (),
94 ContractCostType::ChaCha20DrawBytes => init_input(), ContractCostType::ParseWasmInstructions => init_input(),
97 ContractCostType::ParseWasmFunctions => init_input(),
98 ContractCostType::ParseWasmGlobals => init_input(),
99 ContractCostType::ParseWasmTableEntries => init_input(),
100 ContractCostType::ParseWasmTypes => init_input(),
101 ContractCostType::ParseWasmDataSegments => init_input(),
102 ContractCostType::ParseWasmElemSegments => init_input(),
103 ContractCostType::ParseWasmImports => init_input(),
104 ContractCostType::ParseWasmExports => init_input(),
105 ContractCostType::ParseWasmDataSegmentBytes => init_input(),
106 ContractCostType::InstantiateWasmInstructions => (),
107 ContractCostType::InstantiateWasmFunctions => init_input(),
108 ContractCostType::InstantiateWasmGlobals => init_input(),
109 ContractCostType::InstantiateWasmTableEntries => init_input(),
110 ContractCostType::InstantiateWasmTypes => (),
111 ContractCostType::InstantiateWasmDataSegments => init_input(),
112 ContractCostType::InstantiateWasmElemSegments => init_input(),
113 ContractCostType::InstantiateWasmImports => init_input(),
114 ContractCostType::InstantiateWasmExports => init_input(),
115 ContractCostType::InstantiateWasmDataSegmentBytes => init_input(),
116 ContractCostType::Sec1DecodePointUncompressed => (),
117 ContractCostType::VerifyEcdsaSecp256r1Sig => (),
118 ContractCostType::Bls12381EncodeFp => (),
119 ContractCostType::Bls12381DecodeFp => (),
120 ContractCostType::Bls12381G1CheckPointOnCurve => (),
121 ContractCostType::Bls12381G1CheckPointInSubgroup => (),
122 ContractCostType::Bls12381G2CheckPointOnCurve => (),
123 ContractCostType::Bls12381G2CheckPointInSubgroup => (),
124 ContractCostType::Bls12381G1ProjectiveToAffine => (),
125 ContractCostType::Bls12381G2ProjectiveToAffine => (),
126 ContractCostType::Bls12381G1Add => (),
127 ContractCostType::Bls12381G1Mul => (),
128 ContractCostType::Bls12381G1Msm => init_input(), ContractCostType::Bls12381MapFpToG1 => (),
130 ContractCostType::Bls12381HashToG1 => init_input(),
131 ContractCostType::Bls12381G2Add => (),
132 ContractCostType::Bls12381G2Mul => (),
133 ContractCostType::Bls12381G2Msm => init_input(), ContractCostType::Bls12381MapFp2ToG2 => (),
135 ContractCostType::Bls12381HashToG2 => init_input(),
136 ContractCostType::Bls12381Pairing => init_input(), ContractCostType::Bls12381FrFromU256 => (),
138 ContractCostType::Bls12381FrToU256 => (),
139 ContractCostType::Bls12381FrAddSub => (),
140 ContractCostType::Bls12381FrMul => (),
141 ContractCostType::Bls12381FrPow => init_input(), ContractCostType::Bls12381FrInv => (),
143 ContractCostType::Bn254EncodeFp => (),
144 ContractCostType::Bn254DecodeFp => (),
145 ContractCostType::Bn254G1CheckPointOnCurve => (),
146 ContractCostType::Bn254G2CheckPointOnCurve => (),
147 ContractCostType::Bn254G2CheckPointInSubgroup => (),
148 ContractCostType::Bn254G1ProjectiveToAffine => (),
149 ContractCostType::Bn254G1Add => (),
150 ContractCostType::Bn254G1Mul => (),
151 ContractCostType::Bn254Pairing => init_input(),
152 ContractCostType::Bn254FrFromU256 => (),
153 ContractCostType::Bn254FrToU256 => (),
154 ContractCostType::Bn254FrAddSub => (),
155 ContractCostType::Bn254FrMul => (),
156 ContractCostType::Bn254FrPow => init_input(), ContractCostType::Bn254FrInv => (),
158 }
159 }
160 mt
161 }
162}
163
164impl BudgetTracker {
165 #[cfg(any(test, feature = "testutils", feature = "bench"))]
166 fn reset(&mut self) {
167 self.meter_count = 0;
168 for tracker in &mut self.cost_trackers {
169 tracker.iterations = 0;
170 tracker.inputs = tracker.inputs.map(|_| 0);
171 tracker.cpu = 0;
172 tracker.mem = 0;
173 }
174 self.wasm_memory = 0;
175 }
176
177 fn track_time(&mut self, ty: ContractCostType, duration: u64) -> Result<(), HostError> {
178 let t = self.time_tracker.get_mut(ty as usize).ok_or_else(|| {
179 HostError::from(Error::from_type_and_code(
180 ScErrorType::Budget,
181 ScErrorCode::InternalError,
182 ))
183 })?;
184 *t += duration;
185 Ok(())
186 }
187
188 fn get_time(&self, ty: ContractCostType) -> Result<u64, HostError> {
189 self.time_tracker
190 .get(ty as usize)
191 .map(|t| *t)
192 .ok_or_else(|| (ScErrorType::Budget, ScErrorCode::InternalError).into())
193 }
194}
195
196#[derive(Clone)]
197pub(crate) struct BudgetImpl {
198 cpu_insns: BudgetDimension,
199 mem_bytes: BudgetDimension,
200 tracker: BudgetTracker,
202 is_in_shadow_mode: bool,
203 fuel_costs: wasmi::FuelCosts,
204 depth_limit: u32,
205}
206
207impl BudgetImpl {
208 fn try_from_configs(
210 cpu_limit: u64,
211 mem_limit: u64,
212 cpu_cost_params: ContractCostParams,
213 mem_cost_params: ContractCostParams,
214 ) -> Result<Self, HostError> {
215 Ok(Self {
216 cpu_insns: BudgetDimension::try_from_config(cpu_cost_params, cpu_limit)?,
217 mem_bytes: BudgetDimension::try_from_config(mem_cost_params, mem_limit)?,
218 tracker: BudgetTracker::default(),
219 is_in_shadow_mode: false,
220 fuel_costs: load_calibrated_fuel_costs(),
221 depth_limit: DEFAULT_HOST_DEPTH_LIMIT,
222 })
223 }
224
225 pub(crate) fn get_memory_cost(
226 &self,
227 ty: ContractCostType,
228 iterations: u64,
229 input: Option<u64>,
230 ) -> Result<u64, HostError> {
231 self.mem_bytes.get_cost(ty, iterations, input)
232 }
233
234 pub fn charge(
235 &mut self,
236 ty: ContractCostType,
237 iterations: u64,
238 input: Option<u64>,
239 ) -> Result<(), HostError> {
240 let tracker = self
241 .tracker
242 .cost_trackers
243 .get_mut(ty as usize)
244 .ok_or_else(|| HostError::from((ScErrorType::Budget, ScErrorCode::InternalError)))?;
245
246 if !self.is_in_shadow_mode {
247 self.tracker.meter_count = self.tracker.meter_count.saturating_add(1);
249 tracker.iterations = tracker.iterations.saturating_add(iterations);
250 match (&mut tracker.inputs, input) {
251 (None, None) => (),
252 (Some(t), Some(i)) => *t = t.saturating_add(i.saturating_mul(iterations)),
253 _ => return Err((ScErrorType::Budget, ScErrorCode::InternalError).into()),
255 };
256 }
257
258 let cpu_charged = self.cpu_insns.charge(
259 ty,
260 iterations,
261 input,
262 IsCpu(true),
263 IsShadowMode(self.is_in_shadow_mode),
264 )?;
265 if !self.is_in_shadow_mode {
266 tracker.cpu = tracker.cpu.saturating_add(cpu_charged);
267 }
268 self.cpu_insns
269 .check_budget_limit(IsShadowMode(self.is_in_shadow_mode))?;
270
271 let mem_charged = self.mem_bytes.charge(
272 ty,
273 iterations,
274 input,
275 IsCpu(false),
276 IsShadowMode(self.is_in_shadow_mode),
277 )?;
278 if !self.is_in_shadow_mode {
279 tracker.mem = tracker.mem.saturating_add(mem_charged);
280 }
281 self.mem_bytes
282 .check_budget_limit(IsShadowMode(self.is_in_shadow_mode))
283 }
284
285 fn get_wasmi_fuel_remaining(&self) -> Result<u64, HostError> {
286 let cpu_remaining = self.cpu_insns.get_remaining();
287 let cost_model = self
288 .cpu_insns
289 .get_cost_model(ContractCostType::WasmInsnExec)?;
290 let cpu_per_fuel = cost_model.const_term.max(1);
291 Ok(cpu_remaining.checked_div(cpu_per_fuel).unwrap_or(0))
302 }
303}
304
305impl Default for BudgetImpl {
308 fn default() -> Self {
309 let mut b = Self {
310 cpu_insns: BudgetDimension::default(),
311 mem_bytes: BudgetDimension::default(),
312 tracker: Default::default(),
313 is_in_shadow_mode: false,
314 fuel_costs: load_calibrated_fuel_costs(),
315 depth_limit: DEFAULT_HOST_DEPTH_LIMIT,
316 };
317
318 for ct in ContractCostType::variants() {
319 let Ok(cpu) = b.cpu_insns.get_cost_model_mut(ct) else {
321 continue;
322 };
323 match ct {
324 ContractCostType::WasmInsnExec => {
329 cpu.const_term = 4;
330 cpu.lin_term = ScaledU64(0);
331 }
332 ContractCostType::MemAlloc => {
336 cpu.const_term = 434;
337 cpu.lin_term = ScaledU64::from_unscaled_u64(1).safe_div(8);
338 }
339 ContractCostType::MemCpy => {
353 cpu.const_term = 42;
354 cpu.lin_term = ScaledU64::from_unscaled_u64(1).safe_div(8);
355 }
356 ContractCostType::MemCmp => {
357 cpu.const_term = 44;
358 cpu.lin_term = ScaledU64::from_unscaled_u64(1).safe_div(8);
359 }
360 ContractCostType::DispatchHostFunction => {
361 cpu.const_term = 310;
362 cpu.lin_term = ScaledU64(0);
363 }
364 ContractCostType::VisitObject => {
365 cpu.const_term = 61;
366 cpu.lin_term = ScaledU64(0);
367 }
368 ContractCostType::ValSer => {
369 cpu.const_term = 230;
370 cpu.lin_term = ScaledU64(29);
371 }
372 ContractCostType::ValDeser => {
373 cpu.const_term = 59052;
374 cpu.lin_term = ScaledU64(4001);
375 }
376 ContractCostType::ComputeSha256Hash => {
377 cpu.const_term = 3738;
378 cpu.lin_term = ScaledU64(7012);
379 }
380 ContractCostType::ComputeEd25519PubKey => {
381 cpu.const_term = 40253;
382 cpu.lin_term = ScaledU64(0);
383 }
384 ContractCostType::VerifyEd25519Sig => {
385 cpu.const_term = 377524;
386 cpu.lin_term = ScaledU64(4068);
387 }
388 ContractCostType::VmInstantiation => {
389 cpu.const_term = 451626;
390 cpu.lin_term = ScaledU64(45405);
391 }
392 ContractCostType::VmCachedInstantiation => {
393 cpu.const_term = 41142;
394 cpu.lin_term = ScaledU64(634);
395 }
396 ContractCostType::InvokeVmFunction => {
397 cpu.const_term = 1948;
398 cpu.lin_term = ScaledU64(0);
399 }
400 ContractCostType::ComputeKeccak256Hash => {
401 cpu.const_term = 3766;
402 cpu.lin_term = ScaledU64(5969);
403 }
404 ContractCostType::DecodeEcdsaCurve256Sig => {
405 cpu.const_term = 710;
406 cpu.lin_term = ScaledU64(0);
407 }
408 ContractCostType::RecoverEcdsaSecp256k1Key => {
409 cpu.const_term = 2315295;
410 cpu.lin_term = ScaledU64(0);
411 }
412 ContractCostType::Int256AddSub => {
413 cpu.const_term = 4404;
414 cpu.lin_term = ScaledU64(0);
415 }
416 ContractCostType::Int256Mul => {
417 cpu.const_term = 4947;
418 cpu.lin_term = ScaledU64(0);
419 }
420 ContractCostType::Int256Div => {
421 cpu.const_term = 4911;
422 cpu.lin_term = ScaledU64(0);
423 }
424 ContractCostType::Int256Pow => {
425 cpu.const_term = 4286;
426 cpu.lin_term = ScaledU64(0);
427 }
428 ContractCostType::Int256Shift => {
429 cpu.const_term = 913;
430 cpu.lin_term = ScaledU64(0);
431 }
432 ContractCostType::ChaCha20DrawBytes => {
433 cpu.const_term = 1058;
434 cpu.lin_term = ScaledU64(501);
435 }
436
437 ContractCostType::ParseWasmInstructions => {
438 cpu.const_term = 73077;
439 cpu.lin_term = ScaledU64(25410);
440 }
441 ContractCostType::ParseWasmFunctions => {
442 cpu.const_term = 0;
443 cpu.lin_term = ScaledU64(540752);
444 }
445 ContractCostType::ParseWasmGlobals => {
446 cpu.const_term = 0;
447 cpu.lin_term = ScaledU64(176363);
448 }
449 ContractCostType::ParseWasmTableEntries => {
450 cpu.const_term = 0;
451 cpu.lin_term = ScaledU64(29989);
452 }
453 ContractCostType::ParseWasmTypes => {
454 cpu.const_term = 0;
455 cpu.lin_term = ScaledU64(1061449);
456 }
457 ContractCostType::ParseWasmDataSegments => {
458 cpu.const_term = 0;
459 cpu.lin_term = ScaledU64(237336);
460 }
461 ContractCostType::ParseWasmElemSegments => {
462 cpu.const_term = 0;
463 cpu.lin_term = ScaledU64(328476);
464 }
465 ContractCostType::ParseWasmImports => {
466 cpu.const_term = 0;
467 cpu.lin_term = ScaledU64(701845);
468 }
469 ContractCostType::ParseWasmExports => {
470 cpu.const_term = 0;
471 cpu.lin_term = ScaledU64(429383);
472 }
473 ContractCostType::ParseWasmDataSegmentBytes => {
474 cpu.const_term = 0;
475 cpu.lin_term = ScaledU64(28);
476 }
477 ContractCostType::InstantiateWasmInstructions => {
478 cpu.const_term = 43030;
479 cpu.lin_term = ScaledU64(0);
480 }
481 ContractCostType::InstantiateWasmFunctions => {
482 cpu.const_term = 0;
483 cpu.lin_term = ScaledU64(7556);
484 }
485 ContractCostType::InstantiateWasmGlobals => {
486 cpu.const_term = 0;
487 cpu.lin_term = ScaledU64(10711);
488 }
489 ContractCostType::InstantiateWasmTableEntries => {
490 cpu.const_term = 0;
491 cpu.lin_term = ScaledU64(3300);
492 }
493 ContractCostType::InstantiateWasmTypes => {
494 cpu.const_term = 0;
495 cpu.lin_term = ScaledU64(0);
496 }
497 ContractCostType::InstantiateWasmDataSegments => {
498 cpu.const_term = 0;
499 cpu.lin_term = ScaledU64(23038);
500 }
501 ContractCostType::InstantiateWasmElemSegments => {
502 cpu.const_term = 0;
503 cpu.lin_term = ScaledU64(42488);
504 }
505 ContractCostType::InstantiateWasmImports => {
506 cpu.const_term = 0;
507 cpu.lin_term = ScaledU64(828974);
508 }
509 ContractCostType::InstantiateWasmExports => {
510 cpu.const_term = 0;
511 cpu.lin_term = ScaledU64(297100);
512 }
513 ContractCostType::InstantiateWasmDataSegmentBytes => {
514 cpu.const_term = 0;
515 cpu.lin_term = ScaledU64(14);
516 }
517 ContractCostType::Sec1DecodePointUncompressed => {
518 cpu.const_term = 1882;
519 cpu.lin_term = ScaledU64(0);
520 }
521 ContractCostType::VerifyEcdsaSecp256r1Sig => {
522 cpu.const_term = 3000906;
523 cpu.lin_term = ScaledU64(0);
524 }
525 ContractCostType::Bls12381EncodeFp => {
526 cpu.const_term = 661;
527 cpu.lin_term = ScaledU64(0);
528 }
529 ContractCostType::Bls12381DecodeFp => {
530 cpu.const_term = 985;
531 cpu.lin_term = ScaledU64(0);
532 }
533 ContractCostType::Bls12381G1CheckPointOnCurve => {
534 cpu.const_term = 1934;
535 cpu.lin_term = ScaledU64(0);
536 }
537 ContractCostType::Bls12381G1CheckPointInSubgroup => {
538 cpu.const_term = 730510;
539 cpu.lin_term = ScaledU64(0);
540 }
541 ContractCostType::Bls12381G2CheckPointOnCurve => {
542 cpu.const_term = 5921;
543 cpu.lin_term = ScaledU64(0);
544 }
545 ContractCostType::Bls12381G2CheckPointInSubgroup => {
546 cpu.const_term = 1057822;
547 cpu.lin_term = ScaledU64(0);
548 }
549 ContractCostType::Bls12381G1ProjectiveToAffine => {
550 cpu.const_term = 92642;
551 cpu.lin_term = ScaledU64(0);
552 }
553 ContractCostType::Bls12381G2ProjectiveToAffine => {
554 cpu.const_term = 100742;
555 cpu.lin_term = ScaledU64(0);
556 }
557 ContractCostType::Bls12381G1Add => {
558 cpu.const_term = 7689;
559 cpu.lin_term = ScaledU64(0);
560 }
561 ContractCostType::Bls12381G1Mul => {
562 cpu.const_term = 2458985;
563 cpu.lin_term = ScaledU64(0);
564 }
565 ContractCostType::Bls12381G1Msm => {
566 cpu.const_term = 2426722;
567 cpu.lin_term = ScaledU64(96397671);
568 }
569 ContractCostType::Bls12381MapFpToG1 => {
570 cpu.const_term = 1541554;
571 cpu.lin_term = ScaledU64(0);
572 }
573 ContractCostType::Bls12381HashToG1 => {
574 cpu.const_term = 3211191;
575 cpu.lin_term = ScaledU64(6713);
576 }
577 ContractCostType::Bls12381G2Add => {
578 cpu.const_term = 25207;
579 cpu.lin_term = ScaledU64(0);
580 }
581 ContractCostType::Bls12381G2Mul => {
582 cpu.const_term = 7873219;
583 cpu.lin_term = ScaledU64(0);
584 }
585 ContractCostType::Bls12381G2Msm => {
586 cpu.const_term = 8035968;
587 cpu.lin_term = ScaledU64(309667335);
588 }
589 ContractCostType::Bls12381MapFp2ToG2 => {
590 cpu.const_term = 2420202;
591 cpu.lin_term = ScaledU64(0);
592 }
593 ContractCostType::Bls12381HashToG2 => {
594 cpu.const_term = 7050564;
595 cpu.lin_term = ScaledU64(6797);
596 }
597 ContractCostType::Bls12381Pairing => {
598 cpu.const_term = 10558948;
599 cpu.lin_term = ScaledU64(632860943);
600 }
601 ContractCostType::Bls12381FrFromU256 => {
602 cpu.const_term = 1994;
603 cpu.lin_term = ScaledU64(0);
604 }
605 ContractCostType::Bls12381FrToU256 => {
606 cpu.const_term = 1155;
607 cpu.lin_term = ScaledU64(0);
608 }
609 ContractCostType::Bls12381FrAddSub => {
610 cpu.const_term = 74;
611 cpu.lin_term = ScaledU64(0);
612 }
613 ContractCostType::Bls12381FrMul => {
614 cpu.const_term = 332;
615 cpu.lin_term = ScaledU64(0);
616 }
617 ContractCostType::Bls12381FrPow => {
618 cpu.const_term = 691;
619 cpu.lin_term = ScaledU64(74558);
620 }
621 ContractCostType::Bls12381FrInv => {
622 cpu.const_term = 35421;
623 cpu.lin_term = ScaledU64(0);
624 }
625 ContractCostType::Bn254EncodeFp => {
626 cpu.const_term = 344;
627 cpu.lin_term = ScaledU64(0);
628 }
629 ContractCostType::Bn254DecodeFp => {
630 cpu.const_term = 476;
631 cpu.lin_term = ScaledU64(0);
632 }
633 ContractCostType::Bn254G1CheckPointOnCurve => {
634 cpu.const_term = 904;
635 cpu.lin_term = ScaledU64(0);
636 }
637 ContractCostType::Bn254G2CheckPointOnCurve => {
638 cpu.const_term = 2811;
639 cpu.lin_term = ScaledU64(0);
640 }
641 ContractCostType::Bn254G2CheckPointInSubgroup => {
642 cpu.const_term = 2937755;
643 cpu.lin_term = ScaledU64(0);
644 }
645 ContractCostType::Bn254G1ProjectiveToAffine => {
646 cpu.const_term = 61;
647 cpu.lin_term = ScaledU64(0);
648 }
649 ContractCostType::Bn254G1Add => {
650 cpu.const_term = 3623;
651 cpu.lin_term = ScaledU64(0);
652 }
653 ContractCostType::Bn254G1Mul => {
654 cpu.const_term = 1150435;
655 cpu.lin_term = ScaledU64(0);
656 }
657 ContractCostType::Bn254Pairing => {
658 cpu.const_term = 5263916;
659 cpu.lin_term = ScaledU64(392472814);
660 }
661 ContractCostType::Bn254FrFromU256 => {
662 cpu.const_term = 2052;
663 cpu.lin_term = ScaledU64(0);
664 }
665 ContractCostType::Bn254FrToU256 => {
666 cpu.const_term = 1133;
667 cpu.lin_term = ScaledU64(0);
668 }
669 ContractCostType::Bn254FrAddSub => {
670 cpu.const_term = 74;
671 cpu.lin_term = ScaledU64(0);
672 }
673 ContractCostType::Bn254FrMul => {
674 cpu.const_term = 332;
675 cpu.lin_term = ScaledU64(0);
676 }
677 ContractCostType::Bn254FrPow => {
678 cpu.const_term = 755;
679 cpu.lin_term = ScaledU64(68930);
680 }
681 ContractCostType::Bn254FrInv => {
682 cpu.const_term = 33151;
683 cpu.lin_term = ScaledU64(0);
684 }
685 }
686
687 let Ok(mem) = b.mem_bytes.get_cost_model_mut(ct) else {
689 continue;
690 };
691 match ct {
692 ContractCostType::WasmInsnExec => {
695 mem.const_term = 0;
696 mem.lin_term = ScaledU64(0);
697 }
698 ContractCostType::MemAlloc => {
699 mem.const_term = 16;
700 mem.lin_term = ScaledU64::from_unscaled_u64(1);
701 }
702 ContractCostType::MemCpy => {
703 mem.const_term = 0;
704 mem.lin_term = ScaledU64(0);
705 }
706 ContractCostType::MemCmp => {
707 mem.const_term = 0;
708 mem.lin_term = ScaledU64(0);
709 }
710 ContractCostType::DispatchHostFunction => {
711 mem.const_term = 0;
712 mem.lin_term = ScaledU64(0);
713 }
714 ContractCostType::VisitObject => {
715 mem.const_term = 0;
716 mem.lin_term = ScaledU64(0);
717 }
718 ContractCostType::ValSer => {
721 mem.const_term = 242;
722 mem.lin_term = ScaledU64::from_unscaled_u64(3);
723 }
724 ContractCostType::ValDeser => {
725 mem.const_term = 0;
726 mem.lin_term = ScaledU64::from_unscaled_u64(3);
727 }
728 ContractCostType::ComputeSha256Hash => {
729 mem.const_term = 0;
730 mem.lin_term = ScaledU64(0);
731 }
732 ContractCostType::ComputeEd25519PubKey => {
733 mem.const_term = 0;
734 mem.lin_term = ScaledU64(0);
735 }
736 ContractCostType::VerifyEd25519Sig => {
737 mem.const_term = 0;
738 mem.lin_term = ScaledU64(0);
739 }
740 ContractCostType::VmInstantiation => {
741 mem.const_term = 130065;
742 mem.lin_term = ScaledU64(5064);
743 }
744 ContractCostType::VmCachedInstantiation => {
745 mem.const_term = 69472;
746 mem.lin_term = ScaledU64(1217);
747 }
748 ContractCostType::InvokeVmFunction => {
749 mem.const_term = 14;
750 mem.lin_term = ScaledU64(0);
751 }
752 ContractCostType::ComputeKeccak256Hash => {
753 mem.const_term = 0;
754 mem.lin_term = ScaledU64(0);
755 }
756 ContractCostType::DecodeEcdsaCurve256Sig => {
757 mem.const_term = 0;
758 mem.lin_term = ScaledU64(0);
759 }
760 ContractCostType::RecoverEcdsaSecp256k1Key => {
761 mem.const_term = 181;
762 mem.lin_term = ScaledU64(0);
763 }
764 ContractCostType::Int256AddSub => {
765 mem.const_term = 99;
766 mem.lin_term = ScaledU64(0);
767 }
768 ContractCostType::Int256Mul => {
769 mem.const_term = 99;
770 mem.lin_term = ScaledU64(0);
771 }
772 ContractCostType::Int256Div => {
773 mem.const_term = 99;
774 mem.lin_term = ScaledU64(0);
775 }
776 ContractCostType::Int256Pow => {
777 mem.const_term = 99;
778 mem.lin_term = ScaledU64(0);
779 }
780 ContractCostType::Int256Shift => {
781 mem.const_term = 99;
782 mem.lin_term = ScaledU64(0);
783 }
784 ContractCostType::ChaCha20DrawBytes => {
785 mem.const_term = 0;
786 mem.lin_term = ScaledU64(0);
787 }
788
789 ContractCostType::ParseWasmInstructions => {
790 mem.const_term = 17564;
791 mem.lin_term = ScaledU64(6457);
792 }
793 ContractCostType::ParseWasmFunctions => {
794 mem.const_term = 0;
795 mem.lin_term = ScaledU64(47464);
796 }
797 ContractCostType::ParseWasmGlobals => {
798 mem.const_term = 0;
799 mem.lin_term = ScaledU64(13420);
800 }
801 ContractCostType::ParseWasmTableEntries => {
802 mem.const_term = 0;
803 mem.lin_term = ScaledU64(6285);
804 }
805 ContractCostType::ParseWasmTypes => {
806 mem.const_term = 0;
807 mem.lin_term = ScaledU64(64670);
808 }
809 ContractCostType::ParseWasmDataSegments => {
810 mem.const_term = 0;
811 mem.lin_term = ScaledU64(29074);
812 }
813 ContractCostType::ParseWasmElemSegments => {
814 mem.const_term = 0;
815 mem.lin_term = ScaledU64(48095);
816 }
817 ContractCostType::ParseWasmImports => {
818 mem.const_term = 0;
819 mem.lin_term = ScaledU64(103229);
820 }
821 ContractCostType::ParseWasmExports => {
822 mem.const_term = 0;
823 mem.lin_term = ScaledU64(36394);
824 }
825 ContractCostType::ParseWasmDataSegmentBytes => {
826 mem.const_term = 0;
827 mem.lin_term = ScaledU64(257);
828 }
829 ContractCostType::InstantiateWasmInstructions => {
830 mem.const_term = 70704;
831 mem.lin_term = ScaledU64(0);
832 }
833 ContractCostType::InstantiateWasmFunctions => {
834 mem.const_term = 0;
835 mem.lin_term = ScaledU64(14613);
836 }
837 ContractCostType::InstantiateWasmGlobals => {
838 mem.const_term = 0;
839 mem.lin_term = ScaledU64(6833);
840 }
841 ContractCostType::InstantiateWasmTableEntries => {
842 mem.const_term = 0;
843 mem.lin_term = ScaledU64(1025);
844 }
845 ContractCostType::InstantiateWasmTypes => {
846 mem.const_term = 0;
847 mem.lin_term = ScaledU64(0);
848 }
849 ContractCostType::InstantiateWasmDataSegments => {
850 mem.const_term = 0;
851 mem.lin_term = ScaledU64(129632);
852 }
853 ContractCostType::InstantiateWasmElemSegments => {
854 mem.const_term = 0;
855 mem.lin_term = ScaledU64(13665);
856 }
857 ContractCostType::InstantiateWasmImports => {
858 mem.const_term = 0;
859 mem.lin_term = ScaledU64(97637);
860 }
861 ContractCostType::InstantiateWasmExports => {
862 mem.const_term = 0;
863 mem.lin_term = ScaledU64(9176);
864 }
865 ContractCostType::InstantiateWasmDataSegmentBytes => {
866 mem.const_term = 0;
867 mem.lin_term = ScaledU64(126);
868 }
869 ContractCostType::Sec1DecodePointUncompressed => {
870 mem.const_term = 0;
871 mem.lin_term = ScaledU64(0);
872 }
873 ContractCostType::VerifyEcdsaSecp256r1Sig => {
874 mem.const_term = 0;
875 mem.lin_term = ScaledU64(0);
876 }
877 ContractCostType::Bls12381EncodeFp => {
878 mem.const_term = 0;
879 mem.lin_term = ScaledU64(0);
880 }
881 ContractCostType::Bls12381DecodeFp => {
882 mem.const_term = 0;
883 mem.lin_term = ScaledU64(0);
884 }
885 ContractCostType::Bls12381G1CheckPointOnCurve => {
886 mem.const_term = 0;
887 mem.lin_term = ScaledU64(0);
888 }
889 ContractCostType::Bls12381G1CheckPointInSubgroup => {
890 mem.const_term = 0;
891 mem.lin_term = ScaledU64(0);
892 }
893 ContractCostType::Bls12381G2CheckPointOnCurve => {
894 mem.const_term = 0;
895 mem.lin_term = ScaledU64(0);
896 }
897 ContractCostType::Bls12381G2CheckPointInSubgroup => {
898 mem.const_term = 0;
899 mem.lin_term = ScaledU64(0);
900 }
901 ContractCostType::Bls12381G1ProjectiveToAffine => {
902 mem.const_term = 0;
903 mem.lin_term = ScaledU64(0);
904 }
905 ContractCostType::Bls12381G2ProjectiveToAffine => {
906 mem.const_term = 0;
907 mem.lin_term = ScaledU64(0);
908 }
909 ContractCostType::Bls12381G1Add => {
910 mem.const_term = 0;
911 mem.lin_term = ScaledU64(0);
912 }
913 ContractCostType::Bls12381G1Mul => {
914 mem.const_term = 0;
915 mem.lin_term = ScaledU64(0);
916 }
917 ContractCostType::Bls12381G1Msm => {
918 mem.const_term = 109494;
919 mem.lin_term = ScaledU64(354667);
920 }
921 ContractCostType::Bls12381MapFpToG1 => {
922 mem.const_term = 5552;
923 mem.lin_term = ScaledU64(0);
924 }
925 ContractCostType::Bls12381HashToG1 => {
926 mem.const_term = 9424;
927 mem.lin_term = ScaledU64(0);
928 }
929 ContractCostType::Bls12381G2Add => {
930 mem.const_term = 0;
931 mem.lin_term = ScaledU64(0);
932 }
933 ContractCostType::Bls12381G2Mul => {
934 mem.const_term = 0;
935 mem.lin_term = ScaledU64(0);
936 }
937 ContractCostType::Bls12381G2Msm => {
938 mem.const_term = 219654;
939 mem.lin_term = ScaledU64(354667);
940 }
941 ContractCostType::Bls12381MapFp2ToG2 => {
942 mem.const_term = 3344;
943 mem.lin_term = ScaledU64(0);
944 }
945 ContractCostType::Bls12381HashToG2 => {
946 mem.const_term = 6816;
947 mem.lin_term = ScaledU64(0);
948 }
949 ContractCostType::Bls12381Pairing => {
950 mem.const_term = 2204;
951 mem.lin_term = ScaledU64(9340474);
952 }
953 ContractCostType::Bls12381FrFromU256 => {
954 mem.const_term = 0;
955 mem.lin_term = ScaledU64(0);
956 }
957 ContractCostType::Bls12381FrToU256 => {
958 mem.const_term = 248;
959 mem.lin_term = ScaledU64(0);
960 }
961 ContractCostType::Bls12381FrAddSub => {
962 mem.const_term = 0;
963 mem.lin_term = ScaledU64(0);
964 }
965 ContractCostType::Bls12381FrMul => {
966 mem.const_term = 0;
967 mem.lin_term = ScaledU64(0);
968 }
969 ContractCostType::Bls12381FrPow => {
970 mem.const_term = 0;
971 mem.lin_term = ScaledU64(128);
972 }
973 ContractCostType::Bls12381FrInv => {
974 mem.const_term = 0;
975 mem.lin_term = ScaledU64(0);
976 }
977 ContractCostType::Bn254EncodeFp => {
978 mem.const_term = 0;
979 mem.lin_term = ScaledU64(0);
980 }
981 ContractCostType::Bn254DecodeFp => {
982 mem.const_term = 0;
983 mem.lin_term = ScaledU64(0);
984 }
985 ContractCostType::Bn254G1CheckPointOnCurve => {
986 mem.const_term = 0;
987 mem.lin_term = ScaledU64(0);
988 }
989 ContractCostType::Bn254G2CheckPointOnCurve => {
990 mem.const_term = 0;
991 mem.lin_term = ScaledU64(0);
992 }
993 ContractCostType::Bn254G2CheckPointInSubgroup => {
994 mem.const_term = 0;
995 mem.lin_term = ScaledU64(0);
996 }
997 ContractCostType::Bn254G1ProjectiveToAffine => {
998 mem.const_term = 0;
999 mem.lin_term = ScaledU64(0);
1000 }
1001 ContractCostType::Bn254G1Add => {
1002 mem.const_term = 0;
1003 mem.lin_term = ScaledU64(0);
1004 }
1005 ContractCostType::Bn254G1Mul => {
1006 mem.const_term = 0;
1007 mem.lin_term = ScaledU64(0);
1008 }
1009 ContractCostType::Bn254Pairing => {
1010 mem.const_term = 1821;
1011 mem.lin_term = ScaledU64(6232546);
1012 }
1013 ContractCostType::Bn254FrFromU256 => {
1014 mem.const_term = 0;
1015 mem.lin_term = ScaledU64(0);
1016 }
1017 ContractCostType::Bn254FrToU256 => {
1018 mem.const_term = 312;
1019 mem.lin_term = ScaledU64(0);
1020 }
1021 ContractCostType::Bn254FrAddSub => {
1022 mem.const_term = 0;
1023 mem.lin_term = ScaledU64(0);
1024 }
1025 ContractCostType::Bn254FrMul => {
1026 mem.const_term = 0;
1027 mem.lin_term = ScaledU64(0);
1028 }
1029 ContractCostType::Bn254FrPow => {
1030 mem.const_term = 0;
1031 mem.lin_term = ScaledU64(0);
1032 }
1033 ContractCostType::Bn254FrInv => {
1034 mem.const_term = 0;
1035 mem.lin_term = ScaledU64(0);
1036 }
1037 }
1038 }
1039
1040 b.cpu_insns.reset(limits::DEFAULT_CPU_INSN_LIMIT);
1042 b.mem_bytes.reset(limits::DEFAULT_MEM_BYTES_LIMIT);
1043 b
1044 }
1045}
1046
1047impl Debug for BudgetImpl {
1048 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1049 writeln!(f, "{:=<175}", "")?;
1050 writeln!(
1051 f,
1052 "Cpu limit: {}; used: {}",
1053 self.cpu_insns.limit, self.cpu_insns.total_count
1054 )?;
1055 writeln!(
1056 f,
1057 "Mem limit: {}; used: {}",
1058 self.mem_bytes.limit, self.mem_bytes.total_count
1059 )?;
1060 writeln!(f, "{:=<175}", "")?;
1061 writeln!(
1062 f,
1063 "{:<35}{:<15}{:<15}{:<15}{:<15}{:<20}{:<20}{:<20}{:<20}",
1064 "CostType",
1065 "iterations",
1066 "input",
1067 "cpu_insns",
1068 "mem_bytes",
1069 "const_term_cpu",
1070 "lin_term_cpu",
1071 "const_term_mem",
1072 "lin_term_mem",
1073 )?;
1074 for ct in ContractCostType::variants() {
1075 let i = ct as usize;
1076 writeln!(
1077 f,
1078 "{:<35}{:<15}{:<15}{:<15}{:<15}{:<20}{:<20}{:<20}{:<20}",
1079 format!("{:?}", ct),
1080 self.tracker.cost_trackers[i].iterations,
1081 format!("{:?}", self.tracker.cost_trackers[i].inputs),
1082 self.tracker.cost_trackers[i].cpu,
1083 self.tracker.cost_trackers[i].mem,
1084 self.cpu_insns.cost_models[i].const_term,
1085 format!("{}", self.cpu_insns.cost_models[i].lin_term),
1086 self.mem_bytes.cost_models[i].const_term,
1087 format!("{}", self.mem_bytes.cost_models[i].lin_term),
1088 )?;
1089 }
1090 writeln!(f, "{:=<175}", "")?;
1091 writeln!(
1092 f,
1093 "Internal details (diagnostics info, does not affect fees) "
1094 )?;
1095 writeln!(
1096 f,
1097 "Total # times meter was called: {}",
1098 self.tracker.meter_count,
1099 )?;
1100 writeln!(
1101 f,
1102 "Shadow cpu limit: {}; used: {}",
1103 self.cpu_insns.shadow_limit, self.cpu_insns.shadow_total_count
1104 )?;
1105 writeln!(
1106 f,
1107 "Shadow mem limit: {}; used: {}",
1108 self.mem_bytes.shadow_limit, self.mem_bytes.shadow_total_count
1109 )?;
1110 writeln!(f, "{:=<175}", "")?;
1111 Ok(())
1112 }
1113}
1114
1115impl Display for BudgetImpl {
1116 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1117 writeln!(f, "{:=<65}", "")?;
1118 writeln!(
1119 f,
1120 "Cpu limit: {}; used: {}",
1121 self.cpu_insns.limit, self.cpu_insns.total_count
1122 )?;
1123 writeln!(
1124 f,
1125 "Mem limit: {}; used: {}",
1126 self.mem_bytes.limit, self.mem_bytes.total_count
1127 )?;
1128 writeln!(f, "{:=<65}", "")?;
1129 writeln!(
1130 f,
1131 "{:<35}{:<15}{:<15}",
1132 "CostType", "cpu_insns", "mem_bytes",
1133 )?;
1134 for ct in ContractCostType::variants() {
1135 let i = ct as usize;
1136 writeln!(
1137 f,
1138 "{:<35}{:<15}{:<15}",
1139 format!("{:?}", ct),
1140 self.tracker.cost_trackers[i].cpu,
1141 self.tracker.cost_trackers[i].mem,
1142 )?;
1143 }
1144 writeln!(f, "{:=<65}", "")?;
1145 Ok(())
1146 }
1147}
1148
1149#[allow(unused)]
1150#[cfg(test)]
1151impl BudgetImpl {
1152 fn print_default_params_in_cpp(&self) {
1164 println!();
1166 println!();
1167 println!();
1168 for ct in ContractCostType::variants() {
1169 let Ok(cpu) = self.cpu_insns.get_cost_model(ct) else {
1170 continue;
1171 };
1172 println!("case {}:", ct.name());
1173 println!(
1174 "params[val] = ContractCostParamEntry{{ExtensionPoint{{0}}, {}, {}}};",
1175 cpu.const_term, cpu.lin_term.0
1176 );
1177 println!("break;");
1178 }
1179 println!();
1181 println!();
1182 println!();
1183 for ct in ContractCostType::variants() {
1184 let Ok(mem) = self.mem_bytes.get_cost_model(ct) else {
1185 continue;
1186 };
1187 println!("case {}:", ct.name());
1188 println!(
1189 "params[val] = ContractCostParamEntry{{ExtensionPoint{{0}}, {}, {}}};",
1190 mem.const_term, mem.lin_term.0
1191 );
1192 println!("break;");
1193 }
1194 println!();
1195 println!();
1196 println!();
1197 }
1198}
1199
1200#[derive(Clone)]
1201pub struct Budget(pub(crate) Rc<RefCell<BudgetImpl>>);
1202
1203#[allow(clippy::derivable_impls)]
1204impl Default for Budget {
1205 fn default() -> Self {
1206 #[cfg(all(not(target_family = "wasm"), feature = "tracy"))]
1207 let _client = tracy_client::Client::start();
1208 Self(Default::default())
1209 }
1210}
1211
1212impl Debug for Budget {
1213 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1214 writeln!(f, "{:?}", self.0.try_borrow().map_err(|_| std::fmt::Error)?)
1215 }
1216}
1217
1218impl Display for Budget {
1219 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1220 writeln!(f, "{}", self.0.try_borrow().map_err(|_| std::fmt::Error)?)
1221 }
1222}
1223
1224pub trait AsBudget: Clone {
1225 fn as_budget(&self) -> &Budget;
1226}
1227
1228impl AsBudget for Budget {
1229 fn as_budget(&self) -> &Budget {
1230 self
1231 }
1232}
1233
1234impl AsBudget for &Budget {
1235 fn as_budget(&self) -> &Budget {
1236 self
1237 }
1238}
1239
1240impl AsBudget for Host {
1241 fn as_budget(&self) -> &Budget {
1242 self.budget_ref()
1243 }
1244}
1245
1246impl AsBudget for &Host {
1247 fn as_budget(&self) -> &Budget {
1248 self.budget_ref()
1249 }
1250}
1251
1252impl Budget {
1253 pub fn try_from_configs(
1255 cpu_limit: u64,
1256 mem_limit: u64,
1257 cpu_cost_params: ContractCostParams,
1258 mem_cost_params: ContractCostParams,
1259 ) -> Result<Self, HostError> {
1260 Ok(Self(Rc::new(RefCell::new(BudgetImpl::try_from_configs(
1261 cpu_limit,
1262 mem_limit,
1263 cpu_cost_params,
1264 mem_cost_params,
1265 )?))))
1266 }
1267
1268 pub fn try_from_configs_with_shadow_limits(
1271 cpu_limit: u64,
1272 mem_limit: u64,
1273 cpu_shadow_limit: u64,
1274 mem_shadow_limit: u64,
1275 cpu_cost_params: ContractCostParams,
1276 mem_cost_params: ContractCostParams,
1277 ) -> Result<Self, HostError> {
1278 let budget =
1279 Budget::try_from_configs(cpu_limit, mem_limit, cpu_cost_params, mem_cost_params)?;
1280 budget.set_shadow_limits(cpu_shadow_limit, mem_shadow_limit)?;
1281 Ok(budget)
1282 }
1283
1284 fn with_mut_budget<T, F>(&self, f: F) -> Result<T, HostError>
1286 where
1287 F: FnOnce(RefMut<BudgetImpl>) -> Result<T, HostError>,
1288 {
1289 f(self.0.try_borrow_mut_or_err()?)
1290 }
1291
1292 pub fn bulk_charge(
1299 &self,
1300 ty: ContractCostType,
1301 iterations: u64,
1302 input: Option<u64>,
1303 ) -> Result<(), HostError> {
1304 self.0
1305 .try_borrow_mut_or_err()?
1306 .charge(ty, iterations, input)
1307 }
1308
1309 pub fn charge(&self, ty: ContractCostType, input: Option<u64>) -> Result<(), HostError> {
1315 self.0.try_borrow_mut_or_err()?.charge(ty, 1, input)
1316 }
1317
1318 pub(crate) fn get_memory_cost(
1319 &self,
1320 ty: ContractCostType,
1321 input: Option<u64>,
1322 ) -> Result<u64, HostError> {
1323 self.0
1324 .try_borrow_mut_or_err()?
1325 .get_memory_cost(ty, 1, input)
1326 }
1327
1328 pub(crate) fn with_shadow_mode<T, F>(&self, f: F)
1337 where
1338 F: FnOnce() -> Result<T, HostError>,
1339 {
1340 let mut prev = false;
1341
1342 if self
1343 .with_mut_budget(|mut b| {
1344 prev = b.is_in_shadow_mode;
1345 b.is_in_shadow_mode = true;
1346 b.cpu_insns.check_budget_limit(IsShadowMode(true))?;
1347 b.mem_bytes.check_budget_limit(IsShadowMode(true))
1348 })
1349 .is_ok()
1350 {
1351 let _ = f();
1352 }
1353
1354 let _ = self.with_mut_budget(|mut b| {
1355 b.is_in_shadow_mode = prev;
1356 Ok(())
1357 });
1358 }
1359
1360 pub(crate) fn is_in_shadow_mode(&self) -> Result<bool, HostError> {
1361 Ok(self.0.try_borrow_or_err()?.is_in_shadow_mode)
1362 }
1363
1364 pub(crate) fn set_shadow_limits(&self, cpu: u64, mem: u64) -> Result<(), HostError> {
1365 self.0.try_borrow_mut_or_err()?.cpu_insns.shadow_limit = cpu;
1366 self.0.try_borrow_mut_or_err()?.mem_bytes.shadow_limit = mem;
1367 Ok(())
1368 }
1369
1370 pub(crate) fn ensure_shadow_cpu_limit_factor(&self, factor: u64) -> Result<(), HostError> {
1371 let mut b = self.0.try_borrow_mut_or_err()?;
1372 b.cpu_insns.shadow_limit = b.cpu_insns.limit.saturating_mul(factor);
1373 Ok(())
1374 }
1375
1376 pub(crate) fn ensure_shadow_mem_limit_factor(&self, factor: u64) -> Result<(), HostError> {
1377 let mut b = self.0.try_borrow_mut_or_err()?;
1378 b.mem_bytes.shadow_limit = b.mem_bytes.limit.saturating_mul(factor);
1379 Ok(())
1380 }
1381
1382 pub fn get_tracker(&self, ty: ContractCostType) -> Result<CostTracker, HostError> {
1383 self.0
1384 .try_borrow_or_err()?
1385 .tracker
1386 .cost_trackers
1387 .get(ty as usize)
1388 .map(|x| *x)
1389 .ok_or_else(|| (ScErrorType::Budget, ScErrorCode::InternalError).into())
1390 }
1391
1392 pub fn get_time(&self, ty: ContractCostType) -> Result<u64, HostError> {
1393 self.0.try_borrow_or_err()?.tracker.get_time(ty)
1394 }
1395
1396 pub fn track_time(&self, ty: ContractCostType, duration: u64) -> Result<(), HostError> {
1397 self.0
1398 .try_borrow_mut_or_err()?
1399 .tracker
1400 .track_time(ty, duration)
1401 }
1402
1403 pub fn get_cpu_insns_consumed(&self) -> Result<u64, HostError> {
1404 Ok(self.0.try_borrow_or_err()?.cpu_insns.get_total_count())
1405 }
1406
1407 pub fn get_mem_bytes_consumed(&self) -> Result<u64, HostError> {
1408 Ok(self.0.try_borrow_or_err()?.mem_bytes.get_total_count())
1409 }
1410
1411 pub fn get_cpu_insns_remaining(&self) -> Result<u64, HostError> {
1412 Ok(self.0.try_borrow_or_err()?.cpu_insns.get_remaining())
1413 }
1414
1415 pub fn get_mem_bytes_remaining(&self) -> Result<u64, HostError> {
1416 Ok(self.0.try_borrow_or_err()?.mem_bytes.get_remaining())
1417 }
1418
1419 pub(crate) fn get_wasmi_fuel_remaining(&self) -> Result<u64, HostError> {
1420 self.0.try_borrow_mut_or_err()?.get_wasmi_fuel_remaining()
1421 }
1422
1423 pub fn reset_default(&self) -> Result<(), HostError> {
1424 *self.0.try_borrow_mut_or_err()? = BudgetImpl::default();
1425 Ok(())
1426 }
1427}
1428
1429#[test]
1430fn test_budget_initialization() -> Result<(), HostError> {
1431 use crate::xdr::{ContractCostParamEntry, ExtensionPoint};
1432 let cpu_cost_params = ContractCostParams(
1433 vec![
1434 ContractCostParamEntry {
1435 ext: ExtensionPoint::V0,
1436 const_term: 35,
1437 linear_term: 36,
1438 },
1439 ContractCostParamEntry {
1440 ext: ExtensionPoint::V0,
1441 const_term: 37,
1442 linear_term: 38,
1443 },
1444 ]
1445 .try_into()
1446 .unwrap(),
1447 );
1448 let mem_cost_params = ContractCostParams(
1449 vec![
1450 ContractCostParamEntry {
1451 ext: ExtensionPoint::V0,
1452 const_term: 39,
1453 linear_term: 40,
1454 },
1455 ContractCostParamEntry {
1456 ext: ExtensionPoint::V0,
1457 const_term: 41,
1458 linear_term: 42,
1459 },
1460 ContractCostParamEntry {
1461 ext: ExtensionPoint::V0,
1462 const_term: 43,
1463 linear_term: 44,
1464 },
1465 ]
1466 .try_into()
1467 .unwrap(),
1468 );
1469
1470 let budget = Budget::try_from_configs(100, 100, cpu_cost_params, mem_cost_params)?;
1471 assert_eq!(
1472 budget.0.try_borrow_or_err()?.cpu_insns.cost_models.len(),
1473 ContractCostType::variants().len()
1474 );
1475 assert_eq!(
1476 budget.0.try_borrow_or_err()?.mem_bytes.cost_models.len(),
1477 ContractCostType::variants().len()
1478 );
1479 assert_eq!(
1480 budget.0.try_borrow_or_err()?.tracker.cost_trackers.len(),
1481 ContractCostType::variants().len()
1482 );
1483 assert_eq!(
1484 budget.0.try_borrow_or_err()?.tracker.time_tracker.len(),
1485 ContractCostType::variants().len()
1486 );
1487
1488 Ok(())
1489}