1use std::{fmt, sync::Arc, time::Duration};
7
8use custom_debug_derive::Debug;
9use linera_base::{
10 data_types::{Amount, ApplicationDescription, ArithmeticError, Blob},
11 ensure,
12 identifiers::AccountOwner,
13 ownership::ChainOwnership,
14 vm::VmRuntime,
15};
16use linera_views::{context::Context, ViewError};
17use serde::Serialize;
18
19use crate::{ExecutionError, Message, Operation, ResourceControlPolicy, SystemExecutionStateView};
20
21#[derive(Clone, Debug, Default)]
22pub struct ResourceController<Account = Amount, Tracker = ResourceTracker> {
23 policy: Arc<ResourceControlPolicy>,
25 pub tracker: Tracker,
27 pub account: Account,
29 pub is_free: bool,
31}
32
33impl<Account, Tracker> ResourceController<Account, Tracker> {
34 pub fn new(policy: Arc<ResourceControlPolicy>, tracker: Tracker, account: Account) -> Self {
36 Self {
37 policy,
38 tracker,
39 account,
40 is_free: false,
41 }
42 }
43
44 pub fn policy(&self) -> &Arc<ResourceControlPolicy> {
46 &self.policy
47 }
48
49 pub fn tracker(&self) -> &Tracker {
51 &self.tracker
52 }
53}
54
55pub const RUNTIME_AMOUNT_SIZE: u32 = 16;
57
58pub const RUNTIME_APPLICATION_ID_SIZE: u32 = 32;
60
61pub const RUNTIME_BLOCK_HEIGHT_SIZE: u32 = 8;
63
64pub const RUNTIME_CHAIN_ID_SIZE: u32 = 32;
66
67pub const RUNTIME_TIMESTAMP_SIZE: u32 = 8;
69
70pub const RUNTIME_OWNER_WEIGHT_SIZE: u32 = 8;
72
73pub const RUNTIME_CONSTANT_CHAIN_OWNERSHIP_SIZE: u32 = 4 + 4 * 8;
78
79pub const RUNTIME_CRYPTO_HASH_SIZE: u32 = 32;
81
82pub const RUNTIME_VM_RUNTIME_SIZE: u32 = 1;
84
85pub const RUNTIME_CONSTANT_APPLICATION_DESCRIPTION_SIZE: u32 = 2 * RUNTIME_CRYPTO_HASH_SIZE + RUNTIME_VM_RUNTIME_SIZE + RUNTIME_CHAIN_ID_SIZE + RUNTIME_BLOCK_HEIGHT_SIZE + 4; #[cfg(test)]
94mod tests {
95 use std::mem::size_of;
96
97 use linera_base::{
98 data_types::{Amount, ApplicationDescription, BlockHeight, Timestamp},
99 identifiers::{ApplicationId, ChainId, ModuleId},
100 };
101
102 use crate::resources::{
103 RUNTIME_AMOUNT_SIZE, RUNTIME_APPLICATION_ID_SIZE, RUNTIME_BLOCK_HEIGHT_SIZE,
104 RUNTIME_CHAIN_ID_SIZE, RUNTIME_CONSTANT_APPLICATION_DESCRIPTION_SIZE,
105 RUNTIME_OWNER_WEIGHT_SIZE, RUNTIME_TIMESTAMP_SIZE,
106 };
107
108 #[test]
109 fn test_size_of_runtime_operations() {
110 assert_eq!(RUNTIME_AMOUNT_SIZE as usize, size_of::<Amount>());
111 assert_eq!(
112 RUNTIME_APPLICATION_ID_SIZE as usize,
113 size_of::<ApplicationId>()
114 );
115 assert_eq!(RUNTIME_BLOCK_HEIGHT_SIZE as usize, size_of::<BlockHeight>());
116 assert_eq!(RUNTIME_CHAIN_ID_SIZE as usize, size_of::<ChainId>());
117 assert_eq!(RUNTIME_TIMESTAMP_SIZE as usize, size_of::<Timestamp>());
118 assert_eq!(RUNTIME_OWNER_WEIGHT_SIZE as usize, size_of::<u64>());
119 }
120
121 #[test]
125 fn test_application_description_size() {
126 let description = ApplicationDescription {
129 module_id: ModuleId::default(),
130 creator_chain_id: ChainId::default(),
131 block_height: BlockHeight::default(),
132 application_index: 0,
133 parameters: vec![],
134 required_application_ids: vec![],
135 };
136 let serialized = bcs::to_bytes(&description).expect("serialization should succeed");
137 assert_eq!(
139 serialized.len(),
140 RUNTIME_CONSTANT_APPLICATION_DESCRIPTION_SIZE as usize + 2
141 );
142 }
143}
144
145#[derive(Copy, Debug, Clone, Default)]
151pub struct ResourceTracker {
152 pub block_size: u64,
154 pub evm_fuel: u64,
156 pub wasm_fuel: u64,
158 pub read_operations: u32,
160 pub write_operations: u32,
162 pub bytes_runtime: u32,
164 pub bytes_read: u64,
166 pub bytes_written: u64,
168 pub blobs_read: u32,
170 pub blobs_published: u32,
172 pub blob_bytes_read: u64,
174 pub blob_bytes_published: u64,
176 pub events_read: u32,
178 pub events_published: u32,
180 pub event_bytes_read: u64,
182 pub event_bytes_published: u64,
184 pub bytes_stored: i32,
186 pub operations: u32,
188 pub operation_bytes: u64,
190 pub messages: u32,
192 pub message_bytes: u64,
194 pub http_requests: u32,
196 pub service_oracle_queries: u32,
198 pub service_oracle_execution: Duration,
200 pub grants: Amount,
202}
203
204impl ResourceTracker {
205 fn fuel(&self, vm_runtime: VmRuntime) -> u64 {
206 match vm_runtime {
207 VmRuntime::Wasm => self.wasm_fuel,
208 VmRuntime::Evm => self.evm_fuel,
209 }
210 }
211}
212
213impl fmt::Display for ResourceTracker {
214 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
215 let mut lines = Vec::new();
216
217 let mut block_parts = Vec::new();
218 if self.block_size != 0 {
219 block_parts.push(format!("size={}", self.block_size));
220 }
221 if self.operations != 0 {
222 block_parts.push(format!("operations={}", self.operations));
223 }
224 if self.operation_bytes != 0 {
225 block_parts.push(format!("operation_bytes={}", self.operation_bytes));
226 }
227 if !block_parts.is_empty() {
228 lines.push(format!("block: {}", block_parts.join(", ")));
229 }
230
231 let mut fuel_parts = Vec::new();
232 if self.wasm_fuel != 0 {
233 fuel_parts.push(format!("wasm={}", self.wasm_fuel));
234 }
235 if self.evm_fuel != 0 {
236 fuel_parts.push(format!("evm={}", self.evm_fuel));
237 }
238 if !fuel_parts.is_empty() {
239 lines.push(format!("fuel: {}", fuel_parts.join(", ")));
240 }
241
242 let mut storage_parts = Vec::new();
243 if self.read_operations != 0 {
244 storage_parts.push(format!("reads={}", self.read_operations));
245 }
246 if self.write_operations != 0 {
247 storage_parts.push(format!("writes={}", self.write_operations));
248 }
249 if self.bytes_runtime != 0 {
250 storage_parts.push(format!("runtime_bytes={}", self.bytes_runtime));
251 }
252 if self.bytes_read != 0 {
253 storage_parts.push(format!("bytes_read={}", self.bytes_read));
254 }
255 if self.bytes_written != 0 {
256 storage_parts.push(format!("bytes_written={}", self.bytes_written));
257 }
258 if self.bytes_stored != 0 {
259 storage_parts.push(format!("bytes_stored={}", self.bytes_stored));
260 }
261 if !storage_parts.is_empty() {
262 lines.push(format!("storage: {}", storage_parts.join(", ")));
263 }
264
265 let mut blob_parts = Vec::new();
266 if self.blobs_read != 0 {
267 blob_parts.push(format!("read={}", self.blobs_read));
268 }
269 if self.blobs_published != 0 {
270 blob_parts.push(format!("published={}", self.blobs_published));
271 }
272 if self.blob_bytes_read != 0 {
273 blob_parts.push(format!("bytes_read={}", self.blob_bytes_read));
274 }
275 if self.blob_bytes_published != 0 {
276 blob_parts.push(format!("bytes_published={}", self.blob_bytes_published));
277 }
278 if !blob_parts.is_empty() {
279 lines.push(format!("blobs: {}", blob_parts.join(", ")));
280 }
281
282 let mut event_parts = Vec::new();
283 if self.events_read != 0 {
284 event_parts.push(format!("read={}", self.events_read));
285 }
286 if self.events_published != 0 {
287 event_parts.push(format!("published={}", self.events_published));
288 }
289 if self.event_bytes_read != 0 {
290 event_parts.push(format!("bytes_read={}", self.event_bytes_read));
291 }
292 if self.event_bytes_published != 0 {
293 event_parts.push(format!("bytes_published={}", self.event_bytes_published));
294 }
295 if !event_parts.is_empty() {
296 lines.push(format!("events: {}", event_parts.join(", ")));
297 }
298
299 let mut message_parts = Vec::new();
300 if self.messages != 0 {
301 message_parts.push(format!("count={}", self.messages));
302 }
303 if self.message_bytes != 0 {
304 message_parts.push(format!("bytes={}", self.message_bytes));
305 }
306 if self.grants != Amount::ZERO {
307 message_parts.push(format!("grants={}", self.grants));
308 }
309 if !message_parts.is_empty() {
310 lines.push(format!("messages: {}", message_parts.join(", ")));
311 }
312
313 let mut http_service_parts = Vec::new();
314 if self.http_requests != 0 {
315 http_service_parts.push(format!("http_requests={}", self.http_requests));
316 }
317 if self.service_oracle_queries != 0 {
318 http_service_parts.push(format!("service_queries={}", self.service_oracle_queries));
319 }
320 if self.service_oracle_execution != Duration::ZERO {
321 http_service_parts.push(format!(
322 "service_execution={:?}",
323 self.service_oracle_execution
324 ));
325 }
326 if !http_service_parts.is_empty() {
327 lines.push(format!("http/service: {}", http_service_parts.join(", ")));
328 }
329
330 let mut lines_iter = lines.into_iter();
331 if let Some(first) = lines_iter.next() {
332 write!(f, "{}", first)?;
333 for line in lines_iter {
334 write!(f, "\n {}", line)?;
335 }
336 }
337
338 Ok(())
339 }
340}
341
342pub trait BalanceHolder {
344 fn balance(&self) -> Result<Amount, ArithmeticError>;
345
346 fn try_add_assign(&mut self, other: Amount) -> Result<(), ArithmeticError>;
347
348 fn try_sub_assign(&mut self, other: Amount) -> Result<(), ArithmeticError>;
349}
350
351impl<Account, Tracker> ResourceController<Account, Tracker>
353where
354 Account: BalanceHolder,
355 Tracker: AsRef<ResourceTracker> + AsMut<ResourceTracker>,
356{
357 pub fn balance(&self) -> Result<Amount, ArithmeticError> {
360 self.account.balance()
361 }
362
363 pub fn merge_balance(&mut self, initial: Amount, other: Amount) -> Result<(), ExecutionError> {
366 if other <= initial {
367 let sub_amount = initial.try_sub(other).expect("other <= initial");
368 self.account.try_sub_assign(sub_amount).map_err(|_| {
369 ExecutionError::FeesExceedFunding {
370 fees: sub_amount,
371 balance: self.balance().unwrap_or(Amount::MAX),
372 }
373 })?;
374 } else {
375 self.account
376 .try_add_assign(other.try_sub(initial).expect("other > initial"))?;
377 }
378 Ok(())
379 }
380
381 fn update_balance(&mut self, fees: Amount) -> Result<(), ExecutionError> {
384 if self.is_free {
385 return Ok(());
386 }
387 self.account
388 .try_sub_assign(fees)
389 .map_err(|_| ExecutionError::FeesExceedFunding {
390 fees,
391 balance: self.balance().unwrap_or(Amount::MAX),
392 })?;
393 Ok(())
394 }
395
396 pub(crate) fn remaining_fuel(&self, vm_runtime: VmRuntime) -> u64 {
398 let fuel = self.tracker.as_ref().fuel(vm_runtime);
399 let maximum_fuel_per_block = self.policy.maximum_fuel_per_block(vm_runtime);
400 if self.is_free {
401 return maximum_fuel_per_block.saturating_sub(fuel);
402 }
403 let balance = self.balance().unwrap_or(Amount::MAX);
404 self.policy
405 .remaining_fuel(balance, vm_runtime)
406 .min(maximum_fuel_per_block.saturating_sub(fuel))
407 }
408
409 pub fn track_grant(&mut self, grant: Amount) -> Result<(), ExecutionError> {
411 self.tracker.as_mut().grants.try_add_assign(grant)?;
412 self.update_balance(grant)
413 }
414
415 pub fn track_operation(&mut self, operation: &Operation) -> Result<(), ExecutionError> {
417 self.tracker.as_mut().operations = self
418 .tracker
419 .as_mut()
420 .operations
421 .checked_add(1)
422 .ok_or(ArithmeticError::Overflow)?;
423 self.update_balance(self.policy.operation)?;
424 match operation {
425 Operation::System(_) => Ok(()),
426 Operation::User { bytes, .. } => {
427 let size = bytes.len();
428 self.tracker.as_mut().operation_bytes = self
429 .tracker
430 .as_mut()
431 .operation_bytes
432 .checked_add(size as u64)
433 .ok_or(ArithmeticError::Overflow)?;
434 self.update_balance(self.policy.operation_bytes_price(size as u64)?)?;
435 Ok(())
436 }
437 }
438 }
439
440 pub fn track_message(&mut self, message: &Message) -> Result<(), ExecutionError> {
442 self.tracker.as_mut().messages = self
443 .tracker
444 .as_mut()
445 .messages
446 .checked_add(1)
447 .ok_or(ArithmeticError::Overflow)?;
448 self.update_balance(self.policy.message)?;
449 match message {
450 Message::System(_) => Ok(()),
451 Message::User { bytes, .. } => {
452 let size = bytes.len();
453 self.tracker.as_mut().message_bytes = self
454 .tracker
455 .as_mut()
456 .message_bytes
457 .checked_add(size as u64)
458 .ok_or(ArithmeticError::Overflow)?;
459 self.update_balance(self.policy.message_bytes_price(size as u64)?)?;
460 Ok(())
461 }
462 }
463 }
464
465 pub fn track_http_request(&mut self) -> Result<(), ExecutionError> {
467 self.tracker.as_mut().http_requests = self
468 .tracker
469 .as_ref()
470 .http_requests
471 .checked_add(1)
472 .ok_or(ArithmeticError::Overflow)?;
473 self.update_balance(self.policy.http_request)
474 }
475
476 pub(crate) fn track_fuel(
478 &mut self,
479 fuel: u64,
480 vm_runtime: VmRuntime,
481 ) -> Result<(), ExecutionError> {
482 match vm_runtime {
483 VmRuntime::Wasm => {
484 self.tracker.as_mut().wasm_fuel = self
485 .tracker
486 .as_ref()
487 .wasm_fuel
488 .checked_add(fuel)
489 .ok_or(ArithmeticError::Overflow)?;
490 ensure!(
491 self.tracker.as_ref().wasm_fuel <= self.policy.maximum_wasm_fuel_per_block,
492 ExecutionError::MaximumFuelExceeded(vm_runtime)
493 );
494 }
495 VmRuntime::Evm => {
496 self.tracker.as_mut().evm_fuel = self
497 .tracker
498 .as_ref()
499 .evm_fuel
500 .checked_add(fuel)
501 .ok_or(ArithmeticError::Overflow)?;
502 ensure!(
503 self.tracker.as_ref().evm_fuel <= self.policy.maximum_evm_fuel_per_block,
504 ExecutionError::MaximumFuelExceeded(vm_runtime)
505 );
506 }
507 }
508 self.update_balance(self.policy.fuel_price(fuel, vm_runtime)?)
509 }
510
511 pub(crate) fn track_runtime_chain_id(&mut self) -> Result<(), ExecutionError> {
513 self.track_size_runtime_operations(RUNTIME_CHAIN_ID_SIZE)
514 }
515
516 pub(crate) fn track_runtime_block_height(&mut self) -> Result<(), ExecutionError> {
518 self.track_size_runtime_operations(RUNTIME_BLOCK_HEIGHT_SIZE)
519 }
520
521 pub(crate) fn track_runtime_application_id(&mut self) -> Result<(), ExecutionError> {
523 self.track_size_runtime_operations(RUNTIME_APPLICATION_ID_SIZE)
524 }
525
526 pub(crate) fn track_runtime_application_parameters(
528 &mut self,
529 parameters: &[u8],
530 ) -> Result<(), ExecutionError> {
531 let parameters_len = parameters.len() as u32;
532 self.track_size_runtime_operations(parameters_len)
533 }
534
535 pub(crate) fn track_runtime_timestamp(&mut self) -> Result<(), ExecutionError> {
537 self.track_size_runtime_operations(RUNTIME_TIMESTAMP_SIZE)
538 }
539
540 pub(crate) fn track_runtime_balance(&mut self) -> Result<(), ExecutionError> {
542 self.track_size_runtime_operations(RUNTIME_AMOUNT_SIZE)
543 }
544
545 pub(crate) fn track_runtime_owner_balances(
547 &mut self,
548 owner_balances: &[(AccountOwner, Amount)],
549 ) -> Result<(), ExecutionError> {
550 let mut size = 0;
551 for (account_owner, _) in owner_balances {
552 size += account_owner.size() + RUNTIME_AMOUNT_SIZE;
553 }
554 self.track_size_runtime_operations(size)
555 }
556
557 pub(crate) fn track_runtime_owners(
559 &mut self,
560 owners: &[AccountOwner],
561 ) -> Result<(), ExecutionError> {
562 let mut size = 0;
563 for owner in owners {
564 size += owner.size();
565 }
566 self.track_size_runtime_operations(size)
567 }
568
569 pub(crate) fn track_runtime_chain_ownership(
571 &mut self,
572 chain_ownership: &ChainOwnership,
573 ) -> Result<(), ExecutionError> {
574 let mut size = 0;
575 for account_owner in &chain_ownership.super_owners {
576 size += account_owner.size();
577 }
578 for account_owner in chain_ownership.owners.keys() {
579 size += account_owner.size() + RUNTIME_OWNER_WEIGHT_SIZE;
580 }
581 size += RUNTIME_CONSTANT_CHAIN_OWNERSHIP_SIZE;
582 self.track_size_runtime_operations(size)
583 }
584
585 pub(crate) fn track_runtime_application_description(
587 &mut self,
588 description: &ApplicationDescription,
589 ) -> Result<(), ExecutionError> {
590 let parameters_size = description.parameters.len() as u32;
591 let required_apps_size =
592 description.required_application_ids.len() as u32 * RUNTIME_APPLICATION_ID_SIZE;
593 let size =
594 RUNTIME_CONSTANT_APPLICATION_DESCRIPTION_SIZE + parameters_size + required_apps_size;
595 self.track_size_runtime_operations(size)
596 }
597
598 fn track_size_runtime_operations(&mut self, size: u32) -> Result<(), ExecutionError> {
600 self.tracker.as_mut().bytes_runtime = self
601 .tracker
602 .as_mut()
603 .bytes_runtime
604 .checked_add(size)
605 .ok_or(ArithmeticError::Overflow)?;
606 self.update_balance(self.policy.bytes_runtime_price(size)?)
607 }
608
609 pub(crate) fn track_read_operation(&mut self) -> Result<(), ExecutionError> {
611 self.tracker.as_mut().read_operations = self
612 .tracker
613 .as_mut()
614 .read_operations
615 .checked_add(1)
616 .ok_or(ArithmeticError::Overflow)?;
617 self.update_balance(self.policy.read_operations_price(1)?)
618 }
619
620 pub(crate) fn track_write_operations(&mut self, count: u32) -> Result<(), ExecutionError> {
622 self.tracker.as_mut().write_operations = self
623 .tracker
624 .as_mut()
625 .write_operations
626 .checked_add(count)
627 .ok_or(ArithmeticError::Overflow)?;
628 self.update_balance(self.policy.write_operations_price(count)?)
629 }
630
631 pub(crate) fn track_bytes_read(&mut self, count: u64) -> Result<(), ExecutionError> {
633 self.tracker.as_mut().bytes_read = self
634 .tracker
635 .as_mut()
636 .bytes_read
637 .checked_add(count)
638 .ok_or(ArithmeticError::Overflow)?;
639 if self.tracker.as_mut().bytes_read >= self.policy.maximum_bytes_read_per_block {
640 return Err(ExecutionError::ExcessiveRead);
641 }
642 self.update_balance(self.policy.bytes_read_price(count)?)?;
643 Ok(())
644 }
645
646 pub(crate) fn track_bytes_written(&mut self, count: u64) -> Result<(), ExecutionError> {
648 self.tracker.as_mut().bytes_written = self
649 .tracker
650 .as_mut()
651 .bytes_written
652 .checked_add(count)
653 .ok_or(ArithmeticError::Overflow)?;
654 if self.tracker.as_mut().bytes_written >= self.policy.maximum_bytes_written_per_block {
655 return Err(ExecutionError::ExcessiveWrite);
656 }
657 self.update_balance(self.policy.bytes_written_price(count)?)?;
658 Ok(())
659 }
660
661 pub(crate) fn track_blob_read(&mut self, count: u64) -> Result<(), ExecutionError> {
663 {
664 let tracker = self.tracker.as_mut();
665 tracker.blob_bytes_read = tracker
666 .blob_bytes_read
667 .checked_add(count)
668 .ok_or(ArithmeticError::Overflow)?;
669 tracker.blobs_read = tracker
670 .blobs_read
671 .checked_add(1)
672 .ok_or(ArithmeticError::Overflow)?;
673 }
674 self.update_balance(self.policy.blob_read_price(count)?)?;
675 Ok(())
676 }
677
678 pub fn track_blob_published(&mut self, blob: &Blob) -> Result<(), ExecutionError> {
680 self.policy.check_blob_size(blob.content())?;
681 let size = blob.content().bytes().len() as u64;
682 if blob.is_committee_blob() {
683 return Ok(());
684 }
685 {
686 let tracker = self.tracker.as_mut();
687 tracker.blob_bytes_published = tracker
688 .blob_bytes_published
689 .checked_add(size)
690 .ok_or(ArithmeticError::Overflow)?;
691 tracker.blobs_published = tracker
692 .blobs_published
693 .checked_add(1)
694 .ok_or(ArithmeticError::Overflow)?;
695 }
696 self.update_balance(self.policy.blob_published_price(size)?)?;
697 Ok(())
698 }
699
700 pub(crate) fn track_event_read(&mut self, count: u64) -> Result<(), ExecutionError> {
702 {
703 let tracker = self.tracker.as_mut();
704 tracker.event_bytes_read = tracker
705 .event_bytes_read
706 .checked_add(count)
707 .ok_or(ArithmeticError::Overflow)?;
708 tracker.events_read = tracker
709 .events_read
710 .checked_add(1)
711 .ok_or(ArithmeticError::Overflow)?;
712 }
713 self.update_balance(self.policy.blob_read_price(count)?)?;
714 Ok(())
715 }
716
717 pub(crate) fn track_event_published(
719 &mut self,
720 event_bytes: &[u8],
721 ) -> Result<(), ExecutionError> {
722 let size = event_bytes.len() as u64;
723 {
724 let tracker = self.tracker.as_mut();
725 tracker.event_bytes_published = tracker
726 .event_bytes_published
727 .checked_add(size)
728 .ok_or(ArithmeticError::Overflow)?;
729 tracker.events_published = tracker
730 .events_published
731 .checked_add(1)
732 .ok_or(ArithmeticError::Overflow)?;
733 }
734 self.update_balance(self.policy.blob_published_price(size)?)?;
735 Ok(())
736 }
737
738 #[allow(dead_code)]
741 pub(crate) fn track_stored_bytes(&mut self, delta: i32) -> Result<(), ExecutionError> {
742 self.tracker.as_mut().bytes_stored = self
743 .tracker
744 .as_mut()
745 .bytes_stored
746 .checked_add(delta)
747 .ok_or(ArithmeticError::Overflow)?;
748 Ok(())
749 }
750
751 pub(crate) fn remaining_service_oracle_execution_time(
753 &self,
754 ) -> Result<Duration, ExecutionError> {
755 let tracker = self.tracker.as_ref();
756 let spent_execution_time = tracker.service_oracle_execution;
757 let limit = Duration::from_millis(self.policy.maximum_service_oracle_execution_ms);
758
759 limit
760 .checked_sub(spent_execution_time)
761 .ok_or(ExecutionError::MaximumServiceOracleExecutionTimeExceeded)
762 }
763
764 pub(crate) fn track_service_oracle_call(&mut self) -> Result<(), ExecutionError> {
766 self.tracker.as_mut().service_oracle_queries = self
767 .tracker
768 .as_mut()
769 .service_oracle_queries
770 .checked_add(1)
771 .ok_or(ArithmeticError::Overflow)?;
772 self.update_balance(self.policy.service_as_oracle_query)
773 }
774
775 pub(crate) fn track_service_oracle_execution(
777 &mut self,
778 execution_time: Duration,
779 ) -> Result<(), ExecutionError> {
780 let tracker = self.tracker.as_mut();
781 let spent_execution_time = &mut tracker.service_oracle_execution;
782 let limit = Duration::from_millis(self.policy.maximum_service_oracle_execution_ms);
783
784 *spent_execution_time = spent_execution_time.saturating_add(execution_time);
785
786 ensure!(
787 *spent_execution_time < limit,
788 ExecutionError::MaximumServiceOracleExecutionTimeExceeded
789 );
790
791 Ok(())
792 }
793
794 pub(crate) fn track_service_oracle_response(
796 &self,
797 response_bytes: usize,
798 ) -> Result<(), ExecutionError> {
799 ensure!(
800 response_bytes as u64 <= self.policy.maximum_oracle_response_bytes,
801 ExecutionError::ServiceOracleResponseTooLarge
802 );
803
804 Ok(())
805 }
806}
807
808impl<Account, Tracker> ResourceController<Account, Tracker>
809where
810 Tracker: AsMut<ResourceTracker>,
811{
812 pub fn track_block_size_of(&mut self, data: &impl Serialize) -> Result<(), ExecutionError> {
814 self.track_block_size(bcs::serialized_size(data)?)
815 }
816
817 pub fn track_block_size(&mut self, size: usize) -> Result<(), ExecutionError> {
819 let tracker = self.tracker.as_mut();
820 tracker.block_size = u64::try_from(size)
821 .ok()
822 .and_then(|size| tracker.block_size.checked_add(size))
823 .ok_or(ExecutionError::BlockTooLarge)?;
824 ensure!(
825 tracker.block_size <= self.policy.maximum_block_size,
826 ExecutionError::BlockTooLarge
827 );
828 Ok(())
829 }
830}
831
832impl ResourceController<Option<AccountOwner>, ResourceTracker> {
833 pub async fn with_state<'a, C>(
836 &mut self,
837 view: &'a mut SystemExecutionStateView<C>,
838 ) -> Result<ResourceController<Sources<'a>, &mut ResourceTracker>, ViewError>
839 where
840 C: Context + Clone + 'static,
841 {
842 self.with_state_and_grant(view, None).await
843 }
844
845 pub async fn with_state_and_grant<'a, C>(
849 &mut self,
850 view: &'a mut SystemExecutionStateView<C>,
851 grant: Option<&'a mut Amount>,
852 ) -> Result<ResourceController<Sources<'a>, &mut ResourceTracker>, ViewError>
853 where
854 C: Context + Clone + 'static,
855 {
856 let mut sources = Vec::new();
857 if let Some(grant) = grant {
860 sources.push(grant);
861 } else {
862 sources.push(view.balance.get_mut());
863 }
864 if let Some(owner) = &self.account {
867 if let Some(balance) = view.balances.get_mut(owner).await? {
868 sources.push(balance);
869 }
870 }
871
872 Ok(ResourceController {
873 policy: self.policy.clone(),
874 tracker: &mut self.tracker,
875 account: Sources { sources },
876 is_free: self.is_free,
877 })
878 }
879}
880
881impl BalanceHolder for Amount {
883 fn balance(&self) -> Result<Amount, ArithmeticError> {
884 Ok(*self)
885 }
886
887 fn try_add_assign(&mut self, other: Amount) -> Result<(), ArithmeticError> {
888 self.try_add_assign(other)
889 }
890
891 fn try_sub_assign(&mut self, other: Amount) -> Result<(), ArithmeticError> {
892 self.try_sub_assign(other)
893 }
894}
895
896impl AsMut<ResourceTracker> for ResourceTracker {
899 fn as_mut(&mut self) -> &mut Self {
900 self
901 }
902}
903
904impl AsRef<ResourceTracker> for ResourceTracker {
905 fn as_ref(&self) -> &Self {
906 self
907 }
908}
909
910pub struct Sources<'a> {
912 sources: Vec<&'a mut Amount>,
913}
914
915impl BalanceHolder for Sources<'_> {
916 fn balance(&self) -> Result<Amount, ArithmeticError> {
917 let mut amount = Amount::ZERO;
918 for source in &self.sources {
919 amount.try_add_assign(**source)?;
920 }
921 Ok(amount)
922 }
923
924 fn try_add_assign(&mut self, other: Amount) -> Result<(), ArithmeticError> {
925 let source = self.sources.last_mut().expect("at least one source");
928 source.try_add_assign(other)
929 }
930
931 fn try_sub_assign(&mut self, mut other: Amount) -> Result<(), ArithmeticError> {
932 for source in &mut self.sources {
933 if source.try_sub_assign(other).is_ok() {
934 return Ok(());
935 }
936 other.try_sub_assign(**source).expect("*source < other");
937 **source = Amount::ZERO;
938 }
939 if other > Amount::ZERO {
940 Err(ArithmeticError::Underflow)
941 } else {
942 Ok(())
943 }
944 }
945}