1use crate::{
21	storage::ContractInfo, AccountIdOf, BalanceOf, CodeInfo, Config, Error, Event, HoldReason,
22	Inspect, Origin, Pallet, StorageDeposit as Deposit, System, LOG_TARGET,
23};
24
25use alloc::vec::Vec;
26use core::{fmt::Debug, marker::PhantomData};
27use frame_support::{
28	ensure,
29	traits::{
30		fungible::{Mutate, MutateHold},
31		tokens::{
32			Fortitude, Fortitude::Polite, Precision, Preservation, Restriction, WithdrawConsequence,
33		},
34		Get,
35	},
36	DefaultNoBound, RuntimeDebugNoBound,
37};
38use sp_runtime::{
39	traits::{Saturating, Zero},
40	DispatchError, FixedPointNumber, FixedU128,
41};
42
43pub type DepositOf<T> = Deposit<BalanceOf<T>>;
45
46pub type Meter<T> = RawMeter<T, ReservingExt, Root>;
48
49pub type NestedMeter<T> = RawMeter<T, ReservingExt, Nested>;
51
52pub type GenericMeter<T, S> = RawMeter<T, ReservingExt, S>;
56
57pub trait Ext<T: Config> {
61	fn check_limit(
73		origin: &T::AccountId,
74		limit: Option<BalanceOf<T>>,
75		min_leftover: BalanceOf<T>,
76	) -> Result<BalanceOf<T>, DispatchError>;
77	fn charge(
85		origin: &T::AccountId,
86		contract: &T::AccountId,
87		amount: &DepositOf<T>,
88		state: &ContractState<T>,
89	) -> Result<(), DispatchError>;
90}
91
92pub enum ReservingExt {}
96
97pub trait State: private::Sealed {}
101
102#[derive(Default, Debug)]
104pub struct Root;
105
106#[derive(DefaultNoBound, RuntimeDebugNoBound)]
109pub enum Nested {
110	#[default]
111	DerivedLimit,
112	OwnLimit,
113}
114
115impl State for Root {}
116impl State for Nested {}
117
118#[derive(DefaultNoBound, RuntimeDebugNoBound)]
120pub struct RawMeter<T: Config, E, S: State + Default + Debug> {
121	limit: BalanceOf<T>,
123	total_deposit: DepositOf<T>,
125	own_contribution: Contribution<T>,
127	charges: Vec<Charge<T>>,
132	nested: S,
134	_phantom: PhantomData<E>,
136}
137
138#[derive(Default, RuntimeDebugNoBound)]
140pub struct Diff {
141	pub bytes_added: u32,
143	pub bytes_removed: u32,
145	pub items_added: u32,
147	pub items_removed: u32,
149}
150
151impl Diff {
152	pub fn update_contract<T: Config>(&self, info: Option<&mut ContractInfo<T>>) -> DepositOf<T> {
161		let per_byte = T::DepositPerByte::get();
162		let per_item = T::DepositPerItem::get();
163		let bytes_added = self.bytes_added.saturating_sub(self.bytes_removed);
164		let items_added = self.items_added.saturating_sub(self.items_removed);
165		let mut bytes_deposit = Deposit::Charge(per_byte.saturating_mul((bytes_added).into()));
166		let mut items_deposit = Deposit::Charge(per_item.saturating_mul((items_added).into()));
167
168		let info = if let Some(info) = info {
170			info
171		} else {
172			debug_assert_eq!(self.bytes_removed, 0);
173			debug_assert_eq!(self.items_removed, 0);
174			return bytes_deposit.saturating_add(&items_deposit)
175		};
176
177		let bytes_removed = self.bytes_removed.saturating_sub(self.bytes_added);
179		let items_removed = self.items_removed.saturating_sub(self.items_added);
180		let ratio = FixedU128::checked_from_rational(bytes_removed, info.storage_bytes)
181			.unwrap_or_default()
182			.min(FixedU128::from_u32(1));
183		bytes_deposit = bytes_deposit
184			.saturating_add(&Deposit::Refund(ratio.saturating_mul_int(info.storage_byte_deposit)));
185		let ratio = FixedU128::checked_from_rational(items_removed, info.storage_items)
186			.unwrap_or_default()
187			.min(FixedU128::from_u32(1));
188		items_deposit = items_deposit
189			.saturating_add(&Deposit::Refund(ratio.saturating_mul_int(info.storage_item_deposit)));
190
191		info.storage_bytes =
193			info.storage_bytes.saturating_add(bytes_added).saturating_sub(bytes_removed);
194		info.storage_items =
195			info.storage_items.saturating_add(items_added).saturating_sub(items_removed);
196		match &bytes_deposit {
197			Deposit::Charge(amount) =>
198				info.storage_byte_deposit = info.storage_byte_deposit.saturating_add(*amount),
199			Deposit::Refund(amount) =>
200				info.storage_byte_deposit = info.storage_byte_deposit.saturating_sub(*amount),
201		}
202		match &items_deposit {
203			Deposit::Charge(amount) =>
204				info.storage_item_deposit = info.storage_item_deposit.saturating_add(*amount),
205			Deposit::Refund(amount) =>
206				info.storage_item_deposit = info.storage_item_deposit.saturating_sub(*amount),
207		}
208
209		bytes_deposit.saturating_add(&items_deposit)
210	}
211}
212
213impl Diff {
214	fn saturating_add(&self, rhs: &Self) -> Self {
215		Self {
216			bytes_added: self.bytes_added.saturating_add(rhs.bytes_added),
217			bytes_removed: self.bytes_removed.saturating_add(rhs.bytes_removed),
218			items_added: self.items_added.saturating_add(rhs.items_added),
219			items_removed: self.items_removed.saturating_add(rhs.items_removed),
220		}
221	}
222}
223
224#[derive(RuntimeDebugNoBound, Clone, PartialEq, Eq)]
228pub enum ContractState<T: Config> {
229	Alive,
230	Terminated { beneficiary: AccountIdOf<T> },
231}
232
233#[derive(RuntimeDebugNoBound, Clone)]
243struct Charge<T: Config> {
244	contract: T::AccountId,
245	amount: DepositOf<T>,
246	state: ContractState<T>,
247}
248
249#[derive(RuntimeDebugNoBound)]
251enum Contribution<T: Config> {
252	Alive(Diff),
254	Checked(DepositOf<T>),
257	Terminated { deposit: DepositOf<T>, beneficiary: AccountIdOf<T> },
261}
262
263impl<T: Config> Contribution<T> {
264	fn update_contract(&self, info: Option<&mut ContractInfo<T>>) -> DepositOf<T> {
266		match self {
267			Self::Alive(diff) => diff.update_contract::<T>(info),
268			Self::Terminated { deposit, beneficiary: _ } | Self::Checked(deposit) =>
269				deposit.clone(),
270		}
271	}
272}
273
274impl<T: Config> Default for Contribution<T> {
275	fn default() -> Self {
276		Self::Alive(Default::default())
277	}
278}
279
280impl<T, E, S> RawMeter<T, E, S>
282where
283	T: Config,
284	E: Ext<T>,
285	S: State + Default + Debug,
286{
287	pub fn nested(&self, limit: BalanceOf<T>) -> RawMeter<T, E, Nested> {
294		debug_assert!(matches!(self.contract_state(), ContractState::Alive));
295		let limit = self.available().min(limit);
298		if limit.is_zero() {
299			RawMeter { limit: self.available(), ..Default::default() }
300		} else {
301			RawMeter { limit, nested: Nested::OwnLimit, ..Default::default() }
302		}
303	}
304
305	pub fn absorb(
321		&mut self,
322		absorbed: RawMeter<T, E, Nested>,
323		contract: &T::AccountId,
324		info: Option<&mut ContractInfo<T>>,
325	) {
326		let own_deposit = absorbed.own_contribution.update_contract(info);
327		self.total_deposit = self
328			.total_deposit
329			.saturating_add(&absorbed.total_deposit)
330			.saturating_add(&own_deposit);
331		self.charges.extend_from_slice(&absorbed.charges);
332		if !own_deposit.is_zero() {
333			self.charges.push(Charge {
334				contract: contract.clone(),
335				amount: own_deposit,
336				state: absorbed.contract_state(),
337			});
338		}
339	}
340
341	fn available(&self) -> BalanceOf<T> {
343		self.total_deposit.available(&self.limit)
344	}
345
346	fn contract_state(&self) -> ContractState<T> {
348		match &self.own_contribution {
349			Contribution::Terminated { deposit: _, beneficiary } =>
350				ContractState::Terminated { beneficiary: beneficiary.clone() },
351			_ => ContractState::Alive,
352		}
353	}
354}
355
356impl<T, E> RawMeter<T, E, Root>
358where
359	T: Config,
360	E: Ext<T>,
361{
362	pub fn new(
366		origin: &Origin<T>,
367		limit: Option<BalanceOf<T>>,
368		min_leftover: BalanceOf<T>,
369	) -> Result<Self, DispatchError> {
370		return match origin {
372			Origin::Root => Ok(Self {
373				limit: limit.unwrap_or(T::DefaultDepositLimit::get()),
374				..Default::default()
375			}),
376			Origin::Signed(o) => {
377				let limit = E::check_limit(o, limit, min_leftover)?;
378				Ok(Self { limit, ..Default::default() })
379			},
380		}
381	}
382
383	pub fn try_into_deposit(self, origin: &Origin<T>) -> Result<DepositOf<T>, DispatchError> {
390		let origin = match origin {
392			Origin::Root => return Ok(Deposit::Charge(Zero::zero())),
393			Origin::Signed(o) => o,
394		};
395		for charge in self.charges.iter().filter(|c| matches!(c.amount, Deposit::Refund(_))) {
396			E::charge(origin, &charge.contract, &charge.amount, &charge.state)?;
397		}
398		for charge in self.charges.iter().filter(|c| matches!(c.amount, Deposit::Charge(_))) {
399			E::charge(origin, &charge.contract, &charge.amount, &charge.state)?;
400		}
401		Ok(self.total_deposit)
402	}
403}
404
405impl<T, E> RawMeter<T, E, Nested>
407where
408	T: Config,
409	E: Ext<T>,
410{
411	pub fn charge(&mut self, diff: &Diff) {
413		match &mut self.own_contribution {
414			Contribution::Alive(own) => *own = own.saturating_add(diff),
415			_ => panic!("Charge is never called after termination; qed"),
416		};
417	}
418
419	pub fn charge_deposit(&mut self, contract: T::AccountId, amount: DepositOf<T>) {
426		self.total_deposit = self.total_deposit.saturating_add(&amount);
427		self.charges.push(Charge { contract, amount, state: ContractState::Alive });
428	}
429
430	pub fn charge_instantiate(
434		&mut self,
435		origin: &T::AccountId,
436		contract: &T::AccountId,
437		contract_info: &mut ContractInfo<T>,
438		code_info: &CodeInfo<T>,
439	) -> Result<(), DispatchError> {
440		debug_assert!(matches!(self.contract_state(), ContractState::Alive));
441
442		let ed = Pallet::<T>::min_balance();
444		self.total_deposit = Deposit::Charge(ed);
445		T::Currency::transfer(origin, contract, ed, Preservation::Preserve)?;
446
447		System::<T>::inc_consumers(contract)?;
451
452		let deposit = contract_info.update_base_deposit(&code_info);
453		let deposit = Deposit::Charge(deposit);
454
455		self.charge_deposit(contract.clone(), deposit);
456		Ok(())
457	}
458
459	pub fn terminate(&mut self, info: &ContractInfo<T>, beneficiary: T::AccountId) {
465		debug_assert!(matches!(self.contract_state(), ContractState::Alive));
466		self.own_contribution = Contribution::Terminated {
467			deposit: Deposit::Refund(info.total_deposit()),
468			beneficiary,
469		};
470	}
471
472	pub fn enforce_limit(
482		&mut self,
483		info: Option<&mut ContractInfo<T>>,
484	) -> Result<(), DispatchError> {
485		let deposit = self.own_contribution.update_contract(info);
486		let total_deposit = self.total_deposit.saturating_add(&deposit);
487		if matches!(self.contract_state(), ContractState::Alive) {
489			self.own_contribution = Contribution::Checked(deposit);
490		}
491		if let Deposit::Charge(amount) = total_deposit {
492			if amount > self.limit {
493				return Err(<Error<T>>::StorageDepositLimitExhausted.into())
494			}
495		}
496		Ok(())
497	}
498
499	pub fn enforce_subcall_limit(
502		&mut self,
503		info: Option<&mut ContractInfo<T>>,
504	) -> Result<(), DispatchError> {
505		match self.nested {
506			Nested::OwnLimit => self.enforce_limit(info),
507			Nested::DerivedLimit => Ok(()),
508		}
509	}
510}
511
512impl<T: Config> Ext<T> for ReservingExt {
513	fn check_limit(
514		origin: &T::AccountId,
515		limit: Option<BalanceOf<T>>,
516		min_leftover: BalanceOf<T>,
517	) -> Result<BalanceOf<T>, DispatchError> {
518		let max = T::Currency::reducible_balance(origin, Preservation::Preserve, Polite)
522			.saturating_sub(min_leftover)
523			.saturating_sub(Pallet::<T>::min_balance());
524		let default = max.min(T::DefaultDepositLimit::get());
525		let limit = limit.unwrap_or(default);
526		ensure!(
527			limit <= max &&
528				matches!(T::Currency::can_withdraw(origin, limit), WithdrawConsequence::Success),
529			<Error<T>>::StorageDepositNotEnoughFunds,
530		);
531		Ok(limit)
532	}
533
534	fn charge(
535		origin: &T::AccountId,
536		contract: &T::AccountId,
537		amount: &DepositOf<T>,
538		state: &ContractState<T>,
539	) -> Result<(), DispatchError> {
540		match amount {
541			Deposit::Charge(amount) | Deposit::Refund(amount) if amount.is_zero() => return Ok(()),
542			Deposit::Charge(amount) => {
543				T::Currency::transfer_and_hold(
546					&HoldReason::StorageDepositReserve.into(),
547					origin,
548					contract,
549					*amount,
550					Precision::Exact,
551					Preservation::Preserve,
552					Fortitude::Polite,
553				)?;
554
555				Pallet::<T>::deposit_event(Event::StorageDepositTransferredAndHeld {
556					from: origin.clone(),
557					to: contract.clone(),
558					amount: *amount,
559				});
560			},
561			Deposit::Refund(amount) => {
562				let transferred = T::Currency::transfer_on_hold(
563					&HoldReason::StorageDepositReserve.into(),
564					contract,
565					origin,
566					*amount,
567					Precision::BestEffort,
568					Restriction::Free,
569					Fortitude::Polite,
570				)?;
571
572				Pallet::<T>::deposit_event(Event::StorageDepositTransferredAndReleased {
573					from: contract.clone(),
574					to: origin.clone(),
575					amount: transferred,
576				});
577
578				if transferred < *amount {
579					log::error!(
583						target: LOG_TARGET,
584						"Failed to repatriate full storage deposit {:?} from contract {:?} to origin {:?}. Transferred {:?}.",
585						amount, contract, origin, transferred,
586					);
587				}
588			},
589		}
590		if let ContractState::<T>::Terminated { beneficiary } = state {
591			System::<T>::dec_consumers(&contract);
592			T::Currency::transfer(
594				&contract,
595				&beneficiary,
596				T::Currency::reducible_balance(&contract, Preservation::Expendable, Polite),
597				Preservation::Expendable,
598			)?;
599		}
600		Ok(())
601	}
602}
603
604mod private {
605	pub trait Sealed {}
606	impl Sealed for super::Root {}
607	impl Sealed for super::Nested {}
608}
609
610#[cfg(test)]
611mod tests {
612	use super::*;
613	use crate::{
614		exec::AccountIdOf,
615		tests::{Test, ALICE, BOB, CHARLIE},
616	};
617	use frame_support::parameter_types;
618	use pretty_assertions::assert_eq;
619
620	type TestMeter = RawMeter<Test, TestExt, Root>;
621
622	parameter_types! {
623		static TestExtTestValue: TestExt = Default::default();
624	}
625
626	#[derive(Debug, PartialEq, Eq, Clone)]
627	struct LimitCheck {
628		origin: AccountIdOf<Test>,
629		limit: BalanceOf<Test>,
630		min_leftover: BalanceOf<Test>,
631	}
632
633	#[derive(Debug, PartialEq, Eq, Clone)]
634	struct Charge {
635		origin: AccountIdOf<Test>,
636		contract: AccountIdOf<Test>,
637		amount: DepositOf<Test>,
638		state: ContractState<Test>,
639	}
640
641	#[derive(Default, Debug, PartialEq, Eq, Clone)]
642	pub struct TestExt {
643		limit_checks: Vec<LimitCheck>,
644		charges: Vec<Charge>,
645	}
646
647	impl TestExt {
648		fn clear(&mut self) {
649			self.limit_checks.clear();
650			self.charges.clear();
651		}
652	}
653
654	impl Ext<Test> for TestExt {
655		fn check_limit(
656			origin: &AccountIdOf<Test>,
657			limit: Option<BalanceOf<Test>>,
658			min_leftover: BalanceOf<Test>,
659		) -> Result<BalanceOf<Test>, DispatchError> {
660			let limit = limit.unwrap_or(42);
661			TestExtTestValue::mutate(|ext| {
662				ext.limit_checks
663					.push(LimitCheck { origin: origin.clone(), limit, min_leftover })
664			});
665			Ok(limit)
666		}
667
668		fn charge(
669			origin: &AccountIdOf<Test>,
670			contract: &AccountIdOf<Test>,
671			amount: &DepositOf<Test>,
672			state: &ContractState<Test>,
673		) -> Result<(), DispatchError> {
674			TestExtTestValue::mutate(|ext| {
675				ext.charges.push(Charge {
676					origin: origin.clone(),
677					contract: contract.clone(),
678					amount: amount.clone(),
679					state: state.clone(),
680				})
681			});
682			Ok(())
683		}
684	}
685
686	fn clear_ext() {
687		TestExtTestValue::mutate(|ext| ext.clear())
688	}
689
690	struct ChargingTestCase {
691		origin: Origin<Test>,
692		deposit: DepositOf<Test>,
693		expected: TestExt,
694	}
695
696	#[derive(Default)]
697	struct StorageInfo {
698		bytes: u32,
699		items: u32,
700		bytes_deposit: BalanceOf<Test>,
701		items_deposit: BalanceOf<Test>,
702	}
703
704	fn new_info(info: StorageInfo) -> ContractInfo<Test> {
705		ContractInfo::<Test> {
706			trie_id: Default::default(),
707			code_hash: Default::default(),
708			storage_bytes: info.bytes,
709			storage_items: info.items,
710			storage_byte_deposit: info.bytes_deposit,
711			storage_item_deposit: info.items_deposit,
712			storage_base_deposit: Default::default(),
713			delegate_dependencies: Default::default(),
714		}
715	}
716
717	#[test]
718	fn new_reserves_balance_works() {
719		clear_ext();
720
721		TestMeter::new(&Origin::from_account_id(ALICE), Some(1_000), 0).unwrap();
722
723		assert_eq!(
724			TestExtTestValue::get(),
725			TestExt {
726				limit_checks: vec![LimitCheck { origin: ALICE, limit: 1_000, min_leftover: 0 }],
727				..Default::default()
728			}
729		)
730	}
731
732	#[test]
733	fn empty_charge_works() {
734		clear_ext();
735
736		let mut meter = TestMeter::new(&Origin::from_account_id(ALICE), Some(1_000), 0).unwrap();
737		assert_eq!(meter.available(), 1_000);
738
739		let mut nested0 = meter.nested(BalanceOf::<Test>::zero());
741		nested0.charge(&Default::default());
742		meter.absorb(nested0, &BOB, None);
743
744		assert_eq!(
745			TestExtTestValue::get(),
746			TestExt {
747				limit_checks: vec![LimitCheck { origin: ALICE, limit: 1_000, min_leftover: 0 }],
748				..Default::default()
749			}
750		)
751	}
752
753	#[test]
754	fn charging_works() {
755		let test_cases = vec![
756			ChargingTestCase {
757				origin: Origin::<Test>::from_account_id(ALICE),
758				deposit: Deposit::Refund(28),
759				expected: TestExt {
760					limit_checks: vec![LimitCheck { origin: ALICE, limit: 100, min_leftover: 0 }],
761					charges: vec![
762						Charge {
763							origin: ALICE,
764							contract: CHARLIE,
765							amount: Deposit::Refund(10),
766							state: ContractState::Alive,
767						},
768						Charge {
769							origin: ALICE,
770							contract: CHARLIE,
771							amount: Deposit::Refund(20),
772							state: ContractState::Alive,
773						},
774						Charge {
775							origin: ALICE,
776							contract: BOB,
777							amount: Deposit::Charge(2),
778							state: ContractState::Alive,
779						},
780					],
781				},
782			},
783			ChargingTestCase {
784				origin: Origin::<Test>::Root,
785				deposit: Deposit::Charge(0),
786				expected: TestExt { limit_checks: vec![], charges: vec![] },
787			},
788		];
789
790		for test_case in test_cases {
791			clear_ext();
792
793			let mut meter = TestMeter::new(&test_case.origin, Some(100), 0).unwrap();
794			assert_eq!(meter.available(), 100);
795
796			let mut nested0_info = new_info(StorageInfo {
797				bytes: 100,
798				items: 5,
799				bytes_deposit: 100,
800				items_deposit: 10,
801			});
802			let mut nested0 = meter.nested(BalanceOf::<Test>::zero());
803			nested0.charge(&Diff {
804				bytes_added: 108,
805				bytes_removed: 5,
806				items_added: 1,
807				items_removed: 2,
808			});
809			nested0.charge(&Diff { bytes_removed: 99, ..Default::default() });
810
811			let mut nested1_info = new_info(StorageInfo {
812				bytes: 100,
813				items: 10,
814				bytes_deposit: 100,
815				items_deposit: 20,
816			});
817			let mut nested1 = nested0.nested(BalanceOf::<Test>::zero());
818			nested1.charge(&Diff { items_removed: 5, ..Default::default() });
819			nested0.absorb(nested1, &CHARLIE, Some(&mut nested1_info));
820
821			let mut nested2_info = new_info(StorageInfo {
822				bytes: 100,
823				items: 7,
824				bytes_deposit: 100,
825				items_deposit: 20,
826			});
827			let mut nested2 = nested0.nested(BalanceOf::<Test>::zero());
828			nested2.charge(&Diff { items_removed: 7, ..Default::default() });
829			nested0.absorb(nested2, &CHARLIE, Some(&mut nested2_info));
830
831			nested0.enforce_limit(Some(&mut nested0_info)).unwrap();
832			meter.absorb(nested0, &BOB, Some(&mut nested0_info));
833
834			assert_eq!(meter.try_into_deposit(&test_case.origin).unwrap(), test_case.deposit);
835
836			assert_eq!(nested0_info.extra_deposit(), 112);
837			assert_eq!(nested1_info.extra_deposit(), 110);
838			assert_eq!(nested2_info.extra_deposit(), 100);
839
840			assert_eq!(TestExtTestValue::get(), test_case.expected)
841		}
842	}
843
844	#[test]
845	fn termination_works() {
846		let test_cases = vec![
847			ChargingTestCase {
848				origin: Origin::<Test>::from_account_id(ALICE),
849				deposit: Deposit::Refund(108),
850				expected: TestExt {
851					limit_checks: vec![LimitCheck { origin: ALICE, limit: 1_000, min_leftover: 0 }],
852					charges: vec![
853						Charge {
854							origin: ALICE,
855							contract: CHARLIE,
856							amount: Deposit::Refund(120),
857							state: ContractState::Terminated { beneficiary: CHARLIE },
858						},
859						Charge {
860							origin: ALICE,
861							contract: BOB,
862							amount: Deposit::Charge(12),
863							state: ContractState::Alive,
864						},
865					],
866				},
867			},
868			ChargingTestCase {
869				origin: Origin::<Test>::Root,
870				deposit: Deposit::Charge(0),
871				expected: TestExt { limit_checks: vec![], charges: vec![] },
872			},
873		];
874
875		for test_case in test_cases {
876			clear_ext();
877
878			let mut meter = TestMeter::new(&test_case.origin, Some(1_000), 0).unwrap();
879			assert_eq!(meter.available(), 1_000);
880
881			let mut nested0 = meter.nested(BalanceOf::<Test>::zero());
882			nested0.charge(&Diff {
883				bytes_added: 5,
884				bytes_removed: 1,
885				items_added: 3,
886				items_removed: 1,
887			});
888			nested0.charge(&Diff { items_added: 2, ..Default::default() });
889
890			let mut nested1_info = new_info(StorageInfo {
891				bytes: 100,
892				items: 10,
893				bytes_deposit: 100,
894				items_deposit: 20,
895			});
896			let mut nested1 = nested0.nested(BalanceOf::<Test>::zero());
897			nested1.charge(&Diff { items_removed: 5, ..Default::default() });
898			nested1.charge(&Diff { bytes_added: 20, ..Default::default() });
899			nested1.terminate(&nested1_info, CHARLIE);
900			nested0.enforce_limit(Some(&mut nested1_info)).unwrap();
901			nested0.absorb(nested1, &CHARLIE, None);
902
903			meter.absorb(nested0, &BOB, None);
904			assert_eq!(meter.try_into_deposit(&test_case.origin).unwrap(), test_case.deposit);
905			assert_eq!(TestExtTestValue::get(), test_case.expected)
906		}
907	}
908}