gear_common/auxiliary/
gas_provider.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
19//! Auxiliary implementation of the gas provider.
20
21use crate::{
22    gas_provider::{Error, GasNode, GasNodeId, Provider, TreeImpl},
23    storage::{MapStorage, ValueStorage},
24    Origin,
25};
26use alloc::collections::BTreeMap;
27use core::{cell::RefCell, ops::DerefMut};
28use sp_core::H256;
29
30/// Balance type used in the gas tree.
31pub(crate) type Balance = u64;
32/// Type represents token value equivalent of gas.
33pub(crate) type Funds = u128;
34/// Type represents gas tree node id, which is a key for gas nodes map storage.
35pub(crate) type NodeId = GasNodeId<PlainNodeId, ReservationNodeId>;
36/// Type represents gas tree node, which is a value for gas nodes map storage.
37pub(crate) type Node = GasNode<ExternalOrigin, NodeId, Balance, Funds>;
38
39/// Gas provider implementor used in native, non-wasm runtimes.
40pub struct AuxiliaryGasProvider;
41
42impl Provider for AuxiliaryGasProvider {
43    type ExternalOrigin = ExternalOrigin;
44    type NodeId = NodeId;
45    type Balance = Balance;
46    type Funds = Funds;
47    type InternalError = GasTreeError;
48    type Error = GasTreeError;
49
50    type GasTree = TreeImpl<
51        TotalIssuanceWrap,
52        Self::InternalError,
53        Self::Error,
54        ExternalOrigin,
55        Self::NodeId,
56        GasNodesWrap,
57    >;
58}
59
60#[derive(Debug, Copy, Hash, Clone, Eq, PartialEq, Ord, PartialOrd)]
61pub struct ExternalOrigin(pub H256);
62
63impl Origin for ExternalOrigin {
64    fn into_origin(self) -> H256 {
65        self.0
66    }
67
68    fn from_origin(val: H256) -> Self {
69        Self(val)
70    }
71}
72
73#[derive(Debug, Copy, Hash, Clone, Eq, PartialEq, Ord, PartialOrd)]
74pub struct PlainNodeId(pub H256);
75
76impl Origin for PlainNodeId {
77    fn into_origin(self) -> H256 {
78        self.0
79    }
80
81    fn from_origin(val: H256) -> Self {
82        Self(val)
83    }
84}
85
86impl<U> From<PlainNodeId> for GasNodeId<PlainNodeId, U> {
87    fn from(plain_node_id: PlainNodeId) -> Self {
88        Self::Node(plain_node_id)
89    }
90}
91
92#[derive(Debug, Copy, Hash, Clone, Eq, PartialEq, Ord, PartialOrd)]
93pub struct ReservationNodeId(pub H256);
94
95impl Origin for ReservationNodeId {
96    fn into_origin(self) -> H256 {
97        self.0
98    }
99
100    fn from_origin(val: H256) -> Self {
101        Self(val)
102    }
103}
104
105impl<T> From<ReservationNodeId> for GasNodeId<T, ReservationNodeId> {
106    fn from(node_id: ReservationNodeId) -> Self {
107        Self::Reservation(node_id)
108    }
109}
110
111/// Error type serving error variants returned from gas tree methods.
112#[derive(Clone, Copy, Debug, Eq, PartialEq)]
113pub enum GasTreeError {
114    NodeAlreadyExists,
115    ParentIsLost,
116    ParentHasNoChildren,
117    NodeNotFound,
118    NodeWasConsumed,
119    InsufficientBalance,
120    Forbidden,
121    UnexpectedConsumeOutput,
122    UnexpectedNodeType,
123    ValueIsNotCaught,
124    ValueIsBlocked,
125    ValueIsNotBlocked,
126    ConsumedWithLock,
127    ConsumedWithSystemReservation,
128    TotalValueIsOverflowed,
129    TotalValueIsUnderflowed,
130}
131
132impl Error for GasTreeError {
133    fn node_already_exists() -> Self {
134        Self::NodeAlreadyExists
135    }
136
137    fn parent_is_lost() -> Self {
138        Self::ParentIsLost
139    }
140
141    fn parent_has_no_children() -> Self {
142        Self::ParentHasNoChildren
143    }
144
145    fn node_not_found() -> Self {
146        Self::NodeNotFound
147    }
148
149    fn node_was_consumed() -> Self {
150        Self::NodeWasConsumed
151    }
152
153    fn insufficient_balance() -> Self {
154        Self::InsufficientBalance
155    }
156
157    fn forbidden() -> Self {
158        Self::Forbidden
159    }
160
161    fn unexpected_consume_output() -> Self {
162        Self::UnexpectedConsumeOutput
163    }
164
165    fn unexpected_node_type() -> Self {
166        Self::UnexpectedNodeType
167    }
168
169    fn value_is_not_caught() -> Self {
170        Self::ValueIsNotCaught
171    }
172
173    fn value_is_blocked() -> Self {
174        Self::ValueIsBlocked
175    }
176
177    fn value_is_not_blocked() -> Self {
178        Self::ValueIsNotBlocked
179    }
180
181    fn consumed_with_lock() -> Self {
182        Self::ConsumedWithLock
183    }
184
185    fn consumed_with_system_reservation() -> Self {
186        Self::ConsumedWithSystemReservation
187    }
188
189    fn total_value_is_overflowed() -> Self {
190        Self::TotalValueIsOverflowed
191    }
192
193    fn total_value_is_underflowed() -> Self {
194        Self::TotalValueIsUnderflowed
195    }
196}
197
198std::thread_local! {
199    // Definition of the `TotalIssuance` global storage, accessed by the tree.
200    pub(crate) static TOTAL_ISSUANCE: RefCell<Option<Balance>> = const { RefCell::new(None) };
201}
202
203/// Global `TotalIssuance` storage manager.
204#[derive(Debug, PartialEq, Eq)]
205pub struct TotalIssuanceWrap;
206
207impl ValueStorage for TotalIssuanceWrap {
208    type Value = Balance;
209
210    fn exists() -> bool {
211        TOTAL_ISSUANCE.with(|i| i.borrow().is_some())
212    }
213
214    fn get() -> Option<Self::Value> {
215        TOTAL_ISSUANCE.with(|i| *i.borrow())
216    }
217
218    fn kill() {
219        TOTAL_ISSUANCE.with(|i| {
220            *i.borrow_mut() = None;
221        })
222    }
223
224    fn mutate<R, F: FnOnce(&mut Option<Self::Value>) -> R>(f: F) -> R {
225        TOTAL_ISSUANCE.with(|i| f(i.borrow_mut().deref_mut()))
226    }
227
228    fn put(value: Self::Value) {
229        TOTAL_ISSUANCE.with(|i| {
230            i.replace(Some(value));
231        })
232    }
233
234    fn set(value: Self::Value) -> Option<Self::Value> {
235        Self::mutate(|opt| {
236            let prev = opt.take();
237            *opt = Some(value);
238            prev
239        })
240    }
241
242    fn take() -> Option<Self::Value> {
243        TOTAL_ISSUANCE.with(|i| i.take())
244    }
245}
246
247std::thread_local! {
248    // Definition of the `GasNodes` (tree `StorageMap`) global storage, accessed by the tree.
249    pub(crate) static GAS_NODES: RefCell<BTreeMap<NodeId, Node>> = const { RefCell::new(BTreeMap::new()) };
250}
251
252/// Global `GasNodes` storage manager.
253pub struct GasNodesWrap;
254
255impl MapStorage for GasNodesWrap {
256    type Key = NodeId;
257    type Value = Node;
258
259    fn contains_key(key: &Self::Key) -> bool {
260        GAS_NODES.with(|tree| tree.borrow().contains_key(key))
261    }
262
263    fn get(key: &Self::Key) -> Option<Self::Value> {
264        GAS_NODES.with(|tree| tree.borrow().get(key).cloned())
265    }
266
267    fn insert(key: Self::Key, value: Self::Value) {
268        GAS_NODES.with(|tree| tree.borrow_mut().insert(key, value));
269    }
270
271    fn mutate<R, F: FnOnce(&mut Option<Self::Value>) -> R>(_key: Self::Key, _f: F) -> R {
272        unimplemented!()
273    }
274
275    fn mutate_values<F: FnMut(Self::Value) -> Self::Value>(mut _f: F) {
276        unimplemented!()
277    }
278
279    fn remove(key: Self::Key) {
280        GAS_NODES.with(|tree| tree.borrow_mut().remove(&key));
281    }
282
283    fn clear() {
284        GAS_NODES.with(|tree| tree.borrow_mut().clear());
285    }
286
287    fn take(key: Self::Key) -> Option<Self::Value> {
288        GAS_NODES.with(|tree| tree.borrow_mut().remove(&key))
289    }
290}