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