1use std::cell::RefMut;
2
3use soroban_env_common::Env;
4
5use crate::{
6 e2e_invoke::encode_contract_events,
7 fees::{FeeConfiguration, DATA_SIZE_1KB_INCREMENT, INSTRUCTIONS_INCREMENT, TTL_ENTRY_SIZE},
8 ledger_info::get_key_durability,
9 storage::{AccessType, Storage},
10 xdr::{ContractDataDurability, ScErrorCode, ScErrorType},
11};
12
13use super::{metered_xdr::metered_write_xdr, Host, HostError};
14
15#[derive(Default, Clone, Debug, Eq, PartialEq)]
21pub struct InvocationResources {
22 pub instructions: i64,
24 pub mem_bytes: i64,
26 pub read_entries: u32,
29 pub write_entries: u32,
32 pub read_bytes: u32,
35 pub write_bytes: u32,
38 pub contract_events_size_bytes: u32,
40 pub persistent_rent_ledger_bytes: i64,
44 pub persistent_entry_rent_bumps: u32,
46 pub temporary_rent_ledger_bytes: i64,
50 pub temporary_entry_rent_bumps: u32,
52}
53
54#[derive(Default, Clone, Debug, Eq, PartialEq)]
60pub struct FeeEstimate {
61 pub total: i64,
63 pub instructions: i64,
65 pub read_entries: i64,
67 pub write_entries: i64,
69 pub read_bytes: i64,
71 pub write_bytes: i64,
73 pub contract_events: i64,
75 pub persistent_entry_rent: i64,
77 pub temporary_entry_rent: i64,
79}
80
81impl InvocationResources {
82 pub fn estimate_fees(
91 &self,
92 fee_config: &FeeConfiguration,
93 persistent_rent_rate_denominator: i64,
94 temporary_rent_rate_denominator: i64,
95 ) -> FeeEstimate {
96 let instructions = compute_fee_per_increment(
97 self.instructions,
98 fee_config.fee_per_instruction_increment,
99 INSTRUCTIONS_INCREMENT,
100 );
101 let read_entries = fee_config
102 .fee_per_read_entry
103 .saturating_mul(self.read_entries.saturating_add(self.write_entries).into());
104 let write_entries = fee_config
105 .fee_per_write_entry
106 .saturating_mul(self.write_entries.into());
107 let read_bytes = compute_fee_per_increment(
108 self.read_bytes.into(),
109 fee_config.fee_per_read_1kb,
110 DATA_SIZE_1KB_INCREMENT,
111 );
112 let write_bytes = compute_fee_per_increment(
113 self.write_bytes.into(),
114 fee_config.fee_per_write_1kb,
115 DATA_SIZE_1KB_INCREMENT,
116 );
117 let contract_events = compute_fee_per_increment(
118 self.contract_events_size_bytes.into(),
119 fee_config.fee_per_contract_event_1kb,
120 DATA_SIZE_1KB_INCREMENT,
121 );
122
123 let mut persistent_entry_ttl_entry_writes = fee_config
124 .fee_per_write_entry
125 .saturating_mul(self.persistent_entry_rent_bumps.into());
126 persistent_entry_ttl_entry_writes =
127 persistent_entry_ttl_entry_writes.saturating_add(compute_fee_per_increment(
128 (TTL_ENTRY_SIZE as i64).saturating_mul(self.persistent_entry_rent_bumps.into()),
129 fee_config.fee_per_write_1kb,
130 DATA_SIZE_1KB_INCREMENT,
131 ));
132 let mut temp_entry_ttl_entry_writes = fee_config
133 .fee_per_write_entry
134 .saturating_mul(self.temporary_entry_rent_bumps.into());
135 temp_entry_ttl_entry_writes =
136 temp_entry_ttl_entry_writes.saturating_add(compute_fee_per_increment(
137 (TTL_ENTRY_SIZE as i64).saturating_mul(self.temporary_entry_rent_bumps.into()),
138 fee_config.fee_per_write_1kb,
139 DATA_SIZE_1KB_INCREMENT,
140 ));
141
142 let persistent_entry_rent = compute_fee_per_increment(
143 self.persistent_rent_ledger_bytes,
144 fee_config.fee_per_write_1kb,
145 DATA_SIZE_1KB_INCREMENT.saturating_mul(persistent_rent_rate_denominator),
146 )
147 .saturating_add(persistent_entry_ttl_entry_writes);
148 let temporary_entry_rent = compute_fee_per_increment(
149 self.temporary_rent_ledger_bytes,
150 fee_config.fee_per_write_1kb,
151 DATA_SIZE_1KB_INCREMENT.saturating_mul(temporary_rent_rate_denominator),
152 )
153 .saturating_add(temp_entry_ttl_entry_writes);
154 let total = instructions
155 .saturating_add(read_entries)
156 .saturating_add(write_entries)
157 .saturating_add(read_bytes)
158 .saturating_add(write_bytes)
159 .saturating_add(contract_events)
160 .saturating_add(persistent_entry_rent)
161 .saturating_add(temporary_entry_rent);
162 FeeEstimate {
163 total,
164 instructions,
165 read_entries,
166 write_entries,
167 read_bytes,
168 write_bytes,
169 contract_events,
170 persistent_entry_rent,
171 temporary_entry_rent,
172 }
173 }
174}
175
176#[derive(Default, Clone)]
184pub(crate) struct InvocationMeter {
185 active: bool,
186 enabled: bool,
187 storage_snapshot: Option<Storage>,
188 invocation_resources: Option<InvocationResources>,
189}
190
191pub(crate) struct InvocationMeterScope<'a> {
194 meter: RefMut<'a, InvocationMeter>,
195 host: &'a Host,
196}
197
198impl Drop for InvocationMeterScope<'_> {
199 fn drop(&mut self) {
200 self.meter.finish_invocation(self.host);
201 }
202}
203
204impl InvocationMeter {
205 pub(crate) fn get_invocation_resources(&self) -> Option<InvocationResources> {
207 self.invocation_resources.clone()
208 }
209
210 fn start_invocation<'a>(
211 mut scope: RefMut<'a, InvocationMeter>,
212 host: &'a Host,
213 ) -> Result<Option<InvocationMeterScope<'a>>, HostError> {
214 if scope.active || !scope.enabled {
215 return Ok(None);
216 }
217 scope.storage_snapshot = Some(host.try_borrow_storage()?.clone());
218 host.try_borrow_storage_mut()?.reset_footprint();
222 host.try_borrow_events_mut()?.clear();
223 host.budget_ref().reset()?;
224 Ok(Some(InvocationMeterScope { meter: scope, host }))
225 }
226
227 fn finish_invocation(&mut self, host: &Host) -> () {
228 self.active = false;
229 let mut invocation_resources = InvocationResources::default();
230 let budget = host.budget_ref();
231 invocation_resources.instructions =
232 budget.get_cpu_insns_consumed().unwrap_or_default() as i64;
233 invocation_resources.mem_bytes = budget.get_mem_bytes_consumed().unwrap_or_default() as i64;
234
235 let measure_res = budget.with_observable_shadow_mode(|| {
236 self.try_measure_resources(&mut invocation_resources, host)
237 });
238
239 if measure_res.is_ok() {
240 self.invocation_resources = Some(invocation_resources);
241 } else {
242 self.invocation_resources = None;
243 }
244
245 self.storage_snapshot = None;
246 }
247
248 fn try_measure_resources(
249 &mut self,
250 invocation_resources: &mut InvocationResources,
251 host: &Host,
252 ) -> Result<(), HostError> {
253 let prev_storage = self.storage_snapshot.as_mut().ok_or_else(|| {
254 host.err(
255 ScErrorType::Context,
256 ScErrorCode::InternalError,
257 "missing a storage snapshot in metering scope, `open` must be called before `close`",
258 &[],
259 )
260 })?;
261
262 let mut curr_storage = host.try_borrow_storage_mut()?;
263 let footprint = curr_storage.footprint.clone();
264 let curr_ledger_seq: u32 = host.get_ledger_sequence()?.into();
265 for (key, access_type) in footprint.0.iter(host.budget_ref())? {
266 let maybe_init_entry = prev_storage.try_get_full_with_host(key, host, None)?;
267 let mut init_entry_size = 0;
268 let mut init_live_until_ledger = curr_ledger_seq;
269 if let Some((init_entry, init_entry_live_until)) = maybe_init_entry {
270 let mut buf = Vec::<u8>::new();
271 metered_write_xdr(host.budget_ref(), init_entry.as_ref(), &mut buf)?;
272 init_entry_size = buf.len() as u32;
273 invocation_resources.read_bytes += init_entry_size;
274 if let Some(live_until) = init_entry_live_until {
275 init_live_until_ledger = live_until;
276 }
277 }
278 let mut entry_size = 0;
279 let mut entry_live_until_ledger = None;
280 let maybe_entry = curr_storage.try_get_full_with_host(key, host, None)?;
281 if let Some((entry, entry_live_until)) = maybe_entry {
282 let mut buf = Vec::<u8>::new();
283 metered_write_xdr(host.budget_ref(), entry.as_ref(), &mut buf)?;
284 entry_size = buf.len() as u32;
285 entry_live_until_ledger = entry_live_until;
286 }
287 match access_type {
288 AccessType::ReadOnly => {
289 invocation_resources.read_entries += 1;
290 }
291 AccessType::ReadWrite => {
292 invocation_resources.write_entries += 1;
293 invocation_resources.write_bytes += entry_size;
294 }
295 }
296 if let Some(new_live_until) = entry_live_until_ledger {
297 let extension_ledgers = (new_live_until - init_live_until_ledger) as i64;
298 let size_delta = if entry_size > init_entry_size {
299 (entry_size - init_entry_size) as i64
300 } else {
301 0
302 };
303 let existing_ledgers = (init_live_until_ledger - curr_ledger_seq) as i64;
304 let rent_ledger_bytes =
305 existing_ledgers * size_delta + extension_ledgers * (entry_size as i64);
306 if rent_ledger_bytes > 0 {
307 match get_key_durability(key.as_ref()) {
308 Some(ContractDataDurability::Temporary) => {
309 invocation_resources.temporary_rent_ledger_bytes += rent_ledger_bytes;
310 invocation_resources.temporary_entry_rent_bumps += 1;
311 }
312 Some(ContractDataDurability::Persistent) => {
313 invocation_resources.persistent_rent_ledger_bytes += rent_ledger_bytes;
314 invocation_resources.persistent_entry_rent_bumps += 1;
315 }
316 None => (),
317 }
318 }
319 }
320 }
321 let events = host.try_borrow_events()?.externalize(&host)?;
322 let encoded_contract_events = encode_contract_events(host.budget_ref(), &events)?;
323 for event in &encoded_contract_events {
324 invocation_resources.contract_events_size_bytes += event.len() as u32;
325 }
326 Ok(())
327 }
328}
329
330impl Host {
331 pub(crate) fn maybe_meter_invocation(
337 &self,
338 ) -> Result<Option<InvocationMeterScope<'_>>, HostError> {
339 if let Ok(scope) = self.0.invocation_meter.try_borrow_mut() {
344 InvocationMeter::start_invocation(scope, self)
345 } else {
346 Ok(None)
347 }
348 }
349
350 pub fn enable_invocation_metering(&self) {
352 if let Ok(mut meter) = self.0.invocation_meter.try_borrow_mut() {
353 meter.enabled = true;
354 }
355 }
356}
357
358fn compute_fee_per_increment(resource_value: i64, fee_rate: i64, increment: i64) -> i64 {
359 num_integer::div_ceil(resource_value.saturating_mul(fee_rate), increment.max(1))
360}
361
362#[cfg(test)]
363mod test {
364 use super::*;
365 use crate::{Symbol, TryFromVal, TryIntoVal};
366 use expect_test::expect;
367 use soroban_test_wasms::CONTRACT_STORAGE;
368
369 fn assert_resources_equal_to_budget(host: &Host) {
370 assert_eq!(
371 host.get_last_invocation_resources().unwrap().instructions as u64,
372 host.budget_ref().get_cpu_insns_consumed().unwrap()
373 );
374 assert_eq!(
375 host.get_last_invocation_resources().unwrap().mem_bytes as u64,
376 host.budget_ref().get_mem_bytes_consumed().unwrap()
377 );
378 }
379
380 #[test]
385 fn test_invocation_resource_metering() {
386 let host = Host::test_host_with_recording_footprint();
387 host.enable_invocation_metering();
388 host.enable_debug().unwrap();
389 host.with_mut_ledger_info(|li| {
390 li.sequence_number = 100;
391 li.max_entry_ttl = 10000;
392 li.min_persistent_entry_ttl = 1000;
393 li.min_temp_entry_ttl = 16;
394 })
395 .unwrap();
396
397 let contract_id = host.register_test_contract_wasm(CONTRACT_STORAGE);
398 expect![[r#"
401 InvocationResources {
402 instructions: 4196698,
403 mem_bytes: 2863076,
404 read_entries: 0,
405 write_entries: 2,
406 read_bytes: 0,
407 write_bytes: 3132,
408 contract_events_size_bytes: 0,
409 persistent_rent_ledger_bytes: 3128868,
410 persistent_entry_rent_bumps: 2,
411 temporary_rent_ledger_bytes: 0,
412 temporary_entry_rent_bumps: 0,
413 }"#]]
414 .assert_eq(format!("{:#?}", host.get_last_invocation_resources().unwrap()).as_str());
415 assert_resources_equal_to_budget(&host);
416
417 let key = Symbol::try_from_small_str("key_1").unwrap();
418
419 let _ = &host
421 .call(
422 contract_id,
423 Symbol::try_from_val(&host, &"has_persistent").unwrap(),
424 test_vec![&host, key].into(),
425 )
426 .unwrap();
427 expect![[r#"
428 InvocationResources {
429 instructions: 846137,
430 mem_bytes: 1215737,
431 read_entries: 3,
432 write_entries: 0,
433 read_bytes: 3132,
434 write_bytes: 0,
435 contract_events_size_bytes: 0,
436 persistent_rent_ledger_bytes: 0,
437 persistent_entry_rent_bumps: 0,
438 temporary_rent_ledger_bytes: 0,
439 temporary_entry_rent_bumps: 0,
440 }"#]]
441 .assert_eq(format!("{:#?}", host.get_last_invocation_resources().unwrap()).as_str());
442 assert_resources_equal_to_budget(&host);
443
444 let _ = &host
446 .try_call(
447 contract_id,
448 Symbol::try_from_val(&host, &"put_persistent").unwrap(),
449 test_vec![&host, key, 1234_u64].into(),
450 )
451 .unwrap();
452 expect![[r#"
453 InvocationResources {
454 instructions: 850395,
455 mem_bytes: 1216336,
456 read_entries: 2,
457 write_entries: 1,
458 read_bytes: 3132,
459 write_bytes: 84,
460 contract_events_size_bytes: 0,
461 persistent_rent_ledger_bytes: 83916,
462 persistent_entry_rent_bumps: 1,
463 temporary_rent_ledger_bytes: 0,
464 temporary_entry_rent_bumps: 0,
465 }"#]]
466 .assert_eq(format!("{:#?}", host.get_last_invocation_resources().unwrap()).as_str());
467 assert_resources_equal_to_budget(&host);
468
469 let _ = &host
471 .call(
472 contract_id,
473 Symbol::try_from_val(&host, &"has_persistent").unwrap(),
474 test_vec![&host, key].into(),
475 )
476 .unwrap();
477 expect![[r#"
478 InvocationResources {
479 instructions: 846406,
480 mem_bytes: 1215721,
481 read_entries: 3,
482 write_entries: 0,
483 read_bytes: 3216,
484 write_bytes: 0,
485 contract_events_size_bytes: 0,
486 persistent_rent_ledger_bytes: 0,
487 persistent_entry_rent_bumps: 0,
488 temporary_rent_ledger_bytes: 0,
489 temporary_entry_rent_bumps: 0,
490 }"#]]
491 .assert_eq(format!("{:#?}", host.get_last_invocation_resources().unwrap()).as_str());
492 assert_resources_equal_to_budget(&host);
493
494 let _ = &host
496 .try_call(
497 contract_id,
498 Symbol::try_from_val(&host, &"put_temporary").unwrap(),
499 test_vec![&host, key, 1234_u64].into(),
500 )
501 .unwrap();
502 expect![[r#"
503 InvocationResources {
504 instructions: 852007,
505 mem_bytes: 1216692,
506 read_entries: 2,
507 write_entries: 1,
508 read_bytes: 3132,
509 write_bytes: 84,
510 contract_events_size_bytes: 0,
511 persistent_rent_ledger_bytes: 0,
512 persistent_entry_rent_bumps: 0,
513 temporary_rent_ledger_bytes: 1260,
514 temporary_entry_rent_bumps: 1,
515 }"#]]
516 .assert_eq(format!("{:#?}", host.get_last_invocation_resources().unwrap()).as_str());
517 assert_resources_equal_to_budget(&host);
518
519 let _ = &host
521 .try_call(
522 contract_id,
523 Symbol::try_from_val(&host, &"has_temporary").unwrap(),
524 test_vec![&host, key].into(),
525 )
526 .unwrap();
527 expect![[r#"
528 InvocationResources {
529 instructions: 846795,
530 mem_bytes: 1215789,
531 read_entries: 3,
532 write_entries: 0,
533 read_bytes: 3216,
534 write_bytes: 0,
535 contract_events_size_bytes: 0,
536 persistent_rent_ledger_bytes: 0,
537 persistent_entry_rent_bumps: 0,
538 temporary_rent_ledger_bytes: 0,
539 temporary_entry_rent_bumps: 0,
540 }"#]]
541 .assert_eq(format!("{:#?}", host.get_last_invocation_resources().unwrap()).as_str());
542 assert_resources_equal_to_budget(&host);
543
544 let _ = &host
546 .call(
547 contract_id,
548 Symbol::try_from_val(&host, &"extend_persistent").unwrap(),
549 test_vec![&host, key, &5000_u32, &5000_u32].into(),
550 )
551 .unwrap();
552 expect![[r#"
553 InvocationResources {
554 instructions: 847840,
555 mem_bytes: 1216141,
556 read_entries: 3,
557 write_entries: 0,
558 read_bytes: 3216,
559 write_bytes: 0,
560 contract_events_size_bytes: 0,
561 persistent_rent_ledger_bytes: 336084,
562 persistent_entry_rent_bumps: 1,
563 temporary_rent_ledger_bytes: 0,
564 temporary_entry_rent_bumps: 0,
565 }"#]]
566 .assert_eq(format!("{:#?}", host.get_last_invocation_resources().unwrap()).as_str());
567 assert_resources_equal_to_budget(&host);
568
569 let _ = &host
571 .call(
572 contract_id,
573 Symbol::try_from_val(&host, &"extend_temporary").unwrap(),
574 test_vec![&host, key, &3000_u32, &3000_u32].into(),
575 )
576 .unwrap();
577 expect![[r#"
578 InvocationResources {
579 instructions: 847960,
580 mem_bytes: 1216141,
581 read_entries: 3,
582 write_entries: 0,
583 read_bytes: 3216,
584 write_bytes: 0,
585 contract_events_size_bytes: 0,
586 persistent_rent_ledger_bytes: 0,
587 persistent_entry_rent_bumps: 0,
588 temporary_rent_ledger_bytes: 250740,
589 temporary_entry_rent_bumps: 1,
590 }"#]]
591 .assert_eq(format!("{:#?}", host.get_last_invocation_resources().unwrap()).as_str());
592 assert_resources_equal_to_budget(&host);
593
594 let non_existent_key = Symbol::try_from_small_str("non_exist").unwrap();
596 let res = &host.call(
597 contract_id,
598 Symbol::try_from_val(&host, &"extend_persistent").unwrap(),
599 test_vec![&host, non_existent_key, &5000_u32, &5000_u32].into(),
600 );
601 assert!(res.is_err());
602 expect![[r#"
603 InvocationResources {
604 instructions: 847829,
605 mem_bytes: 1216209,
606 read_entries: 3,
607 write_entries: 0,
608 read_bytes: 3132,
609 write_bytes: 0,
610 contract_events_size_bytes: 0,
611 persistent_rent_ledger_bytes: 0,
612 persistent_entry_rent_bumps: 0,
613 temporary_rent_ledger_bytes: 0,
614 temporary_entry_rent_bumps: 0,
615 }"#]]
616 .assert_eq(format!("{:#?}", host.get_last_invocation_resources().unwrap()).as_str());
617 assert_resources_equal_to_budget(&host);
618 }
619
620 #[test]
621 fn test_resource_fee_estimation() {
622 assert_eq!(
624 InvocationResources {
625 instructions: 0,
626 mem_bytes: 100_000,
627 read_entries: 0,
628 write_entries: 0,
629 read_bytes: 0,
630 write_bytes: 0,
631 contract_events_size_bytes: 0,
632 persistent_rent_ledger_bytes: 0,
633 persistent_entry_rent_bumps: 0,
634 temporary_rent_ledger_bytes: 0,
635 temporary_entry_rent_bumps: 0
636 }
637 .estimate_fees(
638 &FeeConfiguration {
639 fee_per_instruction_increment: 100,
640 fee_per_read_entry: 100,
641 fee_per_write_entry: 100,
642 fee_per_read_1kb: 100,
643 fee_per_write_1kb: 100,
644 fee_per_historical_1kb: 100,
645 fee_per_contract_event_1kb: 100,
646 fee_per_transaction_size_1kb: 100,
647 },
648 1,
649 1
650 ),
651 FeeEstimate {
652 total: 0,
653 instructions: 0,
654 read_entries: 0,
655 write_entries: 0,
656 read_bytes: 0,
657 write_bytes: 0,
658 contract_events: 0,
659 persistent_entry_rent: 0,
660 temporary_entry_rent: 0,
661 }
662 );
663
664 assert_eq!(
666 InvocationResources {
667 instructions: 1,
668 mem_bytes: 100_000,
669 read_entries: 1,
670 write_entries: 1,
671 read_bytes: 1,
672 write_bytes: 1,
673 contract_events_size_bytes: 1,
674 persistent_rent_ledger_bytes: 1,
675 persistent_entry_rent_bumps: 1,
676 temporary_rent_ledger_bytes: 1,
677 temporary_entry_rent_bumps: 1
678 }
679 .estimate_fees(
680 &FeeConfiguration {
681 fee_per_instruction_increment: 100,
682 fee_per_read_entry: 100,
683 fee_per_write_entry: 100,
684 fee_per_read_1kb: 100,
685 fee_per_write_1kb: 100,
686 fee_per_historical_1kb: 100,
687 fee_per_contract_event_1kb: 100,
688 fee_per_transaction_size_1kb: 100,
689 },
690 1,
691 1
692 ),
693 FeeEstimate {
694 total: 516,
695 instructions: 1,
696 read_entries: 200,
697 write_entries: 100,
698 read_bytes: 1,
699 write_bytes: 1,
700 contract_events: 1,
701 persistent_entry_rent: 106,
702 temporary_entry_rent: 106
703 }
704 );
705
706 assert_eq!(
709 InvocationResources {
710 instructions: 10_123_456,
711 mem_bytes: 100_000,
712 read_entries: 30,
713 write_entries: 10,
714 read_bytes: 25_600,
715 write_bytes: 10_340,
716 contract_events_size_bytes: 321_654,
717 persistent_rent_ledger_bytes: 1_000_000_000,
718 persistent_entry_rent_bumps: 3,
719 temporary_rent_ledger_bytes: 4_000_000_000,
720 temporary_entry_rent_bumps: 6
721 }
722 .estimate_fees(
723 &FeeConfiguration {
724 fee_per_instruction_increment: 1000,
725 fee_per_read_entry: 2000,
726 fee_per_write_entry: 4000,
727 fee_per_read_1kb: 1500,
728 fee_per_write_1kb: 3000,
729 fee_per_historical_1kb: 300,
730 fee_per_contract_event_1kb: 200,
731 fee_per_transaction_size_1kb: 900,
732 },
733 1000,
734 2000
735 ),
736 FeeEstimate {
737 total: 10_089_292,
739 instructions: 1_012_346,
740 read_entries: 80000,
741 write_entries: 40000,
742 read_bytes: 37500,
743 write_bytes: 30293,
744 contract_events: 62824,
745 persistent_entry_rent: 2942110,
746 temporary_entry_rent: 5884219
747 }
748 );
749
750 assert_eq!(
752 InvocationResources {
753 instructions: i64::MAX,
754 mem_bytes: i64::MAX,
755 read_entries: u32::MAX,
756 write_entries: u32::MAX,
757 read_bytes: u32::MAX,
758 write_bytes: u32::MAX,
759 contract_events_size_bytes: u32::MAX,
760 persistent_rent_ledger_bytes: i64::MAX,
761 persistent_entry_rent_bumps: u32::MAX,
762 temporary_rent_ledger_bytes: i64::MAX,
763 temporary_entry_rent_bumps: u32::MAX
764 }
765 .estimate_fees(
766 &FeeConfiguration {
767 fee_per_instruction_increment: i64::MAX,
768 fee_per_read_entry: i64::MAX,
769 fee_per_write_entry: i64::MAX,
770 fee_per_read_1kb: i64::MAX,
771 fee_per_write_1kb: i64::MAX,
772 fee_per_historical_1kb: i64::MAX,
773 fee_per_contract_event_1kb: i64::MAX,
774 fee_per_transaction_size_1kb: i64::MAX,
775 },
776 i64::MAX,
777 i64::MAX
778 ),
779 FeeEstimate {
780 total: i64::MAX,
781 instructions: 922337203685478,
782 read_entries: i64::MAX,
783 write_entries: i64::MAX,
784 read_bytes: 9007199254740992,
785 write_bytes: 9007199254740992,
786 contract_events: 9007199254740992,
787 persistent_entry_rent: i64::MAX,
788 temporary_entry_rent: i64::MAX
789 }
790 );
791 }
792}