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 bytes_stored: i32,
178 pub operations: u32,
180 pub operation_bytes: u64,
182 pub messages: u32,
184 pub message_bytes: u64,
186 pub http_requests: u32,
188 pub service_oracle_queries: u32,
190 pub service_oracle_execution: Duration,
192 pub grants: Amount,
194}
195
196impl ResourceTracker {
197 fn fuel(&self, vm_runtime: VmRuntime) -> u64 {
198 match vm_runtime {
199 VmRuntime::Wasm => self.wasm_fuel,
200 VmRuntime::Evm => self.evm_fuel,
201 }
202 }
203}
204
205impl fmt::Display for ResourceTracker {
206 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
207 let mut lines = Vec::new();
208
209 let mut block_parts = Vec::new();
210 if self.block_size != 0 {
211 block_parts.push(format!("size={}", self.block_size));
212 }
213 if self.operations != 0 {
214 block_parts.push(format!("operations={}", self.operations));
215 }
216 if self.operation_bytes != 0 {
217 block_parts.push(format!("operation_bytes={}", self.operation_bytes));
218 }
219 if !block_parts.is_empty() {
220 lines.push(format!("block: {}", block_parts.join(", ")));
221 }
222
223 let mut fuel_parts = Vec::new();
224 if self.wasm_fuel != 0 {
225 fuel_parts.push(format!("wasm={}", self.wasm_fuel));
226 }
227 if self.evm_fuel != 0 {
228 fuel_parts.push(format!("evm={}", self.evm_fuel));
229 }
230 if !fuel_parts.is_empty() {
231 lines.push(format!("fuel: {}", fuel_parts.join(", ")));
232 }
233
234 let mut storage_parts = Vec::new();
235 if self.read_operations != 0 {
236 storage_parts.push(format!("reads={}", self.read_operations));
237 }
238 if self.write_operations != 0 {
239 storage_parts.push(format!("writes={}", self.write_operations));
240 }
241 if self.bytes_runtime != 0 {
242 storage_parts.push(format!("runtime_bytes={}", self.bytes_runtime));
243 }
244 if self.bytes_read != 0 {
245 storage_parts.push(format!("bytes_read={}", self.bytes_read));
246 }
247 if self.bytes_written != 0 {
248 storage_parts.push(format!("bytes_written={}", self.bytes_written));
249 }
250 if self.bytes_stored != 0 {
251 storage_parts.push(format!("bytes_stored={}", self.bytes_stored));
252 }
253 if !storage_parts.is_empty() {
254 lines.push(format!("storage: {}", storage_parts.join(", ")));
255 }
256
257 let mut blob_parts = Vec::new();
258 if self.blobs_read != 0 {
259 blob_parts.push(format!("read={}", self.blobs_read));
260 }
261 if self.blobs_published != 0 {
262 blob_parts.push(format!("published={}", self.blobs_published));
263 }
264 if self.blob_bytes_read != 0 {
265 blob_parts.push(format!("bytes_read={}", self.blob_bytes_read));
266 }
267 if self.blob_bytes_published != 0 {
268 blob_parts.push(format!("bytes_published={}", self.blob_bytes_published));
269 }
270 if !blob_parts.is_empty() {
271 lines.push(format!("blobs: {}", blob_parts.join(", ")));
272 }
273
274 let mut message_parts = Vec::new();
275 if self.messages != 0 {
276 message_parts.push(format!("count={}", self.messages));
277 }
278 if self.message_bytes != 0 {
279 message_parts.push(format!("bytes={}", self.message_bytes));
280 }
281 if self.grants != Amount::ZERO {
282 message_parts.push(format!("grants={}", self.grants));
283 }
284 if !message_parts.is_empty() {
285 lines.push(format!("messages: {}", message_parts.join(", ")));
286 }
287
288 let mut http_service_parts = Vec::new();
289 if self.http_requests != 0 {
290 http_service_parts.push(format!("http_requests={}", self.http_requests));
291 }
292 if self.service_oracle_queries != 0 {
293 http_service_parts.push(format!("service_queries={}", self.service_oracle_queries));
294 }
295 if self.service_oracle_execution != Duration::ZERO {
296 http_service_parts.push(format!(
297 "service_execution={:?}",
298 self.service_oracle_execution
299 ));
300 }
301 if !http_service_parts.is_empty() {
302 lines.push(format!("http/service: {}", http_service_parts.join(", ")));
303 }
304
305 let mut lines_iter = lines.into_iter();
306 if let Some(first) = lines_iter.next() {
307 write!(f, "{}", first)?;
308 for line in lines_iter {
309 write!(f, "\n {}", line)?;
310 }
311 }
312
313 Ok(())
314 }
315}
316
317pub trait BalanceHolder {
319 fn balance(&self) -> Result<Amount, ArithmeticError>;
320
321 fn try_add_assign(&mut self, other: Amount) -> Result<(), ArithmeticError>;
322
323 fn try_sub_assign(&mut self, other: Amount) -> Result<(), ArithmeticError>;
324}
325
326impl<Account, Tracker> ResourceController<Account, Tracker>
328where
329 Account: BalanceHolder,
330 Tracker: AsRef<ResourceTracker> + AsMut<ResourceTracker>,
331{
332 pub fn balance(&self) -> Result<Amount, ArithmeticError> {
335 self.account.balance()
336 }
337
338 pub fn merge_balance(&mut self, initial: Amount, other: Amount) -> Result<(), ExecutionError> {
341 if other <= initial {
342 let sub_amount = initial.try_sub(other).expect("other <= initial");
343 self.account.try_sub_assign(sub_amount).map_err(|_| {
344 ExecutionError::FeesExceedFunding {
345 fees: sub_amount,
346 balance: self.balance().unwrap_or(Amount::MAX),
347 }
348 })?;
349 } else {
350 self.account
351 .try_add_assign(other.try_sub(initial).expect("other > initial"))?;
352 }
353 Ok(())
354 }
355
356 fn update_balance(&mut self, fees: Amount) -> Result<(), ExecutionError> {
359 if self.is_free {
360 return Ok(());
361 }
362 self.account
363 .try_sub_assign(fees)
364 .map_err(|_| ExecutionError::FeesExceedFunding {
365 fees,
366 balance: self.balance().unwrap_or(Amount::MAX),
367 })?;
368 Ok(())
369 }
370
371 pub(crate) fn remaining_fuel(&self, vm_runtime: VmRuntime) -> u64 {
373 let fuel = self.tracker.as_ref().fuel(vm_runtime);
374 let maximum_fuel_per_block = self.policy.maximum_fuel_per_block(vm_runtime);
375 if self.is_free {
376 return maximum_fuel_per_block.saturating_sub(fuel);
377 }
378 let balance = self.balance().unwrap_or(Amount::MAX);
379 self.policy
380 .remaining_fuel(balance, vm_runtime)
381 .min(maximum_fuel_per_block.saturating_sub(fuel))
382 }
383
384 pub fn track_grant(&mut self, grant: Amount) -> Result<(), ExecutionError> {
386 self.tracker.as_mut().grants.try_add_assign(grant)?;
387 self.update_balance(grant)
388 }
389
390 pub fn track_operation(&mut self, operation: &Operation) -> Result<(), ExecutionError> {
392 self.tracker.as_mut().operations = self
393 .tracker
394 .as_mut()
395 .operations
396 .checked_add(1)
397 .ok_or(ArithmeticError::Overflow)?;
398 self.update_balance(self.policy.operation)?;
399 match operation {
400 Operation::System(_) => Ok(()),
401 Operation::User { bytes, .. } => {
402 let size = bytes.len();
403 self.tracker.as_mut().operation_bytes = self
404 .tracker
405 .as_mut()
406 .operation_bytes
407 .checked_add(size as u64)
408 .ok_or(ArithmeticError::Overflow)?;
409 self.update_balance(self.policy.operation_bytes_price(size as u64)?)?;
410 Ok(())
411 }
412 }
413 }
414
415 pub fn track_message(&mut self, message: &Message) -> Result<(), ExecutionError> {
417 self.tracker.as_mut().messages = self
418 .tracker
419 .as_mut()
420 .messages
421 .checked_add(1)
422 .ok_or(ArithmeticError::Overflow)?;
423 self.update_balance(self.policy.message)?;
424 match message {
425 Message::System(_) => Ok(()),
426 Message::User { bytes, .. } => {
427 let size = bytes.len();
428 self.tracker.as_mut().message_bytes = self
429 .tracker
430 .as_mut()
431 .message_bytes
432 .checked_add(size as u64)
433 .ok_or(ArithmeticError::Overflow)?;
434 self.update_balance(self.policy.message_bytes_price(size as u64)?)?;
435 Ok(())
436 }
437 }
438 }
439
440 pub fn track_http_request(&mut self) -> Result<(), ExecutionError> {
442 self.tracker.as_mut().http_requests = self
443 .tracker
444 .as_ref()
445 .http_requests
446 .checked_add(1)
447 .ok_or(ArithmeticError::Overflow)?;
448 self.update_balance(self.policy.http_request)
449 }
450
451 pub(crate) fn track_fuel(
453 &mut self,
454 fuel: u64,
455 vm_runtime: VmRuntime,
456 ) -> Result<(), ExecutionError> {
457 match vm_runtime {
458 VmRuntime::Wasm => {
459 self.tracker.as_mut().wasm_fuel = self
460 .tracker
461 .as_ref()
462 .wasm_fuel
463 .checked_add(fuel)
464 .ok_or(ArithmeticError::Overflow)?;
465 ensure!(
466 self.tracker.as_ref().wasm_fuel <= self.policy.maximum_wasm_fuel_per_block,
467 ExecutionError::MaximumFuelExceeded(vm_runtime)
468 );
469 }
470 VmRuntime::Evm => {
471 self.tracker.as_mut().evm_fuel = self
472 .tracker
473 .as_ref()
474 .evm_fuel
475 .checked_add(fuel)
476 .ok_or(ArithmeticError::Overflow)?;
477 ensure!(
478 self.tracker.as_ref().evm_fuel <= self.policy.maximum_evm_fuel_per_block,
479 ExecutionError::MaximumFuelExceeded(vm_runtime)
480 );
481 }
482 }
483 self.update_balance(self.policy.fuel_price(fuel, vm_runtime)?)
484 }
485
486 pub(crate) fn track_runtime_chain_id(&mut self) -> Result<(), ExecutionError> {
488 self.track_size_runtime_operations(RUNTIME_CHAIN_ID_SIZE)
489 }
490
491 pub(crate) fn track_runtime_block_height(&mut self) -> Result<(), ExecutionError> {
493 self.track_size_runtime_operations(RUNTIME_BLOCK_HEIGHT_SIZE)
494 }
495
496 pub(crate) fn track_runtime_application_id(&mut self) -> Result<(), ExecutionError> {
498 self.track_size_runtime_operations(RUNTIME_APPLICATION_ID_SIZE)
499 }
500
501 pub(crate) fn track_runtime_application_parameters(
503 &mut self,
504 parameters: &[u8],
505 ) -> Result<(), ExecutionError> {
506 let parameters_len = parameters.len() as u32;
507 self.track_size_runtime_operations(parameters_len)
508 }
509
510 pub(crate) fn track_runtime_timestamp(&mut self) -> Result<(), ExecutionError> {
512 self.track_size_runtime_operations(RUNTIME_TIMESTAMP_SIZE)
513 }
514
515 pub(crate) fn track_runtime_balance(&mut self) -> Result<(), ExecutionError> {
517 self.track_size_runtime_operations(RUNTIME_AMOUNT_SIZE)
518 }
519
520 pub(crate) fn track_runtime_owner_balances(
522 &mut self,
523 owner_balances: &[(AccountOwner, Amount)],
524 ) -> Result<(), ExecutionError> {
525 let mut size = 0;
526 for (account_owner, _) in owner_balances {
527 size += account_owner.size() + RUNTIME_AMOUNT_SIZE;
528 }
529 self.track_size_runtime_operations(size)
530 }
531
532 pub(crate) fn track_runtime_owners(
534 &mut self,
535 owners: &[AccountOwner],
536 ) -> Result<(), ExecutionError> {
537 let mut size = 0;
538 for owner in owners {
539 size += owner.size();
540 }
541 self.track_size_runtime_operations(size)
542 }
543
544 pub(crate) fn track_runtime_chain_ownership(
546 &mut self,
547 chain_ownership: &ChainOwnership,
548 ) -> Result<(), ExecutionError> {
549 let mut size = 0;
550 for account_owner in &chain_ownership.super_owners {
551 size += account_owner.size();
552 }
553 for account_owner in chain_ownership.owners.keys() {
554 size += account_owner.size() + RUNTIME_OWNER_WEIGHT_SIZE;
555 }
556 size += RUNTIME_CONSTANT_CHAIN_OWNERSHIP_SIZE;
557 self.track_size_runtime_operations(size)
558 }
559
560 pub(crate) fn track_runtime_application_description(
562 &mut self,
563 description: &ApplicationDescription,
564 ) -> Result<(), ExecutionError> {
565 let parameters_size = description.parameters.len() as u32;
566 let required_apps_size =
567 description.required_application_ids.len() as u32 * RUNTIME_APPLICATION_ID_SIZE;
568 let size =
569 RUNTIME_CONSTANT_APPLICATION_DESCRIPTION_SIZE + parameters_size + required_apps_size;
570 self.track_size_runtime_operations(size)
571 }
572
573 fn track_size_runtime_operations(&mut self, size: u32) -> Result<(), ExecutionError> {
575 self.tracker.as_mut().bytes_runtime = self
576 .tracker
577 .as_mut()
578 .bytes_runtime
579 .checked_add(size)
580 .ok_or(ArithmeticError::Overflow)?;
581 self.update_balance(self.policy.bytes_runtime_price(size)?)
582 }
583
584 pub(crate) fn track_read_operation(&mut self) -> Result<(), ExecutionError> {
586 self.tracker.as_mut().read_operations = self
587 .tracker
588 .as_mut()
589 .read_operations
590 .checked_add(1)
591 .ok_or(ArithmeticError::Overflow)?;
592 self.update_balance(self.policy.read_operations_price(1)?)
593 }
594
595 pub(crate) fn track_write_operations(&mut self, count: u32) -> Result<(), ExecutionError> {
597 self.tracker.as_mut().write_operations = self
598 .tracker
599 .as_mut()
600 .write_operations
601 .checked_add(count)
602 .ok_or(ArithmeticError::Overflow)?;
603 self.update_balance(self.policy.write_operations_price(count)?)
604 }
605
606 pub(crate) fn track_bytes_read(&mut self, count: u64) -> Result<(), ExecutionError> {
608 self.tracker.as_mut().bytes_read = self
609 .tracker
610 .as_mut()
611 .bytes_read
612 .checked_add(count)
613 .ok_or(ArithmeticError::Overflow)?;
614 if self.tracker.as_mut().bytes_read >= self.policy.maximum_bytes_read_per_block {
615 return Err(ExecutionError::ExcessiveRead);
616 }
617 self.update_balance(self.policy.bytes_read_price(count)?)?;
618 Ok(())
619 }
620
621 pub(crate) fn track_bytes_written(&mut self, count: u64) -> Result<(), ExecutionError> {
623 self.tracker.as_mut().bytes_written = self
624 .tracker
625 .as_mut()
626 .bytes_written
627 .checked_add(count)
628 .ok_or(ArithmeticError::Overflow)?;
629 if self.tracker.as_mut().bytes_written >= self.policy.maximum_bytes_written_per_block {
630 return Err(ExecutionError::ExcessiveWrite);
631 }
632 self.update_balance(self.policy.bytes_written_price(count)?)?;
633 Ok(())
634 }
635
636 pub(crate) fn track_blob_read(&mut self, count: u64) -> Result<(), ExecutionError> {
638 {
639 let tracker = self.tracker.as_mut();
640 tracker.blob_bytes_read = tracker
641 .blob_bytes_read
642 .checked_add(count)
643 .ok_or(ArithmeticError::Overflow)?;
644 tracker.blobs_read = tracker
645 .blobs_read
646 .checked_add(1)
647 .ok_or(ArithmeticError::Overflow)?;
648 }
649 self.update_balance(self.policy.blob_read_price(count)?)?;
650 Ok(())
651 }
652
653 pub fn track_blob_published(&mut self, blob: &Blob) -> Result<(), ExecutionError> {
655 self.policy.check_blob_size(blob.content())?;
656 let size = blob.content().bytes().len() as u64;
657 if blob.is_committee_blob() {
658 return Ok(());
659 }
660 {
661 let tracker = self.tracker.as_mut();
662 tracker.blob_bytes_published = tracker
663 .blob_bytes_published
664 .checked_add(size)
665 .ok_or(ArithmeticError::Overflow)?;
666 tracker.blobs_published = tracker
667 .blobs_published
668 .checked_add(1)
669 .ok_or(ArithmeticError::Overflow)?;
670 }
671 self.update_balance(self.policy.blob_published_price(size)?)?;
672 Ok(())
673 }
674
675 #[allow(dead_code)]
678 pub(crate) fn track_stored_bytes(&mut self, delta: i32) -> Result<(), ExecutionError> {
679 self.tracker.as_mut().bytes_stored = self
680 .tracker
681 .as_mut()
682 .bytes_stored
683 .checked_add(delta)
684 .ok_or(ArithmeticError::Overflow)?;
685 Ok(())
686 }
687
688 pub(crate) fn remaining_service_oracle_execution_time(
690 &self,
691 ) -> Result<Duration, ExecutionError> {
692 let tracker = self.tracker.as_ref();
693 let spent_execution_time = tracker.service_oracle_execution;
694 let limit = Duration::from_millis(self.policy.maximum_service_oracle_execution_ms);
695
696 limit
697 .checked_sub(spent_execution_time)
698 .ok_or(ExecutionError::MaximumServiceOracleExecutionTimeExceeded)
699 }
700
701 pub(crate) fn track_service_oracle_call(&mut self) -> Result<(), ExecutionError> {
703 self.tracker.as_mut().service_oracle_queries = self
704 .tracker
705 .as_mut()
706 .service_oracle_queries
707 .checked_add(1)
708 .ok_or(ArithmeticError::Overflow)?;
709 self.update_balance(self.policy.service_as_oracle_query)
710 }
711
712 pub(crate) fn track_service_oracle_execution(
714 &mut self,
715 execution_time: Duration,
716 ) -> Result<(), ExecutionError> {
717 let tracker = self.tracker.as_mut();
718 let spent_execution_time = &mut tracker.service_oracle_execution;
719 let limit = Duration::from_millis(self.policy.maximum_service_oracle_execution_ms);
720
721 *spent_execution_time = spent_execution_time.saturating_add(execution_time);
722
723 ensure!(
724 *spent_execution_time < limit,
725 ExecutionError::MaximumServiceOracleExecutionTimeExceeded
726 );
727
728 Ok(())
729 }
730
731 pub(crate) fn track_service_oracle_response(
733 &mut self,
734 response_bytes: usize,
735 ) -> Result<(), ExecutionError> {
736 ensure!(
737 response_bytes as u64 <= self.policy.maximum_oracle_response_bytes,
738 ExecutionError::ServiceOracleResponseTooLarge
739 );
740
741 Ok(())
742 }
743}
744
745impl<Account, Tracker> ResourceController<Account, Tracker>
746where
747 Tracker: AsMut<ResourceTracker>,
748{
749 pub fn track_block_size_of(&mut self, data: &impl Serialize) -> Result<(), ExecutionError> {
751 self.track_block_size(bcs::serialized_size(data)?)
752 }
753
754 pub fn track_block_size(&mut self, size: usize) -> Result<(), ExecutionError> {
756 let tracker = self.tracker.as_mut();
757 tracker.block_size = u64::try_from(size)
758 .ok()
759 .and_then(|size| tracker.block_size.checked_add(size))
760 .ok_or(ExecutionError::BlockTooLarge)?;
761 ensure!(
762 tracker.block_size <= self.policy.maximum_block_size,
763 ExecutionError::BlockTooLarge
764 );
765 Ok(())
766 }
767}
768
769impl ResourceController<Option<AccountOwner>, ResourceTracker> {
770 pub async fn with_state<'a, C>(
773 &mut self,
774 view: &'a mut SystemExecutionStateView<C>,
775 ) -> Result<ResourceController<Sources<'a>, &mut ResourceTracker>, ViewError>
776 where
777 C: Context + Clone + 'static,
778 {
779 self.with_state_and_grant(view, None).await
780 }
781
782 pub async fn with_state_and_grant<'a, C>(
786 &mut self,
787 view: &'a mut SystemExecutionStateView<C>,
788 grant: Option<&'a mut Amount>,
789 ) -> Result<ResourceController<Sources<'a>, &mut ResourceTracker>, ViewError>
790 where
791 C: Context + Clone + 'static,
792 {
793 let mut sources = Vec::new();
794 if let Some(grant) = grant {
797 sources.push(grant);
798 } else {
799 sources.push(view.balance.get_mut());
800 }
801 if let Some(owner) = &self.account {
804 if let Some(balance) = view.balances.get_mut(owner).await? {
805 sources.push(balance);
806 }
807 }
808
809 Ok(ResourceController {
810 policy: self.policy.clone(),
811 tracker: &mut self.tracker,
812 account: Sources { sources },
813 is_free: self.is_free,
814 })
815 }
816}
817
818impl BalanceHolder for Amount {
820 fn balance(&self) -> Result<Amount, ArithmeticError> {
821 Ok(*self)
822 }
823
824 fn try_add_assign(&mut self, other: Amount) -> Result<(), ArithmeticError> {
825 self.try_add_assign(other)
826 }
827
828 fn try_sub_assign(&mut self, other: Amount) -> Result<(), ArithmeticError> {
829 self.try_sub_assign(other)
830 }
831}
832
833impl AsMut<ResourceTracker> for ResourceTracker {
836 fn as_mut(&mut self) -> &mut Self {
837 self
838 }
839}
840
841impl AsRef<ResourceTracker> for ResourceTracker {
842 fn as_ref(&self) -> &Self {
843 self
844 }
845}
846
847pub struct Sources<'a> {
849 sources: Vec<&'a mut Amount>,
850}
851
852impl BalanceHolder for Sources<'_> {
853 fn balance(&self) -> Result<Amount, ArithmeticError> {
854 let mut amount = Amount::ZERO;
855 for source in &self.sources {
856 amount.try_add_assign(**source)?;
857 }
858 Ok(amount)
859 }
860
861 fn try_add_assign(&mut self, other: Amount) -> Result<(), ArithmeticError> {
862 let source = self.sources.last_mut().expect("at least one source");
865 source.try_add_assign(other)
866 }
867
868 fn try_sub_assign(&mut self, mut other: Amount) -> Result<(), ArithmeticError> {
869 for source in &mut self.sources {
870 if source.try_sub_assign(other).is_ok() {
871 return Ok(());
872 }
873 other.try_sub_assign(**source).expect("*source < other");
874 **source = Amount::ZERO;
875 }
876 if other > Amount::ZERO {
877 Err(ArithmeticError::Underflow)
878 } else {
879 Ok(())
880 }
881 }
882}