1use super::*;
20use crate::storage::MapStorage;
21
22#[derive(Debug, Clone, Copy)]
24enum CatchValueOutput<Balance> {
25 Blocked,
27 Missed,
31 Caught(Balance),
33}
34
35impl<Balance: BalanceTrait> CatchValueOutput<Balance> {
36 fn into_consume_output<ExternalId, Funds>(
37 self,
38 origin: ExternalId,
39 multiplier: GasMultiplier<Funds, Balance>,
40 ) -> Option<(
41 NegativeImbalance<Balance>,
42 GasMultiplier<Funds, Balance>,
43 ExternalId,
44 )> {
45 match self {
46 CatchValueOutput::Caught(value) => {
47 Some((NegativeImbalance::new(value), multiplier, origin))
48 }
49 _ => None,
50 }
51 }
52
53 fn is_blocked(&self) -> bool {
54 matches!(self, CatchValueOutput::Blocked)
55 }
56
57 fn is_caught(&self) -> bool {
58 matches!(self, CatchValueOutput::Caught(_))
59 }
60}
61
62pub struct TreeImpl<TotalValue, InternalError, Error, ExternalId, NodeId, StorageMap>(
63 PhantomData<(
64 TotalValue,
65 InternalError,
66 Error,
67 ExternalId,
68 NodeId,
69 StorageMap,
70 )>,
71);
72
73impl<TotalValue, Balance, Funds, InternalError, Error, ExternalId, NodeId, StorageMap>
74 TreeImpl<TotalValue, InternalError, Error, ExternalId, NodeId, StorageMap>
75where
76 Balance: BalanceTrait,
77 Funds: Clone,
78 TotalValue: ValueStorage<Value = Balance>,
79 InternalError: super::Error,
80 Error: From<InternalError>,
81 ExternalId: Clone,
82 NodeId: Copy,
83 StorageMap: MapStorage<Key = NodeId, Value = GasNode<ExternalId, NodeId, Balance, Funds>>,
84{
85 pub(super) fn get_node(key: impl Into<NodeId>) -> Option<StorageMap::Value> {
86 StorageMap::get(&key.into())
87 }
88
89 pub(super) fn node_with_value(
99 node: StorageMap::Value,
100 ) -> Result<(StorageMap::Value, Option<NodeId>), Error> {
101 let mut ret_node = node;
102 let mut ret_id = None;
103 if let GasNode::UnspecifiedLocal { parent, .. } = ret_node {
104 ret_id = Some(parent);
105 ret_node = Self::get_node(parent).ok_or_else(InternalError::parent_is_lost)?;
106 if !(ret_node.is_external() || ret_node.is_specified_local() || ret_node.is_reserved())
107 {
108 return Err(InternalError::unexpected_node_type().into());
109 }
110 }
111
112 Ok((ret_node, ret_id))
113 }
114
115 pub(super) fn decrease_parents_ref(node: &StorageMap::Value) -> Result<(), Error> {
116 let id = match node.parent() {
117 Some(id) => id,
118 None => return Ok(()),
119 };
120
121 let mut parent = Self::get_node(id).ok_or_else(InternalError::parent_is_lost)?;
122 if parent.refs() == 0 {
123 return Err(InternalError::parent_has_no_children().into());
124 }
125
126 match node {
127 GasNode::SpecifiedLocal { .. } => {
128 parent.decrease_spec_refs();
129 }
130 GasNode::UnspecifiedLocal { .. } => {
131 parent.decrease_unspec_refs();
132 }
133 _ => return Err(InternalError::unexpected_node_type().into()),
134 }
135
136 StorageMap::insert(id, parent);
138
139 Ok(())
140 }
141
142 fn catch_value(node: &mut StorageMap::Value) -> Result<CatchValueOutput<Balance>, Error> {
156 if node.is_patron() {
157 return Ok(CatchValueOutput::Blocked);
158 }
159
160 if !node.is_unspecified_local() {
161 if let Some((mut patron, patron_id)) = Self::find_ancestor_patron(node)? {
162 let self_value = node
163 .value_mut()
164 .ok_or_else(InternalError::unexpected_node_type)?;
165 if self_value.is_zero() {
166 return Ok(CatchValueOutput::Missed);
168 }
169 let patron_value = patron
170 .value_mut()
171 .ok_or_else(InternalError::unexpected_node_type)?;
172 *patron_value = patron_value.saturating_add(*self_value);
173 *self_value = Zero::zero();
174 StorageMap::insert(patron_id, patron);
175
176 Ok(CatchValueOutput::Missed)
177 } else {
178 let self_value = node
179 .value_mut()
180 .ok_or_else(InternalError::unexpected_node_type)?;
181 let value_copy = *self_value;
182 *self_value = Zero::zero();
183
184 Ok(CatchValueOutput::Caught(value_copy))
185 }
186 } else {
187 Ok(CatchValueOutput::Blocked)
188 }
189 }
190
191 #[allow(clippy::type_complexity)]
200 fn find_ancestor_patron(
201 node: &StorageMap::Value,
202 ) -> Result<Option<(StorageMap::Value, NodeId)>, Error> {
203 match node {
204 GasNode::External { .. } | GasNode::Cut { .. } | GasNode::Reserved { .. } => Ok(None),
205 GasNode::SpecifiedLocal { parent, .. } => {
206 let mut ret_id = *parent;
207 let mut ret_node =
208 Self::get_node(*parent).ok_or_else(InternalError::parent_is_lost)?;
209 while !ret_node.is_patron() {
210 match ret_node {
211 GasNode::External { .. } | GasNode::Reserved { .. } => return Ok(None),
212 GasNode::SpecifiedLocal { parent, .. } => {
213 ret_id = parent;
214 ret_node =
215 Self::get_node(parent).ok_or_else(InternalError::parent_is_lost)?;
216 }
217 _ => return Err(InternalError::unexpected_node_type().into()),
218 }
219 }
220 Ok(Some((ret_node, ret_id)))
221 }
222 GasNode::UnspecifiedLocal { .. } => Err(InternalError::forbidden().into()),
225 }
226 }
227
228 fn try_remove_consumed_ancestors(
281 key: NodeId,
282 descendant_catch_output: CatchValueOutput<Balance>,
283 ) -> ConsumeResultOf<Self> {
284 let mut node_id = key;
285
286 let mut node = Self::get_node(key).ok_or_else(InternalError::node_not_found)?;
287 let mut consume_output = None;
288 let (external, multiplier, _) = Self::get_origin_node(key)?;
289
290 let mut catch_output = if descendant_catch_output.is_caught() {
301 CatchValueOutput::Caught(Zero::zero())
302 } else {
303 descendant_catch_output
304 };
305 while !node.is_patron() {
306 if catch_output.is_blocked() {
307 catch_output = Self::catch_value(&mut node)?;
308 }
309
310 if catch_output.is_blocked() {
312 return Err(InternalError::value_is_blocked().into());
313 }
314
315 consume_output = consume_output
316 .or_else(|| catch_output.into_consume_output(external.clone(), multiplier.clone()));
317
318 if node.spec_refs() == 0 {
319 Self::decrease_parents_ref(&node)?;
320 StorageMap::remove(node_id);
321
322 match node {
323 GasNode::External { .. } | GasNode::Reserved { .. } => {
324 if !catch_output.is_caught() {
325 return Err(InternalError::value_is_not_caught().into());
326 }
327 return Ok(consume_output);
328 }
329 GasNode::SpecifiedLocal { parent, .. } => {
330 node_id = parent;
331 node = Self::get_node(parent).ok_or_else(InternalError::parent_is_lost)?;
332 }
333 _ => return Err(InternalError::unexpected_node_type().into()),
334 }
335 } else {
336 StorageMap::insert(node_id, node);
337 return Ok(consume_output);
338 }
339 }
340
341 Ok(consume_output)
342 }
343
344 fn create_from_with_value(
346 key: impl Into<NodeId>,
347 new_node_key: impl Into<NodeId>,
348 amount: Balance,
349 constructor: impl FnOnce(
350 NodeId,
351 Balance,
352 &mut GasNode<ExternalId, NodeId, Balance, Funds>,
353 NodeId,
354 ) -> Result<GasNode<ExternalId, NodeId, Balance, Funds>, Error>,
355 ) -> Result<(), Error> {
356 let key = key.into();
357 let new_node_key = new_node_key.into();
358
359 if StorageMap::contains_key(&new_node_key) {
362 return Err(InternalError::node_already_exists().into());
363 }
364
365 let (mut node, node_id) =
366 Self::node_with_value(Self::get_node(key).ok_or_else(InternalError::node_not_found)?)?;
367 if node.is_cut() {
369 return Err(InternalError::forbidden().into());
370 }
371
372 if node
375 .value()
376 .ok_or_else(InternalError::unexpected_node_type)?
377 < amount
378 {
379 return Err(InternalError::insufficient_balance().into());
380 }
381
382 let node_id = node_id.unwrap_or(key);
383
384 let new_node = constructor(key, amount, &mut node, node_id)?;
385
386 StorageMap::insert(new_node_key, new_node);
388
389 let node_value = node
390 .value_mut()
391 .ok_or_else(InternalError::unexpected_node_type)?;
392
393 *node_value = node_value.saturating_sub(amount);
394
395 StorageMap::insert(node_id, node);
396
397 Ok(())
398 }
399
400 fn get_limit_node_impl(
402 key: impl Into<NodeId>,
403 validate: impl FnOnce(&GasNode<ExternalId, NodeId, Balance, Funds>) -> Result<(), Error>,
404 ) -> Result<(Balance, NodeId), Error> {
405 let key = key.into();
406
407 let node = Self::get_node(key).ok_or_else(InternalError::node_not_found)?;
408
409 validate(&node)?;
410
411 let (node_with_value, maybe_key) = Self::node_with_value(node)?;
412
413 let v = node_with_value
415 .value()
416 .ok_or_else(InternalError::unexpected_node_type)?;
417
418 Ok((v, maybe_key.unwrap_or(key)))
419 }
420}
421
422impl<TotalValue, Balance, Funds, InternalError, Error, ExternalId, NodeId, StorageMap> Tree
423 for TreeImpl<TotalValue, InternalError, Error, ExternalId, NodeId, StorageMap>
424where
425 Balance: BalanceTrait,
426 Funds: Clone,
427 TotalValue: ValueStorage<Value = Balance>,
428 InternalError: super::Error,
429 Error: From<InternalError>,
430 ExternalId: Clone,
431 NodeId: Copy,
432 StorageMap: MapStorage<Key = NodeId, Value = GasNode<ExternalId, NodeId, Balance, Funds>>,
433{
434 type ExternalOrigin = ExternalId;
435 type NodeId = NodeId;
436 type Balance = Balance;
437 type Funds = Funds;
438
439 type PositiveImbalance = PositiveImbalance<Balance>;
440 type NegativeImbalance = NegativeImbalance<Balance>;
441
442 type InternalError = InternalError;
443 type Error = Error;
444
445 fn total_supply() -> Self::Balance {
446 TotalValue::get().unwrap_or_else(Zero::zero)
447 }
448
449 fn create(
450 origin: Self::ExternalOrigin,
451 multiplier: GasMultiplier<Self::Funds, Self::Balance>,
452 key: impl Into<Self::NodeId>,
453 amount: Self::Balance,
454 ) -> Result<Self::PositiveImbalance, Self::Error> {
455 let key = key.into();
456
457 if StorageMap::contains_key(&key) {
458 return Err(InternalError::node_already_exists().into());
459 }
460
461 let node = GasNode::new(origin, multiplier, amount, false);
462
463 StorageMap::insert(key, node);
465
466 let positive_imbalance = PositiveImbalance::new(amount);
467
468 TotalValue::mutate(|total| {
470 positive_imbalance.apply_to(total).map_err(|_| {
471 *total = None;
472 InternalError::total_value_is_overflowed()
473 })
474 })?;
475
476 Ok(positive_imbalance)
477 }
478
479 fn get_origin_node(
480 key: impl Into<Self::NodeId>,
481 ) -> Result<OriginNodeDataOf<Self>, Self::Error> {
482 let key = key.into();
483 let node = Self::get_node(key).ok_or_else(InternalError::node_not_found)?;
484
485 if let Some((external_origin, multiplier)) = node.external_data() {
486 Ok((external_origin, multiplier, key))
487 } else {
488 let root_id = node
489 .root_id()
490 .unwrap_or_else(|| unreachable!("Guaranteed by GasNode::root_id() fn"));
491
492 let root_node = Self::get_node(root_id).ok_or_else(InternalError::node_not_found)?;
493
494 let (external_origin, multiplier) = root_node
495 .external_data()
496 .unwrap_or_else(|| unreachable!("Guaranteed by GasNode::root_id() fn"));
497 Ok((external_origin, multiplier, root_id))
498 }
499 }
500
501 fn get_limit_node(
502 key: impl Into<Self::NodeId>,
503 ) -> Result<(Self::Balance, Self::NodeId), Self::Error> {
504 let key = key.into();
505
506 Self::get_limit_node_impl(key, |node| {
507 if node.is_consumed() {
508 Err(InternalError::node_was_consumed().into())
509 } else {
510 Ok(())
511 }
512 })
513 }
514
515 fn get_limit_node_consumed(
516 key: impl Into<Self::NodeId>,
517 ) -> Result<(Self::Balance, Self::NodeId), Self::Error> {
518 let key = key.into();
519
520 Self::get_limit_node_impl(key, |node| {
521 if node.is_consumed() {
522 Ok(())
523 } else {
524 Err(InternalError::forbidden().into())
525 }
526 })
527 }
528
529 fn consume(key: impl Into<Self::NodeId>) -> ConsumeResultOf<Self> {
556 let key = key.into();
557 let mut node = Self::get_node(key).ok_or_else(InternalError::node_not_found)?;
558
559 #[cfg(fuzz)]
560 {
561 let s = fail::FailScenario::setup();
562 fail::fail_point!("fail_fuzzer", |_| {
566 Err(InternalError::node_already_exists().into())
570 });
571 s.teardown();
572 }
573
574 if node.is_consumed() {
575 return Err(InternalError::node_was_consumed().into());
576 }
577
578 if !node.lock().is_zero() {
580 return Err(InternalError::consumed_with_lock().into());
581 }
582
583 if let Some(system_reserve) = node.system_reserve()
584 && !system_reserve.is_zero()
585 {
586 return Err(InternalError::consumed_with_system_reservation().into());
587 }
588
589 node.mark_consumed();
590 let catch_output = Self::catch_value(&mut node)?;
591 let (external, multiplier, _) = Self::get_origin_node(key)?;
592
593 let res = if node.refs() == 0 {
594 Self::decrease_parents_ref(&node)?;
595 StorageMap::remove(key);
596
597 match node {
598 GasNode::External { .. } | GasNode::Cut { .. } | GasNode::Reserved { .. } => {
599 if !catch_output.is_caught() {
600 return Err(InternalError::value_is_not_caught().into());
601 }
602 catch_output.into_consume_output(external, multiplier)
603 }
604 GasNode::UnspecifiedLocal { parent, .. } => {
605 if !catch_output.is_blocked() {
606 return Err(InternalError::value_is_not_blocked().into());
607 }
608 Self::try_remove_consumed_ancestors(parent, catch_output)?
609 }
610 GasNode::SpecifiedLocal { parent, .. } => {
611 if catch_output.is_blocked() {
612 return Err(InternalError::value_is_blocked().into());
613 }
614 let consume_output = catch_output.into_consume_output(external, multiplier);
615 let consume_ancestors_output =
616 Self::try_remove_consumed_ancestors(parent, catch_output)?;
617 match (&consume_output, consume_ancestors_output) {
618 (Some(_), Some((neg_imb, ..))) if neg_imb.peek().is_zero() => {
620 consume_output
621 }
622 (None, None) => consume_output,
623 _ => return Err(InternalError::unexpected_consume_output().into()),
624 }
625 }
626 }
627 } else {
628 if node.is_cut() || node.is_unspecified_local() {
629 return Err(InternalError::unexpected_node_type().into());
630 }
631
632 StorageMap::insert(key, node);
633 catch_output.into_consume_output(external, multiplier)
634 };
635
636 if let Some((negative_imbalance, ..)) = res.as_ref() {
638 TotalValue::mutate(|total| {
639 negative_imbalance.apply_to(total).map_err(|_| {
640 *total = None;
641 InternalError::total_value_is_underflowed()
642 })
643 })?;
644 }
645
646 Ok(res)
647 }
648
649 fn spend(
656 key: impl Into<Self::NodeId>,
657 amount: Self::Balance,
658 ) -> Result<Self::NegativeImbalance, Self::Error> {
659 let key = key.into();
660
661 let (mut node, node_id) =
664 Self::node_with_value(Self::get_node(key).ok_or_else(InternalError::node_not_found)?)?;
665
666 let node_value = node
669 .value_mut()
670 .ok_or_else(InternalError::unexpected_node_type)?;
671
672 if *node_value < amount {
673 return Err(InternalError::insufficient_balance().into());
674 }
675
676 *node_value = node_value.saturating_sub(amount);
677 log::debug!("Spent {amount:?} of gas");
678
679 StorageMap::insert(node_id.unwrap_or(key), node);
681
682 let negative_imbalance = NegativeImbalance::new(amount);
683
684 TotalValue::mutate(|total| {
686 negative_imbalance.apply_to(total).map_err(|_| {
687 *total = None;
688 InternalError::total_value_is_underflowed()
689 })
690 })?;
691
692 Ok(negative_imbalance)
693 }
694
695 fn split_with_value(
696 key: impl Into<Self::NodeId>,
697 new_key: impl Into<Self::NodeId>,
698 amount: Self::Balance,
699 ) -> Result<(), Self::Error> {
700 Self::create_from_with_value(
701 key,
702 new_key,
703 amount,
704 |_key, value, parent_node, parent_id| {
705 parent_node.increase_spec_refs();
706
707 Ok(GasNode::SpecifiedLocal {
708 root: parent_node.root_id().unwrap_or(parent_id),
709 value,
710 lock: Zero::zero(),
711 system_reserve: Zero::zero(),
712 parent: parent_id,
713 refs: Default::default(),
714 consumed: false,
715 })
716 },
717 )
718 }
719
720 fn split(
721 key: impl Into<Self::NodeId>,
722 new_key: impl Into<Self::NodeId>,
723 ) -> Result<(), Self::Error> {
724 let key = key.into();
725 let new_key = new_key.into();
726
727 let (mut node, node_id) =
728 Self::node_with_value(Self::get_node(key).ok_or_else(InternalError::node_not_found)?)?;
729 let node_id = node_id.unwrap_or(key);
730
731 if node.is_cut() {
733 return Err(InternalError::forbidden().into());
734 }
735
736 if StorageMap::contains_key(&new_key) {
738 return Err(InternalError::node_already_exists().into());
739 }
740
741 node.increase_unspec_refs();
742
743 let new_node = GasNode::UnspecifiedLocal {
744 root: node.root_id().unwrap_or(node_id),
745 parent: node_id,
746 lock: Zero::zero(),
747 system_reserve: Zero::zero(),
748 };
749
750 StorageMap::insert(new_key, new_node);
752 StorageMap::insert(node_id, node);
754
755 Ok(())
756 }
757
758 fn cut(
759 key: impl Into<Self::NodeId>,
760 new_key: impl Into<Self::NodeId>,
761 amount: Self::Balance,
762 ) -> Result<(), Self::Error> {
763 Self::create_from_with_value(
764 key,
765 new_key,
766 amount,
767 |key, value, _parent_node, _parent_id| {
768 let (id, multiplier, _) = Self::get_origin_node(key)?;
769 Ok(GasNode::Cut {
770 id,
771 multiplier,
772 value,
773 lock: Zero::zero(),
774 })
775 },
776 )
777 }
778
779 fn create_deposit(
780 key: impl Into<Self::NodeId>,
781 new_key: impl Into<Self::NodeId>,
782 amount: Self::Balance,
783 ) -> Result<(), Self::Error> {
784 Self::create_from_with_value(
785 key,
786 new_key,
787 amount,
788 |key, value, _parent_node, _parent_id| {
789 let (id, multiplier, _) = Self::get_origin_node(key)?;
790 Ok(GasNode::new(id, multiplier, value, true))
791 },
792 )
793 }
794
795 fn exists(key: impl Into<Self::NodeId>) -> bool {
796 Self::get_node(key).is_some()
797 }
798
799 fn exists_and_deposit(key: impl Into<Self::NodeId>) -> bool {
800 Self::get_node(key)
801 .map(|node| matches!(node, GasNode::External { deposit: true, .. }))
802 .unwrap_or(false)
803 }
804
805 fn clear() {
806 TotalValue::kill();
807 StorageMap::clear();
808 }
809}
810
811impl<TotalValue, Balance, Funds, InternalError, Error, ExternalId, NodeId, StorageMap> LockableTree
812 for TreeImpl<TotalValue, InternalError, Error, ExternalId, NodeId, StorageMap>
813where
814 Balance: BalanceTrait,
815 Funds: Clone,
816 TotalValue: ValueStorage<Value = Balance>,
817 InternalError: super::Error,
818 Error: From<InternalError>,
819 ExternalId: Clone,
820 NodeId: Copy,
821 StorageMap: MapStorage<Key = NodeId, Value = GasNode<ExternalId, NodeId, Balance, Funds>>,
822{
823 fn lock(
824 key: impl Into<Self::NodeId>,
825 id: LockId,
826 amount: Self::Balance,
827 ) -> Result<(), Self::Error> {
828 let key = key.into();
829
830 let node = Self::get_node(key).ok_or_else(InternalError::node_not_found)?;
832
833 if node.is_consumed() {
835 return Err(InternalError::node_was_consumed().into());
836 }
837
838 if amount.is_zero() {
840 return Ok(());
841 }
842
843 let (mut ancestor_node, ancestor_id) = Self::node_with_value(node)?;
845
846 let ancestor_node_value = ancestor_node
848 .value_mut()
849 .ok_or_else(InternalError::unexpected_node_type)?;
850
851 if *ancestor_node_value < amount {
852 return Err(InternalError::insufficient_balance().into());
853 }
854
855 *ancestor_node_value = ancestor_node_value.saturating_sub(amount);
856
857 let mut node = if let Some(ancestor_id) = ancestor_id {
860 StorageMap::insert(ancestor_id, ancestor_node);
861
862 Self::get_node(key).ok_or_else(InternalError::node_not_found)?
864 } else {
865 ancestor_node
866 };
867
868 let locked = node.lock()[id];
869 node.lock_mut()[id] = locked.saturating_add(amount);
870
871 StorageMap::insert(key, node);
872
873 Ok(())
874 }
875
876 fn unlock(
889 key: impl Into<Self::NodeId>,
890 id: LockId,
891 amount: Self::Balance,
892 ) -> Result<(), Self::Error> {
893 let key = key.into();
894
895 let mut node = Self::get_node(key).ok_or_else(InternalError::node_not_found)?;
897
898 if node.is_consumed() {
900 return Err(InternalError::node_was_consumed().into());
901 }
902
903 if amount.is_zero() {
905 return Ok(());
906 }
907
908 let node_lock = &mut node.lock_mut()[id];
910 if *node_lock < amount {
911 return Err(InternalError::insufficient_balance().into());
912 }
913
914 *node_lock = node_lock.saturating_sub(amount);
915
916 let (ancestor_node, ancestor_id) = Self::node_with_value(node.clone())?;
918
919 let (mut ancestor_node, ancestor_id) = if let Some(ancestor_id) = ancestor_id {
923 StorageMap::insert(key, node);
924
925 (ancestor_node, ancestor_id)
926 } else {
927 (node, key)
928 };
929
930 let ancestor_value = ancestor_node
931 .value_mut()
932 .ok_or_else(InternalError::unexpected_node_type)?;
933
934 *ancestor_value = ancestor_value.saturating_add(amount);
935
936 StorageMap::insert(ancestor_id, ancestor_node);
937
938 Ok(())
939 }
940
941 fn get_lock(key: impl Into<Self::NodeId>, id: LockId) -> Result<Self::Balance, Self::Error> {
942 let key = key.into();
943 let node = Self::get_node(key).ok_or_else(InternalError::node_not_found)?;
944
945 Ok(node.lock()[id])
946 }
947}
948
949impl<TotalValue, Balance, Funds, InternalError, Error, ExternalId, NodeId, StorageMap>
950 ReservableTree for TreeImpl<TotalValue, InternalError, Error, ExternalId, NodeId, StorageMap>
951where
952 Balance: BalanceTrait,
953 Funds: Clone,
954 TotalValue: ValueStorage<Value = Balance>,
955 InternalError: super::Error,
956 Error: From<InternalError>,
957 ExternalId: Clone,
958 NodeId: Copy,
959 StorageMap: MapStorage<Key = NodeId, Value = GasNode<ExternalId, NodeId, Balance, Funds>>,
960{
961 fn reserve(
962 key: impl Into<Self::NodeId>,
963 new_key: impl Into<Self::NodeId>,
964 amount: Self::Balance,
965 ) -> Result<(), Self::Error> {
966 Self::create_from_with_value(
967 key,
968 new_key,
969 amount,
970 |key, value, _parent_node, _parent_id| {
971 let (id, multiplier, _) = Self::get_origin_node(key)?;
972 Ok(GasNode::Reserved {
973 id,
974 multiplier,
975 value,
976 lock: Zero::zero(),
977 refs: Default::default(),
978 consumed: false,
979 })
980 },
981 )
982 }
983
984 fn system_reserve(
985 key: impl Into<Self::NodeId>,
986 amount: Self::Balance,
987 ) -> Result<(), Self::Error> {
988 let key = key.into();
989
990 let node = Self::get_node(key).ok_or_else(InternalError::node_not_found)?;
992
993 if !node.is_system_reservable() {
995 return Err(InternalError::forbidden().into());
996 }
997
998 if node.is_consumed() {
1000 return Err(InternalError::node_was_consumed().into());
1001 }
1002
1003 if amount.is_zero() {
1005 return Ok(());
1006 }
1007
1008 let (mut ancestor_node, ancestor_id) = Self::node_with_value(node)?;
1010
1011 let ancestor_node_value = ancestor_node
1013 .value_mut()
1014 .ok_or_else(InternalError::unexpected_node_type)?;
1015
1016 if *ancestor_node_value < amount {
1017 return Err(InternalError::insufficient_balance().into());
1018 }
1019
1020 *ancestor_node_value = ancestor_node_value.saturating_sub(amount);
1021
1022 let mut node = if let Some(ancestor_id) = ancestor_id {
1025 StorageMap::insert(ancestor_id, ancestor_node);
1026
1027 Self::get_node(key).ok_or_else(InternalError::node_not_found)?
1029 } else {
1030 ancestor_node
1031 };
1032
1033 let system_reservation = node
1034 .system_reserve_mut()
1035 .ok_or_else(InternalError::unexpected_node_type)?;
1036
1037 *system_reservation = system_reservation.saturating_add(amount);
1038
1039 StorageMap::insert(key, node);
1040
1041 Ok(())
1042 }
1043
1044 fn system_unreserve(key: impl Into<Self::NodeId>) -> Result<Self::Balance, Self::Error> {
1045 let key = key.into();
1046
1047 let mut node = Self::get_node(key).ok_or_else(InternalError::node_not_found)?;
1049
1050 if !node.is_system_reservable() {
1052 return Err(InternalError::forbidden().into());
1053 }
1054
1055 if node.is_consumed() {
1057 return Err(InternalError::node_was_consumed().into());
1058 }
1059
1060 let amount = node
1061 .system_reserve()
1062 .ok_or_else(InternalError::unexpected_node_type)?;
1063
1064 if amount.is_zero() {
1066 return Ok(Zero::zero());
1067 }
1068
1069 let system_reservation = node
1071 .system_reserve_mut()
1072 .ok_or_else(InternalError::unexpected_node_type)?;
1073
1074 *system_reservation = Zero::zero();
1075
1076 let (ancestor_node, ancestor_id) = Self::node_with_value(node.clone())?;
1078
1079 let (mut ancestor_node, ancestor_id) = if let Some(ancestor_id) = ancestor_id {
1083 StorageMap::insert(key, node);
1084
1085 (ancestor_node, ancestor_id)
1086 } else {
1087 (node, key)
1088 };
1089
1090 let ancestor_value = ancestor_node
1091 .value_mut()
1092 .ok_or_else(InternalError::unexpected_node_type)?;
1093
1094 *ancestor_value = ancestor_value.saturating_add(amount);
1095
1096 StorageMap::insert(ancestor_id, ancestor_node);
1097
1098 Ok(amount)
1099 }
1100
1101 fn get_system_reserve(key: impl Into<Self::NodeId>) -> Result<Self::Balance, Self::Error> {
1102 let node = Self::get_node(key).ok_or_else(InternalError::node_not_found)?;
1103
1104 node.system_reserve()
1105 .ok_or_else(|| InternalError::forbidden().into())
1106 }
1107}