soroban_sdk/ledger.rs
1//! Ledger contains types for retrieving information about the current ledger.
2use crate::{env::internal, unwrap::UnwrapInfallible, BytesN, Env, TryIntoVal};
3
4/// Ledger retrieves information about the current ledger.
5///
6/// For more details about the ledger and the ledger header that the values in the Ledger are derived from, see:
7/// - <https://developers.stellar.org/docs/learn/encyclopedia/network-configuration/ledger-headers>
8///
9/// ### Examples
10///
11/// ```
12/// use soroban_sdk::Env;
13///
14/// # use soroban_sdk::{contract, contractimpl, BytesN};
15/// #
16/// # #[contract]
17/// # pub struct Contract;
18/// #
19/// # #[contractimpl]
20/// # impl Contract {
21/// # pub fn f(env: Env) {
22/// let ledger = env.ledger();
23///
24/// let protocol_version = ledger.protocol_version();
25/// let sequence = ledger.sequence();
26/// let timestamp = ledger.timestamp();
27/// let network_id = ledger.network_id();
28/// # }
29/// # }
30/// #
31/// # #[cfg(feature = "testutils")]
32/// # fn main() {
33/// # let env = Env::default();
34/// # let contract_id = env.register(Contract, ());
35/// # ContractClient::new(&env, &contract_id).f();
36/// # }
37/// # #[cfg(not(feature = "testutils"))]
38/// # fn main() { }
39/// ```
40#[derive(Clone)]
41pub struct Ledger(Env);
42
43impl Ledger {
44 #[inline(always)]
45 pub(crate) fn env(&self) -> &Env {
46 &self.0
47 }
48
49 #[inline(always)]
50 pub(crate) fn new(env: &Env) -> Ledger {
51 Ledger(env.clone())
52 }
53
54 /// Returns the version of the protocol that the ledger created with.
55 pub fn protocol_version(&self) -> u32 {
56 internal::Env::get_ledger_version(self.env())
57 .unwrap_infallible()
58 .into()
59 }
60
61 /// Returns the sequence number of the ledger.
62 ///
63 /// The sequence number is a unique number for each ledger
64 /// that is sequential, incremented by one for each new ledger.
65 pub fn sequence(&self) -> u32 {
66 internal::Env::get_ledger_sequence(self.env())
67 .unwrap_infallible()
68 .into()
69 }
70
71 /// Returns the maximum ledger sequence number that data can live to.
72 #[doc(hidden)]
73 pub fn max_live_until_ledger(&self) -> u32 {
74 internal::Env::get_max_live_until_ledger(self.env())
75 .unwrap_infallible()
76 .into()
77 }
78
79 /// Returns a unix timestamp for when the ledger was closed.
80 ///
81 /// The timestamp is the number of seconds, excluding leap seconds, that
82 /// have elapsed since unix epoch. Unix epoch is January 1st, 1970, at
83 /// 00:00:00 UTC.
84 ///
85 /// For more details see:
86 /// - <https://developers.stellar.org/docs/learn/encyclopedia/network-configuration/ledger-headers#close-time>
87 pub fn timestamp(&self) -> u64 {
88 internal::Env::get_ledger_timestamp(self.env())
89 .unwrap_infallible()
90 .try_into_val(self.env())
91 .unwrap()
92 }
93
94 /// Returns the network identifier.
95 ///
96 /// This is SHA-256 hash of the network passphrase, for example
97 /// for the Public Network this returns:
98 /// > SHA256(Public Global Stellar Network ; September 2015)
99 ///
100 /// Returns for the Test Network:
101 /// > SHA256(Test SDF Network ; September 2015)
102 pub fn network_id(&self) -> BytesN<32> {
103 let env = self.env();
104 let bin_obj = internal::Env::get_ledger_network_id(env).unwrap_infallible();
105 unsafe { BytesN::<32>::unchecked_new(env.clone(), bin_obj) }
106 }
107}
108
109#[cfg(any(test, feature = "testutils"))]
110use crate::testutils;
111
112#[cfg(any(test, feature = "testutils"))]
113#[cfg_attr(feature = "docs", doc(cfg(feature = "testutils")))]
114impl testutils::Ledger for Ledger {
115 fn set(&self, li: testutils::LedgerInfo) {
116 let env = self.env();
117 env.host().set_ledger_info(li).unwrap();
118 }
119
120 fn set_protocol_version(&self, protocol_version: u32) {
121 self.with_mut(|ledger_info| {
122 ledger_info.protocol_version = protocol_version;
123 });
124 }
125
126 fn set_sequence_number(&self, sequence_number: u32) {
127 self.with_mut(|ledger_info| {
128 ledger_info.sequence_number = sequence_number;
129 });
130 }
131
132 fn set_timestamp(&self, timestamp: u64) {
133 self.with_mut(|ledger_info| {
134 ledger_info.timestamp = timestamp;
135 });
136 }
137
138 fn set_network_id(&self, network_id: [u8; 32]) {
139 self.with_mut(|ledger_info| {
140 ledger_info.network_id = network_id;
141 });
142 }
143
144 fn set_base_reserve(&self, base_reserve: u32) {
145 self.with_mut(|ledger_info| {
146 ledger_info.base_reserve = base_reserve;
147 });
148 }
149
150 fn set_min_temp_entry_ttl(&self, min_temp_entry_ttl: u32) {
151 self.with_mut(|ledger_info| {
152 ledger_info.min_temp_entry_ttl = min_temp_entry_ttl;
153 });
154 }
155
156 fn set_min_persistent_entry_ttl(&self, min_persistent_entry_ttl: u32) {
157 self.with_mut(|ledger_info| {
158 ledger_info.min_persistent_entry_ttl = min_persistent_entry_ttl;
159 });
160 }
161
162 fn set_max_entry_ttl(&self, max_entry_ttl: u32) {
163 self.with_mut(|ledger_info| {
164 // For the sake of consistency across SDK methods,
165 // we always make TTL values to not include the current ledger.
166 // The actual network setting in env expects this to include
167 // the current ledger, so we need to add 1 here.
168 ledger_info.max_entry_ttl = max_entry_ttl.saturating_add(1);
169 });
170 }
171
172 fn get(&self) -> testutils::LedgerInfo {
173 let env = self.env();
174 env.host().with_ledger_info(|li| Ok(li.clone())).unwrap()
175 }
176
177 fn with_mut<F>(&self, f: F)
178 where
179 F: FnMut(&mut internal::LedgerInfo),
180 {
181 let env = self.env();
182 env.host().with_mut_ledger_info(f).unwrap();
183 }
184}