1use super::*;
5use core::ops::{Add, Index, IndexMut};
6use enum_iterator::cardinality;
7use gear_core::ids::ReservationId;
8use scale_decode::DecodeAsType;
9use scale_encode::EncodeAsType;
10use sp_runtime::{
11 codec::{self, MaxEncodedLen},
12 scale_info,
13 traits::Zero,
14};
15
16#[derive(
18 Debug,
19 Copy,
20 Clone,
21 Hash,
22 Eq,
23 PartialEq,
24 Ord,
25 PartialOrd,
26 Encode,
27 EncodeAsType,
28 Decode,
29 DecodeAsType,
30 TypeInfo,
31)]
32#[codec(crate = codec)]
33#[scale_info(crate = scale_info)]
34pub enum GasNodeId<T, U> {
35 Node(T),
36 Reservation(U),
37}
38
39impl<T, U> GasNodeId<T, U> {
40 pub fn to_node_id(self) -> Option<T> {
41 match self {
42 GasNodeId::Node(message_id) => Some(message_id),
43 GasNodeId::Reservation(_) => None,
44 }
45 }
46
47 pub fn to_reservation_id(self) -> Option<U> {
48 match self {
49 GasNodeId::Node(_) => None,
50 GasNodeId::Reservation(reservation_id) => Some(reservation_id),
51 }
52 }
53}
54
55impl<T, U> fmt::Display for GasNodeId<T, U>
56where
57 T: fmt::Display,
58 U: fmt::Display,
59{
60 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
61 match self {
62 GasNodeId::Node(id) => fmt::Display::fmt(id, f),
63 GasNodeId::Reservation(id) => fmt::Display::fmt(id, f),
64 }
65 }
66}
67
68impl<U> From<MessageId> for GasNodeId<MessageId, U> {
69 fn from(id: MessageId) -> Self {
70 Self::Node(id)
71 }
72}
73
74impl<T> From<ReservationId> for GasNodeId<T, ReservationId> {
75 fn from(id: ReservationId) -> Self {
76 Self::Reservation(id)
77 }
78}
79
80#[derive(Clone, Copy, Decode, Encode, Debug, Default, PartialEq, Eq, TypeInfo, MaxEncodedLen)]
81#[codec(crate = codec)]
82#[scale_info(crate = scale_info)]
83pub struct NodeLock<Balance>([Balance; cardinality::<LockId>()]);
84
85impl<Balance> Index<LockId> for NodeLock<Balance> {
86 type Output = Balance;
87
88 fn index(&self, index: LockId) -> &Self::Output {
89 &self.0[index as usize]
90 }
91}
92
93impl<Balance> IndexMut<LockId> for NodeLock<Balance> {
94 fn index_mut(&mut self, index: LockId) -> &mut Self::Output {
95 &mut self.0[index as usize]
96 }
97}
98
99impl<Balance: Zero + Copy> Zero for NodeLock<Balance> {
100 fn zero() -> Self {
101 Self([Balance::zero(); cardinality::<LockId>()])
102 }
103
104 fn is_zero(&self) -> bool {
105 self.0.iter().all(|x| x.is_zero())
106 }
107}
108
109impl<Balance: Add<Output = Balance> + Copy> Add<Self> for NodeLock<Balance> {
110 type Output = Self;
111
112 fn add(self, other: Self) -> Self::Output {
113 let NodeLock(mut inner) = self;
114 let NodeLock(other) = other;
115
116 for (i, elem) in inner.iter_mut().enumerate() {
117 *elem = *elem + other[i];
118 }
119
120 Self(inner)
121 }
122}
123
124impl<Balance: Zero + Copy + sp_runtime::traits::Saturating> NodeLock<Balance> {
127 pub fn total_locked(&self) -> Balance {
128 self.0
129 .iter()
130 .fold(Balance::zero(), |acc, v| acc.saturating_add(*v))
131 }
132}
133
134#[derive(Clone, Decode, Debug, Encode, MaxEncodedLen, TypeInfo, PartialEq, Eq)]
136#[codec(crate = codec)]
137#[scale_info(crate = scale_info)]
138pub enum GasNode<ExternalId: Clone, Id: Clone, Balance: Zero + Clone, Funds> {
139 External {
143 id: ExternalId,
144 multiplier: GasMultiplier<Funds, Balance>,
145 value: Balance,
146 lock: NodeLock<Balance>,
147 system_reserve: Balance,
148 refs: ChildrenRefs,
149 consumed: bool,
150 deposit: bool,
151 },
152
153 Cut {
158 id: ExternalId,
159 multiplier: GasMultiplier<Funds, Balance>,
160 value: Balance,
161 lock: NodeLock<Balance>,
162 },
163
164 Reserved {
168 id: ExternalId,
169 multiplier: GasMultiplier<Funds, Balance>,
170 value: Balance,
171 lock: NodeLock<Balance>,
172 refs: ChildrenRefs,
173 consumed: bool,
174 },
175
176 SpecifiedLocal {
185 parent: Id,
186 root: Id,
187 value: Balance,
188 lock: NodeLock<Balance>,
189 system_reserve: Balance,
190 refs: ChildrenRefs,
191 consumed: bool,
192 },
193
194 UnspecifiedLocal {
199 parent: Id,
200 root: Id,
201 lock: NodeLock<Balance>,
202 system_reserve: Balance,
203 },
204}
205
206#[derive(Clone, Copy, Default, Decode, Debug, Encode, MaxEncodedLen, TypeInfo, PartialEq, Eq)]
208#[codec(crate = codec)]
209#[scale_info(crate = scale_info)]
210pub struct ChildrenRefs {
211 spec_refs: u32,
212 unspec_refs: u32,
213}
214
215impl<
216 ExternalId: Clone,
217 Id: Clone + Copy,
218 Balance: Default + Zero + Clone + Copy + sp_runtime::traits::Saturating,
219 Funds: Clone,
220> GasNode<ExternalId, Id, Balance, Funds>
221{
222 pub fn total_value(&self) -> Balance {
224 self.value()
225 .unwrap_or_default()
226 .saturating_add(self.lock().total_locked())
227 .saturating_add(self.system_reserve().unwrap_or_default())
228 }
229}
230
231impl<ExternalId: Clone, Id: Clone + Copy, Balance: Default + Zero + Clone + Copy, Funds: Clone>
232 GasNode<ExternalId, Id, Balance, Funds>
233{
234 pub fn new(
236 id: ExternalId,
237 multiplier: GasMultiplier<Funds, Balance>,
238 value: Balance,
239 deposit: bool,
240 ) -> Self {
241 Self::External {
242 id,
243 multiplier,
244 value,
245 lock: Zero::zero(),
246 system_reserve: Zero::zero(),
247 refs: Default::default(),
248 consumed: false,
249 deposit,
250 }
251 }
252
253 pub fn increase_spec_refs(&mut self) {
255 self.adjust_refs(true, true);
256 }
257
258 pub fn decrease_spec_refs(&mut self) {
260 self.adjust_refs(false, true);
261 }
262
263 pub fn increase_unspec_refs(&mut self) {
265 self.adjust_refs(true, false);
266 }
267
268 pub fn decrease_unspec_refs(&mut self) {
270 self.adjust_refs(false, false);
271 }
272
273 pub fn mark_consumed(&mut self) {
275 if let Self::External { consumed, .. }
276 | Self::SpecifiedLocal { consumed, .. }
277 | Self::Reserved { consumed, .. } = self
278 {
279 *consumed = true;
280 }
281 }
282
283 pub fn is_consumed(&self) -> bool {
288 if let Self::External { consumed, .. }
289 | Self::SpecifiedLocal { consumed, .. }
290 | Self::Reserved { consumed, .. } = self
291 {
292 *consumed
293 } else {
294 false
295 }
296 }
297
298 pub fn is_patron(&self) -> bool {
310 if let Self::External { refs, consumed, .. }
311 | Self::SpecifiedLocal { refs, consumed, .. }
312 | Self::Reserved { refs, consumed, .. } = self
313 {
314 !consumed || refs.unspec_refs != 0
315 } else {
316 false
317 }
318 }
319
320 pub fn value(&self) -> Option<Balance> {
322 match self {
323 Self::External { value, .. }
324 | Self::Cut { value, .. }
325 | Self::Reserved { value, .. }
326 | Self::SpecifiedLocal { value, .. } => Some(*value),
327 Self::UnspecifiedLocal { .. } => None,
328 }
329 }
330
331 pub fn value_mut(&mut self) -> Option<&mut Balance> {
333 match *self {
334 Self::External { ref mut value, .. }
335 | Self::Cut { ref mut value, .. }
336 | Self::Reserved { ref mut value, .. }
337 | Self::SpecifiedLocal { ref mut value, .. } => Some(value),
338 Self::UnspecifiedLocal { .. } => None,
339 }
340 }
341
342 pub fn lock(&self) -> &NodeLock<Balance> {
344 match self {
345 Self::External { lock, .. }
346 | Self::UnspecifiedLocal { lock, .. }
347 | Self::SpecifiedLocal { lock, .. }
348 | Self::Reserved { lock, .. }
349 | Self::Cut { lock, .. } => lock,
350 }
351 }
352
353 pub fn lock_mut(&mut self) -> &mut NodeLock<Balance> {
355 match *self {
356 Self::External { ref mut lock, .. }
357 | Self::UnspecifiedLocal { ref mut lock, .. }
358 | Self::SpecifiedLocal { ref mut lock, .. }
359 | Self::Reserved { ref mut lock, .. }
360 | Self::Cut { ref mut lock, .. } => lock,
361 }
362 }
363
364 pub fn system_reserve(&self) -> Option<Balance> {
366 match self {
367 GasNode::External { system_reserve, .. }
368 | GasNode::SpecifiedLocal { system_reserve, .. }
369 | GasNode::UnspecifiedLocal { system_reserve, .. } => Some(*system_reserve),
370 GasNode::Cut { .. } | GasNode::Reserved { .. } => None,
371 }
372 }
373
374 pub fn system_reserve_mut(&mut self) -> Option<&mut Balance> {
376 match self {
377 GasNode::External { system_reserve, .. }
378 | GasNode::SpecifiedLocal { system_reserve, .. }
379 | GasNode::UnspecifiedLocal { system_reserve, .. } => Some(system_reserve),
380 GasNode::Cut { .. } | GasNode::Reserved { .. } => None,
381 }
382 }
383
384 pub fn parent(&self) -> Option<Id> {
390 match self {
391 Self::External { .. } | Self::Cut { .. } | Self::Reserved { .. } => None,
392 Self::SpecifiedLocal { parent, .. } | Self::UnspecifiedLocal { parent, .. } => {
393 Some(*parent)
394 }
395 }
396 }
397
398 pub fn refs(&self) -> u32 {
400 self.spec_refs().saturating_add(self.unspec_refs())
401 }
402
403 pub fn spec_refs(&self) -> u32 {
405 match self {
406 Self::External { refs, .. }
407 | Self::SpecifiedLocal { refs, .. }
408 | Self::Reserved { refs, .. } => refs.spec_refs,
409 _ => 0,
410 }
411 }
412
413 pub fn unspec_refs(&self) -> u32 {
415 match self {
416 Self::External { refs, .. }
417 | Self::SpecifiedLocal { refs, .. }
418 | Self::Reserved { refs, .. } => refs.unspec_refs,
419 _ => 0,
420 }
421 }
422
423 pub fn root_id(&self) -> Option<Id> {
425 match self {
426 Self::SpecifiedLocal { root, .. } | Self::UnspecifiedLocal { root, .. } => Some(*root),
427 Self::External { .. } | Self::Cut { .. } | Self::Reserved { .. } => None,
428 }
429 }
430
431 pub fn external_data(&self) -> Option<(ExternalId, GasMultiplier<Funds, Balance>)> {
433 match self {
434 Self::External { id, multiplier, .. }
435 | Self::Cut { id, multiplier, .. }
436 | Self::Reserved { id, multiplier, .. } => Some((id.clone(), multiplier.clone())),
437 Self::SpecifiedLocal { .. } | Self::UnspecifiedLocal { .. } => None,
438 }
439 }
440
441 pub(crate) fn is_external(&self) -> bool {
443 matches!(self, Self::External { .. })
444 }
445
446 pub(crate) fn is_specified_local(&self) -> bool {
448 matches!(self, Self::SpecifiedLocal { .. })
449 }
450
451 pub(crate) fn is_unspecified_local(&self) -> bool {
453 matches!(self, Self::UnspecifiedLocal { .. })
454 }
455
456 pub(crate) fn is_cut(&self) -> bool {
458 matches!(self, Self::Cut { .. })
459 }
460
461 pub(crate) fn is_reserved(&self) -> bool {
463 matches!(self, Self::Reserved { .. })
464 }
465
466 pub(crate) fn is_system_reservable(&self) -> bool {
468 self.system_reserve().is_some()
469 }
470
471 fn adjust_refs(&mut self, increase: bool, spec: bool) {
472 if let Self::External { refs, .. }
473 | Self::SpecifiedLocal { refs, .. }
474 | Self::Reserved { refs, .. } = self
475 {
476 match (increase, spec) {
477 (true, true) => refs.spec_refs = refs.spec_refs.saturating_add(1),
478 (true, false) => refs.unspec_refs = refs.unspec_refs.saturating_add(1),
479 (false, true) => refs.spec_refs = refs.spec_refs.saturating_sub(1),
480 (false, false) => refs.unspec_refs = refs.unspec_refs.saturating_sub(1),
481 }
482 }
483 }
484}
485
486#[cfg(test)]
487mod tests {
488 use super::*;
489
490 #[test]
491 fn asserts_node_have_either_external_data_or_root_id() {
493 let nodes_with_external_data: [gas_provider::node::GasNode<i32, i32, i32, i32>; 3] = [
494 GasNode::External {
495 id: Default::default(),
496 multiplier: GasMultiplier::ValuePerGas(100),
497 value: Default::default(),
498 lock: Default::default(),
499 system_reserve: Default::default(),
500 refs: Default::default(),
501 consumed: Default::default(),
502 deposit: Default::default(),
503 },
504 GasNode::Cut {
505 id: Default::default(),
506 multiplier: GasMultiplier::ValuePerGas(100),
507 value: Default::default(),
508 lock: Default::default(),
509 },
510 GasNode::Reserved {
511 id: Default::default(),
512 multiplier: GasMultiplier::ValuePerGas(100),
513 value: Default::default(),
514 lock: Default::default(),
515 refs: Default::default(),
516 consumed: Default::default(),
517 },
518 ];
519
520 for node in nodes_with_external_data {
521 assert!(node.external_data().is_some() || node.root_id().is_none());
522 }
523
524 let nodes_with_root_id: [gas_provider::node::GasNode<i32, i32, i32, i32>; 2] = [
525 GasNode::SpecifiedLocal {
526 parent: Default::default(),
527 root: Default::default(),
528 value: Default::default(),
529 lock: Default::default(),
530 system_reserve: Default::default(),
531 refs: Default::default(),
532 consumed: Default::default(),
533 },
534 GasNode::UnspecifiedLocal {
535 parent: Default::default(),
536 root: Default::default(),
537 lock: Default::default(),
538 system_reserve: Default::default(),
539 },
540 ];
541
542 for node in nodes_with_root_id {
543 assert!(node.external_data().is_none() || node.root_id().is_some());
544 }
545 }
546}