@@ -4,10 +4,6 @@ use crate::build_solidity;
44use soroban_sdk:: testutils:: storage:: { Instance , Persistent , Temporary } ;
55use 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]
128fn 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