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