soroban_sdk/
ledger.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
//! Ledger contains types for retrieving information about the current ledger.
use crate::{env::internal, unwrap::UnwrapInfallible, BytesN, Env, TryIntoVal};

/// Ledger retrieves information about the current ledger.
///
/// For more details about the ledger and the ledger header that the values in the Ledger are derived from, see:
///  - <https://developers.stellar.org/docs/learn/encyclopedia/network-configuration/ledger-headers>
///
/// ### Examples
///
/// ```
/// use soroban_sdk::Env;
///
/// # use soroban_sdk::{contract, contractimpl, BytesN};
/// #
/// # #[contract]
/// # pub struct Contract;
/// #
/// # #[contractimpl]
/// # impl Contract {
/// #     pub fn f(env: Env) {
/// let ledger = env.ledger();
///
/// let protocol_version = ledger.protocol_version();
/// let sequence = ledger.sequence();
/// let timestamp = ledger.timestamp();
/// let network_id = ledger.network_id();
/// #     }
/// # }
/// #
/// # #[cfg(feature = "testutils")]
/// # fn main() {
/// #     let env = Env::default();
/// #     let contract_id = env.register(Contract, ());
/// #     ContractClient::new(&env, &contract_id).f();
/// # }
/// # #[cfg(not(feature = "testutils"))]
/// # fn main() { }
/// ```
#[derive(Clone)]
pub struct Ledger(Env);

impl Ledger {
    #[inline(always)]
    pub(crate) fn env(&self) -> &Env {
        &self.0
    }

    #[inline(always)]
    pub(crate) fn new(env: &Env) -> Ledger {
        Ledger(env.clone())
    }

    /// Returns the version of the protocol that the ledger created with.
    pub fn protocol_version(&self) -> u32 {
        internal::Env::get_ledger_version(self.env())
            .unwrap_infallible()
            .into()
    }

    /// Returns the sequence number of the ledger.
    ///
    /// The sequence number is a unique number for each ledger
    /// that is sequential, incremented by one for each new ledger.
    pub fn sequence(&self) -> u32 {
        internal::Env::get_ledger_sequence(self.env())
            .unwrap_infallible()
            .into()
    }

    /// Returns the maximum ledger sequence number that data can live to.
    #[doc(hidden)]
    pub fn max_live_until_ledger(&self) -> u32 {
        internal::Env::get_max_live_until_ledger(self.env())
            .unwrap_infallible()
            .into()
    }

    /// Returns a unix timestamp for when the ledger was closed.
    ///
    /// The timestamp is the number of seconds, excluding leap seconds, that
    /// have elapsed since unix epoch. Unix epoch is January 1st, 1970, at
    /// 00:00:00 UTC.
    ///
    /// For more details see:
    ///  - <https://developers.stellar.org/docs/learn/encyclopedia/network-configuration/ledger-headers#close-time>
    pub fn timestamp(&self) -> u64 {
        internal::Env::get_ledger_timestamp(self.env())
            .unwrap_infallible()
            .try_into_val(self.env())
            .unwrap()
    }

    /// Returns the network identifier.
    ///
    /// This is SHA-256 hash of the network passphrase, for example
    /// for the Public Network this returns:
    /// > SHA256(Public Global Stellar Network ; September 2015)
    ///
    /// Returns for the Test Network:
    /// > SHA256(Test SDF Network ; September 2015)
    pub fn network_id(&self) -> BytesN<32> {
        let env = self.env();
        let bin_obj = internal::Env::get_ledger_network_id(env).unwrap_infallible();
        unsafe { BytesN::<32>::unchecked_new(env.clone(), bin_obj) }
    }
}

#[cfg(any(test, feature = "testutils"))]
use crate::testutils;

#[cfg(any(test, feature = "testutils"))]
#[cfg_attr(feature = "docs", doc(cfg(feature = "testutils")))]
impl testutils::Ledger for Ledger {
    fn set(&self, li: testutils::LedgerInfo) {
        let env = self.env();
        env.host().set_ledger_info(li).unwrap();
    }

    fn set_protocol_version(&self, protocol_version: u32) {
        self.with_mut(|ledger_info| {
            ledger_info.protocol_version = protocol_version;
        });
    }

    fn set_sequence_number(&self, sequence_number: u32) {
        self.with_mut(|ledger_info| {
            ledger_info.sequence_number = sequence_number;
        });
    }

    fn set_timestamp(&self, timestamp: u64) {
        self.with_mut(|ledger_info| {
            ledger_info.timestamp = timestamp;
        });
    }

    fn set_network_id(&self, network_id: [u8; 32]) {
        self.with_mut(|ledger_info| {
            ledger_info.network_id = network_id;
        });
    }

    fn set_base_reserve(&self, base_reserve: u32) {
        self.with_mut(|ledger_info| {
            ledger_info.base_reserve = base_reserve;
        });
    }

    fn set_min_temp_entry_ttl(&self, min_temp_entry_ttl: u32) {
        self.with_mut(|ledger_info| {
            ledger_info.min_temp_entry_ttl = min_temp_entry_ttl;
        });
    }

    fn set_min_persistent_entry_ttl(&self, min_persistent_entry_ttl: u32) {
        self.with_mut(|ledger_info| {
            ledger_info.min_persistent_entry_ttl = min_persistent_entry_ttl;
        });
    }

    fn set_max_entry_ttl(&self, max_entry_ttl: u32) {
        self.with_mut(|ledger_info| {
            // For the sake of consistency across SDK methods,
            // we always make  TTL values to not include the current ledger.
            // The actual network setting in env expects this to include
            // the current ledger, so we need to add 1 here.
            ledger_info.max_entry_ttl = max_entry_ttl.saturating_add(1);
        });
    }

    fn get(&self) -> testutils::LedgerInfo {
        let env = self.env();
        env.host().with_ledger_info(|li| Ok(li.clone())).unwrap()
    }

    fn with_mut<F>(&self, f: F)
    where
        F: FnMut(&mut internal::LedgerInfo),
    {
        let env = self.env();
        env.host().with_mut_ledger_info(f).unwrap();
    }
}