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