Skip to main content

gear_common/gas_provider/
lockable.rs

1// Copyright (C) Gear Technologies Inc.
2// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
3
4use super::{scheduler::StorageType, *};
5pub use gear_core::gas::LockId;
6
7/// An error indicating there is no corresponding enum variant to the one provided
8#[derive(Debug)]
9pub struct TryFromStorageTypeError;
10
11impl fmt::Display for TryFromStorageTypeError {
12    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
13        write!(formatter, "Corresponding enum variant not found")
14    }
15}
16
17impl TryFrom<StorageType> for LockId {
18    type Error = TryFromStorageTypeError;
19
20    fn try_from(storage: StorageType) -> Result<Self, Self::Error> {
21        match storage {
22            StorageType::Mailbox => Ok(Self::Mailbox),
23            StorageType::Waitlist => Ok(Self::Waitlist),
24            StorageType::Reservation => Ok(Self::Reservation),
25            StorageType::DispatchStash => Ok(Self::DispatchStash),
26            _ => Err(TryFromStorageTypeError),
27        }
28    }
29}
30
31pub trait LockableTree: Tree {
32    /// Locking some value from underlying node balance.
33    ///
34    /// If `key` does not identify any value or the `amount` exceeds what's
35    /// locked under that key, an error is returned.
36    ///
37    /// This can't create imbalance as no value is burned or created.
38    fn lock(
39        key: impl Into<Self::NodeId>,
40        id: LockId,
41        amount: Self::Balance,
42    ) -> Result<(), Self::Error>;
43
44    /// Unlocking some value from node's locked balance.
45    ///
46    /// If `key` does not identify any value or the `amount` exceeds what's
47    /// locked under that key, an error is returned.
48    ///
49    /// This can't create imbalance as no value is burned or created.
50    fn unlock(
51        key: impl Into<Self::NodeId>,
52        id: LockId,
53        amount: Self::Balance,
54    ) -> Result<(), Self::Error>;
55
56    /// Unlocking all value from node's locked balance. Returns the actual amount having been unlocked
57    /// (wrapped in a `Result`)
58    ///
59    /// See [`unlock`](Self::unlock) for details.
60    fn unlock_all(key: impl Into<Self::NodeId>, id: LockId) -> Result<Self::Balance, Self::Error> {
61        let key = key.into();
62        let amount = Self::get_lock(key.clone(), id)?;
63        Self::unlock(key, id, amount.clone()).map(|_| amount)
64    }
65
66    /// Get locked value associated with given id.
67    ///
68    /// Returns errors in cases of absence associated with given key node,
69    /// or if such functionality is forbidden for specific node type:
70    /// for example, for `GasNode::ReservedLocal`.
71    fn get_lock(key: impl Into<Self::NodeId>, id: LockId) -> Result<Self::Balance, Self::Error>;
72}
73
74#[test]
75fn lock_id_enum_discriminants_are_consistent() {
76    // Important for the [`gsdk::SignedApi`] implementation:
77    // the function `migrate_program()` relies on `LockId::Reservation` having discriminant 2
78    assert_eq!(0, LockId::Mailbox as usize);
79    assert_eq!(1, LockId::Waitlist as usize);
80    assert_eq!(2, LockId::Reservation as usize);
81    assert_eq!(3, LockId::DispatchStash as usize);
82}