Skip to content

Commit 0377b7f

Browse files
authored
Update migration guide with the information on archived persistent entry behavior change (#1560)
### What Update migration guide with the information on archived persistent entry behavior change. Fixes #1545 Also bump the SDK dependencies. ### Why Improving documentation on breaking changes. ### Known limitations N/A
1 parent 677edf4 commit 0377b7f

File tree

5 files changed

+209
-28
lines changed

5 files changed

+209
-28
lines changed

Cargo.lock

Lines changed: 12 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,25 +28,25 @@ soroban-token-spec = { version = "23.0.0-rc.3", path = "soroban-token-spec" }
2828
stellar-asset-spec = { version = "23.0.0-rc.3", path = "stellar-asset-spec" }
2929

3030
[workspace.dependencies.soroban-env-common]
31-
version = "=23.0.0-rc.2"
31+
version = "=23.0.1"
3232
#git = "https://github.com/stellar/rs-soroban-env"
3333
#rev = "bd0c80a1fe171e75f8d745f17975a73927d44ecd"
3434

3535
[workspace.dependencies.soroban-env-guest]
36-
version = "=23.0.0-rc.2"
36+
version = "=23.0.1"
3737
#git = "https://github.com/stellar/rs-soroban-env"
3838
#rev = "bd0c80a1fe171e75f8d745f17975a73927d44ecd"
3939

4040
[workspace.dependencies.soroban-env-host]
41-
version = "=23.0.0-rc.2"
41+
version = "=23.0.1"
4242
#git = "https://github.com/stellar/rs-soroban-env"
4343
#rev = "bd0c80a1fe171e75f8d745f17975a73927d44ecd"
4444

4545
[workspace.dependencies.stellar-strkey]
4646
version = "=0.0.13"
4747

4848
[workspace.dependencies.stellar-xdr]
49-
version = "=23.0.0-rc.2"
49+
version = "=23.0.0"
5050
default-features = false
5151
features = ["curr"]
5252
#git = "https://github.com/stellar/rs-stellar-xdr"

soroban-sdk/src/_migrating.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
//! This change concerns `soroban-token-sdk` and is documented in detail in
77
//! `soroban-token-sdk` crate migration guide.
88
//!
9+
//! 3. [Accessing archived persistent entries in tests no longer results in a panic][v23_archived_testing],
10+
//! automatic restoration is emulated instead. Note, that instance storage is a
11+
//! persistent entry as well.
12+
//!
913
//! # Migrating from v21 to v22
1014
//!
1115
//! 1. [`Env::register`] and [`Env::register_at`] replace [`Env::register_contract`] and [`Env::register_contract_wasm`].
@@ -243,4 +247,5 @@
243247
//! [`Hash<32>`]: crate::crypto::Hash
244248
//! [`Hash<32>::to_bytes`]: crate::crypto::Hash::to_bytes
245249
250+
pub mod v23_archived_testing;
246251
pub mod v23_contractevent;
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
//! Accessing archived persistent entries in tests no longer results in an error.
2+
//!
3+
//! Prior to protocol 23 the SDK used to emulate the failure when an archived
4+
//! ledger entry was accessed in tests. This behavior has never represented the
5+
//! actual behavior of the network, just one possible scenario when an archived
6+
//! entry is present in the transaction footprint.
7+
//!
8+
//! In protocol 23 automatic entry restoration has been introduced, which makes
9+
//! it possible for a transaction to restore an archived entry before accessing
10+
//! it. As this behavior will become the most common case on the network, the
11+
//! SDK has been changed to emulate automatic restoration in tests as well.
12+
//!
13+
//! Note, that instance storage is a persistent entry as well, so it is subject
14+
//! to the same change.
15+
//!
16+
//! ## Example
17+
//!
18+
//! Consider the following simple contract that extends entry TTL
19+
//! along with the test that relies on the error on archived entry access in
20+
//! SDK 22:
21+
//!
22+
//! ```
23+
//! #![no_std]
24+
//! use soroban_sdk::{contract, contractimpl, contracttype, Env};
25+
//!
26+
//! #[contract]
27+
//! struct Contract;
28+
//!
29+
//! #[contracttype]
30+
//! enum DataKey {
31+
//! Key,
32+
//! }
33+
//!
34+
//! #[contractimpl]
35+
//! impl Contract {
36+
//! pub fn create_and_extend_entry(env: Env) {
37+
//! env.storage().persistent().set(&DataKey::Key, &123_u32);
38+
//! // Extend the entry to live for at least 1_000_000 ledgers.
39+
//! env.storage()
40+
//! .persistent()
41+
//! .extend_ttl(&DataKey::Key, 1_000_000, 1_000_000);
42+
//! }
43+
//!
44+
//! pub fn read_entry(env: Env) -> u32 {
45+
//! env.storage().persistent().get(&DataKey::Key).unwrap()
46+
//! }
47+
//! }
48+
//!
49+
//! mod test {
50+
//! extern crate std;
51+
//! use soroban_sdk::testutils::{storage::Persistent, Ledger};
52+
//!
53+
//! use super::*;
54+
//!
55+
//! #[test]
56+
//! fn test_entry_archived() {
57+
//! let env = Env::default();
58+
//! let contract = env.register(Contract, ());
59+
//! let client = ContractClient::new(&env, &contract);
60+
//! client.create_and_extend_entry();
61+
//! let current_ledger = env.ledger().sequence();
62+
//! assert_eq!(client.read_entry(), 123);
63+
//!
64+
//! // Bump ledger sequence past entry TTL.
65+
//! env.ledger()
66+
//! .set_sequence_number(current_ledger + 1_000_000 + 1);
67+
//! let res = client.try_read_entry();
68+
//! // 👀 In SDK 22 `res` would be an error because the entry is archived.
69+
//! // 👀 In SDK 23 `res` is Ok(123) because the entry is automatically restored.
70+
//! assert!(res.is_err());
71+
//! }
72+
//! }
73+
//!
74+
//! # fn main() { }
75+
//! ```
76+
//!
77+
//! The best way to address this change is to update the tests to explicitly
78+
//! verify the expected entry TTL after the extension. This way there is no need
79+
//! to rely on the storage behavior, and also the test becomes more robust as
80+
//! it enforces the exact expected TTL value, so there is no risk of bumping
81+
//! the ledger sequence further than the expected TTL and still having the test
82+
//! pass.
83+
//!
84+
//! The example test above can be re-written as follows:
85+
//!
86+
//! ```
87+
//! #![no_std]
88+
//! use soroban_sdk::{contract, contractimpl, contracttype, Env};
89+
//!
90+
//! #[contract]
91+
//! struct Contract;
92+
//!
93+
//! #[contracttype]
94+
//! enum DataKey {
95+
//! Key,
96+
//! }
97+
//!
98+
//! #[contractimpl]
99+
//! impl Contract {
100+
//! pub fn create_and_extend_entry(env: Env) {
101+
//! env.storage().persistent().set(&DataKey::Key, &123_u32);
102+
//! // Extend the entry to live for at least 1_000_000 ledgers.
103+
//! env.storage()
104+
//! .persistent()
105+
//! .extend_ttl(&DataKey::Key, 1_000_000, 1_000_000);
106+
//! }
107+
//!
108+
//! pub fn read_entry(env: Env) -> u32 {
109+
//! env.storage().persistent().get(&DataKey::Key).unwrap()
110+
//! }
111+
//! }
112+
//!
113+
//! #[cfg(test)]
114+
//! mod test {
115+
//! extern crate std;
116+
//! use soroban_sdk::testutils::{storage::Persistent, Ledger};
117+
//!
118+
//! use super::*;
119+
//!
120+
//! #[test]
121+
//! fn test_entry_ttl_extended() {
122+
//! let env = Env::default();
123+
//! let contract = env.register(Contract, ());
124+
//! let client = ContractClient::new(&env, &contract);
125+
//! client.create_and_extend_entry();
126+
//! assert_eq!(client.read_entry(), 123);
127+
//!
128+
//! // 👀 Verify that the entry TTL was extended correctly by 1000000 ledgers.
129+
//! env.as_contract(&contract, || {
130+
//! assert_eq!(env.storage().persistent().get_ttl(&DataKey::Key), 1_000_000);
131+
//! });
132+
//! }
133+
//!
134+
//! // 👀 This test is not really necessary, but it demonstrates the
135+
//! // auto-restoration behavior in tests.
136+
//! #[test]
137+
//! fn test_auto_restore() {
138+
//! let env = Env::default();
139+
//! let contract = env.register(Contract, ());
140+
//! let client = ContractClient::new(&env, &contract);
141+
//! client.create_and_extend_entry();
142+
//! let current_ledger = env.ledger().sequence();
143+
//!
144+
//! // Bump ledger sequence past entry TTL.
145+
//! env.ledger()
146+
//! .set_sequence_number(current_ledger + 1_000_000 + 1);
147+
//! // 👀 Entry can still be accessed because automatic restoration is emulated
148+
//! // in tests.
149+
//! assert_eq!(client.read_entry(), 123);
150+
//!
151+
//! // 👀 Automatic restoration is also accounted for in cost_estimate():
152+
//! let resources = env.cost_estimate().resources();
153+
//! // Even though `read_entry` call is normally read-only, auto-restoration
154+
//! // will cause 2 entry writes here: 1 for the contract instance, another
155+
//! // one for the restored entry.
156+
//! assert_eq!(resources.write_entries, 2);
157+
//! // 2 rent bumps will happen as well for the respective entries.
158+
//! assert_eq!(resources.persistent_entry_rent_bumps, 2);
159+
//!
160+
//! // 👀 Entry TTL after auto-restoration can be observed via get_ttl().
161+
//! env.as_contract(&contract, || {
162+
//! // Auto-restored entries have their TTL extended by the minimum
163+
//! // possible TTL worth of ledgers (`min_persistent_entry_ttl`),
164+
//! // including the ledger in which they were restored (that's why
165+
//! // we subtract 1 here).
166+
//! assert_eq!(
167+
//! env.storage().persistent().get_ttl(&DataKey::Key),
168+
//! env.ledger().get().min_persistent_entry_ttl - 1
169+
//! );
170+
//! });
171+
//! }
172+
//! }
173+
//!
174+
//! # fn main() { }
175+
//! ```
176+
//!

tests/fuzz/fuzz/Cargo.lock

Lines changed: 12 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)