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;