gear_common/gas_provider/
mod.rs

1// This file is part of Gear.
2
3// Copyright (C) 2021-2025 Gear Technologies Inc.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19use super::*;
20use frame_support::traits::tokens::Balance as BalanceTrait;
21use sp_runtime::{RuntimeDebug, traits::Zero};
22use sp_std::marker::PhantomData;
23
24mod error;
25mod internal;
26mod lockable;
27mod negative_imbalance;
28mod node;
29mod positive_imbalance;
30mod reservable;
31
32#[cfg(feature = "std")]
33pub mod auxiliary;
34
35#[cfg(test)]
36mod property_tests;
37
38pub use error::Error;
39pub use internal::TreeImpl;
40pub use lockable::{LockId, LockableTree};
41pub use negative_imbalance::NegativeImbalance;
42pub use node::{ChildrenRefs, GasNode, GasNodeId, NodeLock};
43pub use positive_imbalance::PositiveImbalance;
44pub use reservable::ReservableTree;
45
46/// Simplified type for result of `GasTree::consume` call.
47pub type ConsumeResultOf<T> = Result<
48    Option<(
49        <T as Tree>::NegativeImbalance,
50        GasMultiplier<<T as Tree>::Funds, <T as Tree>::Balance>,
51        <T as Tree>::ExternalOrigin,
52    )>,
53    <T as Tree>::Error,
54>;
55
56/// Simplified type for `GasTree::get_origin_node` call.
57pub type OriginNodeDataOf<T> = (
58    <T as Tree>::ExternalOrigin,
59    GasMultiplier<<T as Tree>::Funds, <T as Tree>::Balance>,
60    <T as Tree>::NodeId,
61);
62
63/// Abstraction for a chain of value items each piece of which has an attributed
64/// owner and can be traced up to some root origin.
65///
66/// The definition is largely inspired by the `frame_support::traits::Currency`,
67/// however, the intended use is very close to the UTxO based ledger model.
68pub trait Tree {
69    /// Type representing the external owner of a value (gas) item.
70    type ExternalOrigin;
71
72    /// Type that identifies a node of the tree.
73    type NodeId: Clone;
74
75    /// Type representing a quantity of value.
76    type Balance: Clone;
77
78    /// Type representing a quantity of token balance.
79    type Funds: Clone;
80
81    // Types to denote a result of some unbalancing operation - that is
82    // operations that create inequality between the underlying value
83    // supply and some hypothetical "collateral" asset.
84
85    /// `PositiveImbalance` indicates that some value has been added
86    /// to circulation , i.e. total supply has increased.
87    type PositiveImbalance: Imbalance<Balance = Self::Balance>;
88
89    /// `NegativeImbalance` indicates that some value has been removed
90    /// from circulation, i.e. total supply has decreased.
91    type NegativeImbalance: Imbalance<Balance = Self::Balance>;
92
93    type InternalError: Error;
94
95    /// Error type
96    type Error: From<Self::InternalError>;
97
98    /// The total amount of value currently in circulation.
99    fn total_supply() -> Self::Balance;
100
101    /// Increase the total issuance of the underlying value by creating some
102    /// `amount` of it and attributing it to the `origin`.
103    ///
104    /// The `key` identifies the created "bag" of value. In case the `key`
105    /// already identifies some other piece of value an error is returned.
106    fn create(
107        origin: Self::ExternalOrigin,
108        multiplier: GasMultiplier<Self::Funds, Self::Balance>,
109        key: impl Into<Self::NodeId>,
110        amount: Self::Balance,
111    ) -> Result<Self::PositiveImbalance, Self::Error>;
112
113    /// The id of node, external origin and funds multiplier for a key.
114    ///
115    /// Error occurs if the tree is invalidated (has "orphan" nodes), and the
116    /// node identified by the `key` belongs to a subtree originating at
117    /// such "orphan" node, or in case of inexistent key.
118    fn get_origin_node(key: impl Into<Self::NodeId>)
119    -> Result<OriginNodeDataOf<Self>, Self::Error>;
120
121    /// The external origin for a key.
122    ///
123    /// See [`get_origin_node`](Self::get_origin_node) for details.
124    fn get_external(key: impl Into<Self::NodeId>) -> Result<Self::ExternalOrigin, Self::Error> {
125        Self::get_origin_node(key).map(|(external, _multiplier, _key)| external)
126    }
127
128    /// The funds multiplier for a key.
129    ///
130    /// See [`get_origin_node`](Self::get_origin_node) for details.
131    fn get_funds_multiplier(
132        key: impl Into<Self::NodeId>,
133    ) -> Result<GasMultiplier<Self::Funds, Self::Balance>, Self::Error> {
134        Self::get_origin_node(key).map(|(_external, multiplier, _key)| multiplier)
135    }
136
137    /// The id of external node for a key.
138    ///
139    /// See [`get_origin_node`](Self::get_origin_node) for details.
140    fn get_origin_key(key: impl Into<Self::NodeId>) -> Result<Self::NodeId, Self::Error> {
141        Self::get_origin_node(key).map(|(_external, _multiplier, key)| key)
142    }
143
144    /// Get value associated with given id and the key of an ancestor,
145    /// that keeps this value.
146    ///
147    /// Error occurs if the tree is invalidated (has "orphan" nodes), and the
148    /// node identified by the `key` belongs to a subtree originating at
149    /// such "orphan" node, or in case of inexistent key.
150    fn get_limit_node(
151        key: impl Into<Self::NodeId>,
152    ) -> Result<(Self::Balance, Self::NodeId), Self::Error>;
153
154    /// Get value associated with given id and the key of an consumed ancestor,
155    /// that keeps this value.
156    ///
157    /// Error occurs if the tree is invalidated (has "orphan" nodes), and the
158    /// node identified by the `key` belongs to a subtree originating at
159    /// such "orphan" node, or in case of inexistent key.
160    fn get_limit_node_consumed(
161        key: impl Into<Self::NodeId>,
162    ) -> Result<(Self::Balance, Self::NodeId), Self::Error>;
163
164    /// Get value associated with given id.
165    ///
166    /// See [`get_limit_node`](Self::get_limit_node) for details.
167    fn get_limit(key: impl Into<Self::NodeId>) -> Result<Self::Balance, Self::Error> {
168        Self::get_limit_node(key).map(|(balance, _key)| balance)
169    }
170
171    /// Get value associated with given id within consumed node.
172    ///
173    /// See [`get_limit_node_consumed`](Self::get_limit_node_consumed) for details.
174    fn get_limit_consumed(key: impl Into<Self::NodeId>) -> Result<Self::Balance, Self::Error> {
175        Self::get_limit_node_consumed(key).map(|(balance, _key)| balance)
176    }
177
178    /// Consume underlying value.
179    ///
180    /// If `key` does not identify any value or the value can't be fully
181    /// consumed due to being a part of other value or itself having
182    /// unconsumed parts, return `None`, else the corresponding
183    /// piece of value is destroyed and imbalance is created.
184    ///
185    /// Error occurs if the tree is invalidated (has "orphan" nodes), and the
186    /// node identified by the `key` belongs to a subtree originating at
187    /// such "orphan" node, or in case of inexistent key.
188    fn consume(key: impl Into<Self::NodeId>) -> ConsumeResultOf<Self>;
189
190    /// Burn underlying value.
191    ///
192    /// This "spends" the specified amount of value thereby decreasing the
193    /// overall supply of it. In case of a success, this indicates the
194    /// entire value supply becomes over-collateralized,
195    /// hence negative imbalance.
196    fn spend(
197        key: impl Into<Self::NodeId>,
198        amount: Self::Balance,
199    ) -> Result<Self::NegativeImbalance, Self::Error>;
200
201    /// Split underlying value.
202    ///
203    /// If `key` does not identify any value or the `amount` exceeds what's
204    /// locked under that key, an error is returned.
205    ///
206    /// This can't create imbalance as no value is burned or created.
207    fn split_with_value(
208        key: impl Into<Self::NodeId>,
209        new_key: impl Into<Self::NodeId>,
210        amount: Self::Balance,
211    ) -> Result<(), Self::Error>;
212
213    /// Split underlying value.
214    ///
215    /// If `key` does not identify any value an error is returned.
216    ///
217    /// This can't create imbalance as no value is burned or created.
218    fn split(
219        key: impl Into<Self::NodeId>,
220        new_key: impl Into<Self::NodeId>,
221    ) -> Result<(), Self::Error>;
222
223    /// Cut underlying value to a reserved node.
224    ///
225    /// If `key` does not identify any value or the `amount` exceeds what's
226    /// locked under that key, an error is returned.
227    ///
228    /// This can't create imbalance as no value is burned or created.
229    fn cut(
230        key: impl Into<Self::NodeId>,
231        new_key: impl Into<Self::NodeId>,
232        amount: Self::Balance,
233    ) -> Result<(), Self::Error>;
234
235    /// Creates deposit external node to be used as pre-defined gas node.
236    fn create_deposit(
237        key: impl Into<Self::NodeId>,
238        new_key: impl Into<Self::NodeId>,
239        amount: Self::Balance,
240    ) -> Result<(), Self::Error>;
241
242    /// Return bool, defining does node exist.
243    fn exists(key: impl Into<Self::NodeId>) -> bool;
244
245    /// Returns bool, defining does node exist and is external with deposit.
246    fn exists_and_deposit(key: impl Into<Self::NodeId>) -> bool;
247
248    /// Removes all values.
249    fn clear();
250}
251
252/// Represents logic of centralized GasTree-algorithm.
253pub trait Provider {
254    /// Type representing the external owner of a value (gas) item.
255    type ExternalOrigin;
256
257    /// Type that identifies a tree node.
258    type NodeId;
259
260    /// Type representing a quantity of value.
261    type Balance;
262
263    /// Type representing a quantity of token balance.
264    type Funds;
265
266    // Types to denote a result of some unbalancing operation - that is
267    // operations that create inequality between the underlying value
268    // supply and some hypothetical "collateral" asset.
269
270    type InternalError: Error;
271
272    /// Error type.
273    type Error: From<Self::InternalError>;
274
275    /// A ledger to account for gas creation and consumption.
276    type GasTree: LockableTree<
277            ExternalOrigin = Self::ExternalOrigin,
278            NodeId = Self::NodeId,
279            Balance = Self::Balance,
280            Funds = Self::Funds,
281            InternalError = Self::InternalError,
282            Error = Self::Error,
283        > + ReservableTree;
284
285    /// Resets all related to gas provider storages.
286    ///
287    /// It's a temporary production solution to avoid DB migrations
288    /// and would be available for test purposes only in the future.
289    fn reset() {
290        Self::GasTree::clear();
291    }
292}
293
294/// Represents either added or removed value to/from total supply of the currency.
295pub trait Imbalance {
296    type Balance;
297
298    /// Returns imbalance raw value.
299    fn peek(&self) -> Self::Balance;
300
301    /// Applies imbalance to some amount.
302    fn apply_to(&self, amount: &mut Option<Self::Balance>) -> Result<(), ImbalanceError>;
303}
304
305/// Represents errors returned by via the [Imbalance] trait.
306/// Indicates the imbalance value causes amount value overflowing
307/// when applied to the latter.
308#[derive(Debug, PartialEq)]
309pub struct ImbalanceError;