Skip to content

Commit d5bd638

Browse files
committed
test(soroban): tests for extending instance TTLs
Signed-off-by: Tarek <tareknaser360@gmail.com>
1 parent 9fa34d2 commit d5bd638

File tree

1 file changed

+237
-4
lines changed

1 file changed

+237
-4
lines changed

tests/soroban_testcases/ttl.rs

Lines changed: 237 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,6 @@ use crate::build_solidity;
44
use soroban_sdk::testutils::storage::{Instance, Persistent, Temporary};
55
use soroban_sdk::testutils::Ledger;
66

7-
/// This test is adapted from
8-
/// [Stellar Soroban Examples](https://github.com/stellar/soroban-examples/blob/f595fb5df06058ec0b9b829e9e4d0fe0513e0aa8/ttl).
9-
///
10-
/// It shows testing the TTL extension for persistent storage keys using the `extendPersistentTTL` built-in function
117
#[test]
128
fn ttl_basic_persistent() {
139
let runtime = build_solidity(
@@ -146,3 +142,240 @@ fn ttl_instance_wrong() {
146142
},
147143
);
148144
}
145+
146+
#[test]
147+
fn ttl_instance_correct() {
148+
let runtime = build_solidity(
149+
r#"contract instance_counter {
150+
/// Variable stored in instance storage
151+
uint64 instance instanceCount = 3;
152+
153+
/// Extends the TTL for the instance storage to 10000 ledgers
154+
/// if the current TTL is smaller than 2000 ledgers
155+
function extend_instance_ttl() public view returns (int64) {
156+
return extend_instance_ttl(2000, 10000);
157+
}
158+
}"#,
159+
|env| {
160+
env.env.ledger().with_mut(|li| {
161+
// Current ledger sequence - the TTL is the number of
162+
// ledgers from the `sequence_number` (exclusive) until
163+
// the last ledger sequence where entry is still considered
164+
// alive.
165+
li.sequence_number = 100_000;
166+
// Minimum TTL for persistent entries - new persistent (and instance)
167+
// entries will have this TTL when created.
168+
li.min_persistent_entry_ttl = 500;
169+
// Minimum TTL for temporary entries - new temporary
170+
// entries will have this TTL when created.
171+
li.min_temp_entry_ttl = 100;
172+
// Maximum TTL of any entry. Note, that entries can have their TTL
173+
// extended indefinitely, but each extension can be at most
174+
// `max_entry_ttl` ledger from the current `sequence_number`.
175+
li.max_entry_ttl = 15000;
176+
});
177+
},
178+
);
179+
180+
let addr = runtime.contracts.last().unwrap();
181+
182+
// Initial TTL for instance storage
183+
runtime.env.as_contract(addr, || {
184+
assert_eq!(runtime.env.storage().instance().get_ttl(), 499);
185+
});
186+
187+
// Extend instance TTL to 10000 ledgers
188+
runtime.invoke_contract(addr, "extend_instance_ttl", vec![]);
189+
runtime.env.as_contract(addr, || {
190+
assert_eq!(runtime.env.storage().instance().get_ttl(), 10000);
191+
});
192+
}
193+
194+
/// This test is adapted from
195+
/// [Stellar Soroban Examples](https://github.com/stellar/soroban-examples/blob/f595fb5df06058ec0b9b829e9e4d0fe0513e0aa8/ttl).
196+
#[test]
197+
fn ttl_combined() {
198+
let runtime = build_solidity(
199+
r#"
200+
contract ttl_storage {
201+
uint64 public persistent pCount = 11;
202+
uint64 temporary tCount = 7;
203+
uint64 instance iCount = 3;
204+
205+
function extend_persistent_ttl() public view returns (int64) {
206+
return pCount.extendTtl(1000, 5000);
207+
}
208+
209+
function extend_temp_ttl() public view returns (int64) {
210+
return tCount.extendTtl(3000, 7000);
211+
}
212+
213+
function extend_instance_ttl() public view returns (int64) {
214+
return extend_instance_ttl(2000, 10000);
215+
}
216+
}"#,
217+
|env| {
218+
env.env.ledger().with_mut(|li| {
219+
li.sequence_number = 100_000;
220+
li.min_persistent_entry_ttl = 500;
221+
li.min_temp_entry_ttl = 100;
222+
li.max_entry_ttl = 15000;
223+
});
224+
},
225+
);
226+
227+
let addr = runtime.contracts.last().unwrap();
228+
229+
// Verify initial TTLs
230+
runtime.env.as_contract(addr, || {
231+
let pkey = runtime
232+
.env
233+
.storage()
234+
.persistent()
235+
.all()
236+
.keys()
237+
.first()
238+
.unwrap();
239+
let tkey = runtime
240+
.env
241+
.storage()
242+
.temporary()
243+
.all()
244+
.keys()
245+
.first()
246+
.unwrap();
247+
assert_eq!(runtime.env.storage().persistent().get_ttl(&pkey), 499);
248+
assert_eq!(runtime.env.storage().instance().get_ttl(), 499);
249+
assert_eq!(runtime.env.storage().temporary().get_ttl(&tkey), 99);
250+
});
251+
252+
// Extend persistent storage TTL
253+
runtime.invoke_contract(addr, "extend_persistent_ttl", vec![]);
254+
runtime.env.as_contract(addr, || {
255+
let pkey = runtime
256+
.env
257+
.storage()
258+
.persistent()
259+
.all()
260+
.keys()
261+
.first()
262+
.unwrap();
263+
assert_eq!(runtime.env.storage().persistent().get_ttl(&pkey), 5000);
264+
});
265+
266+
// Extend instance storage TTL
267+
runtime.invoke_contract(addr, "extend_instance_ttl", vec![]);
268+
runtime.env.as_contract(addr, || {
269+
assert_eq!(runtime.env.storage().instance().get_ttl(), 10000);
270+
});
271+
272+
// Extend temporary storage TTL
273+
runtime.invoke_contract(addr, "extend_temp_ttl", vec![]);
274+
runtime.env.as_contract(addr, || {
275+
let tkey = runtime
276+
.env
277+
.storage()
278+
.temporary()
279+
.all()
280+
.keys()
281+
.first()
282+
.unwrap();
283+
assert_eq!(runtime.env.storage().temporary().get_ttl(&tkey), 7000);
284+
});
285+
286+
// Bump ledger sequence by 5000
287+
runtime.env.ledger().with_mut(|li| {
288+
li.sequence_number = 105_000;
289+
});
290+
291+
// Verify TTL after ledger increment
292+
runtime.env.as_contract(addr, || {
293+
let pkey = runtime
294+
.env
295+
.storage()
296+
.persistent()
297+
.all()
298+
.keys()
299+
.first()
300+
.unwrap();
301+
let tkey = runtime
302+
.env
303+
.storage()
304+
.temporary()
305+
.all()
306+
.keys()
307+
.first()
308+
.unwrap();
309+
assert_eq!(runtime.env.storage().persistent().get_ttl(&pkey), 0);
310+
assert_eq!(runtime.env.storage().instance().get_ttl(), 5000);
311+
assert_eq!(runtime.env.storage().temporary().get_ttl(&tkey), 2000);
312+
});
313+
314+
// Re-extend all TTLs
315+
runtime.invoke_contract(addr, "extend_persistent_ttl", vec![]);
316+
runtime.invoke_contract(addr, "extend_instance_ttl", vec![]);
317+
runtime.invoke_contract(addr, "extend_temp_ttl", vec![]);
318+
319+
// Final TTL verification
320+
runtime.env.as_contract(addr, || {
321+
let pkey = runtime
322+
.env
323+
.storage()
324+
.persistent()
325+
.all()
326+
.keys()
327+
.first()
328+
.unwrap();
329+
let tkey = runtime
330+
.env
331+
.storage()
332+
.temporary()
333+
.all()
334+
.keys()
335+
.first()
336+
.unwrap();
337+
assert_eq!(runtime.env.storage().persistent().get_ttl(&pkey), 5000);
338+
assert_eq!(runtime.env.storage().instance().get_ttl(), 5000); // Threshold not met, remains the same
339+
assert_eq!(runtime.env.storage().temporary().get_ttl(&tkey), 7000);
340+
});
341+
}
342+
343+
#[test]
344+
#[should_panic(expected = "[testing-only] Accessed contract instance key that has been archived.")]
345+
fn test_persistent_entry_archival() {
346+
let runtime = build_solidity(
347+
r#"
348+
contract persistent_cleanup {
349+
uint64 public persistent pCount = 11;
350+
351+
function extend_persistent_ttl() public view returns (int64) {
352+
return pCount.extendTtl(1000, 10000);
353+
}
354+
355+
function extend_instance_ttl() public view returns (int64) {
356+
return extend_instance_ttl(2000, 10000);
357+
}
358+
}"#,
359+
|env| {
360+
env.env.ledger().with_mut(|li| {
361+
li.sequence_number = 100_000;
362+
li.min_persistent_entry_ttl = 500;
363+
li.min_temp_entry_ttl = 100;
364+
li.max_entry_ttl = 15000;
365+
});
366+
},
367+
);
368+
369+
let addr = runtime.contracts.last().unwrap();
370+
371+
// Extend instance TTL
372+
runtime.invoke_contract(addr, "extend_instance_ttl", vec![]);
373+
374+
// Bump ledger sequence by 10001 (one past persistent TTL)
375+
runtime.env.ledger().with_mut(|li| {
376+
li.sequence_number = 110_001;
377+
});
378+
379+
// This should panic as the persistent entry is archived
380+
runtime.invoke_contract(addr, "extend_persistent_ttl", vec![]);
381+
}

0 commit comments

Comments
 (0)