You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/build/guides/archival/test-ttl-extension.mdx
+52-41Lines changed: 52 additions & 41 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,7 +8,7 @@ In order to test contracts that extend the contract data [TTL](../../../learn/fu
8
8
9
9
## Example
10
10
11
-
Follow along the [example](https://github.com/stellar/soroban-examples/blob/main/ttl/src/lib.rs) that tests TTL extensions. The example has extensive comments, this document just highlights the most important parts.
11
+
Follow along the [example](https://github.com/stellar/soroban-examples/blob/v23.0.0/ttl/src/lib.rs) that tests TTL extensions. The example has extensive comments, this document just highlights the most important parts.
12
12
13
13
We use a very simple contract that only extends an entry for every Soroban storage type:
14
14
@@ -51,30 +51,38 @@ The focus of the example is the tests, so the following code snippets come from
51
51
It's a good idea to define the custom values of TTL-related network settings, since the defaults are defined by the SDK and aren't immediately obvious for the reader of the tests:
52
52
53
53
```rust
54
-
env.ledger().with_mut(|li| {
55
-
// Current ledger sequence - the TTL is the number of
56
-
// ledgers from the `sequence_number` (exclusive) until
57
-
// the last ledger sequence where entry is still considered
58
-
// alive.
59
-
li.sequence_number =100_000;
60
-
// Minimum TTL for persistent entries - new persistent (and instance)
61
-
// entries will have this TTL when created.
62
-
li.min_persistent_entry_ttl =500;
63
-
// Minimum TTL for temporary entries - new temporary
64
-
// entries will have this TTL when created.
65
-
li.min_temp_entry_ttl =100;
66
-
// Maximum TTL of any entry. Note, that entries can have their TTL
67
-
// extended indefinitely, but each extension can be at most
68
-
// `max_entry_ttl` ledger from the current `sequence_number`.
69
-
li.max_entry_ttl =15000;
70
-
});
54
+
/// Create an environment with specific values of network settings.
55
+
fncreate_env() ->Env {
56
+
letenv=Env::default();
57
+
env.ledger().with_mut(|li| {
58
+
// Current ledger sequence - the TTL is the number of
59
+
// ledgers from the `sequence_number` (exclusive) until
60
+
// the last ledger sequence where entry is still considered
61
+
// alive.
62
+
li.sequence_number =100_000;
63
+
// Minimum TTL for persistent entries - new persistent (and instance)
64
+
// entries will have this TTL when created.
65
+
li.min_persistent_entry_ttl =500;
66
+
// Minimum TTL for temporary entries - new temporary
67
+
// entries will have this TTL when created.
68
+
li.min_temp_entry_ttl =100;
69
+
// Maximum TTL of any entry. Note, that entries can have their TTL
70
+
// extended indefinitely, but each extension can be at most
71
+
// `max_entry_ttl` ledger from the current `sequence_number`.
72
+
li.max_entry_ttl =15000;
73
+
});
74
+
env
75
+
}
71
76
```
72
77
73
78
You could also use the current [network settings](../../../networks/resource-limits-fees.mdx#resource-fees) when setting up the tests, but keep in mind that these are subject to change, and the contract should be able to work with any values of these settings.
74
79
75
-
Now we run a test scenario that verifies the TTL extension logic (see [`test_extend_ttl_behavior`](https://github.com/stellar/soroban-examples/blob/f595fb5df06058ec0b9b829e9e4d0fe0513e0aa8/ttl/src/test.rs#L38) test for the full scenario). First, we setup the data and ensure that the initial TTL values correspond to the network settings we've defined above:
80
+
Now we run a test scenario that verifies the TTL extension logic (see [`test_extend_ttl_behavior`](https://github.com/stellar/soroban-examples/blob/v23.0.0/ttl/src/test.rs#L38) test for the full scenario). First, we setup the data and ensure that the initial TTL values correspond to the network settings we've defined above:
76
81
77
82
```rust
83
+
// Create initial entries and make sure their TTLs correspond to
84
+
// `min_persistent_entry_ttl` and `min_temp_entry_ttl` values set in
85
+
// `create_env()`.
78
86
client.setup();
79
87
env.as_contract(&contract_id, || {
80
88
// Note, that TTL doesn't include the current ledger, but when entry
Then we can extend the entries again and ensure that only entries that are below threshold have been extended (specifically, persistent and temporary entries in this example):
Soroban SDK also emulates the behavior for the entries that have their TTL expired. Temporary entries behave 'as if' they were deleted (see [`test_temp_entry_removal`](https://github.com/stellar/soroban-examples/blob/f595fb5df06058ec0b9b829e9e4d0fe0513e0aa8/ttl/src/test.rs#L112) test for the full scenario):
145
+
Soroban SDK also emulates the behavior for the entries that have their TTL expired. Temporary entries behave 'as if' they were deleted (see [`test_temp_entry_removal`](https://github.com/stellar/soroban-examples/blob/v23.0.0/ttl/src/test.rs#L112) test for the full scenario):
135
146
136
147
```rust
148
+
// Extend the temporary entry TTL to 7000 ledgers.
137
149
client.extend_temporary();
138
150
// Bump the ledger sequence by 7001 ledgers (one ledger past TTL).
139
151
env.ledger().with_mut(|li| {
140
-
li.sequence_number =100_000+7001;
152
+
li.sequence_number +=7001;
141
153
});
142
154
// Now the entry is no longer present in the environment.
Persistent entries are more subtle: when a transaction that is executed on-chain contains a persistent entry that has been archived (i.e. it has its TTL expired) in the footprint, then the Soroban environment will not even be instantiated. Since this behavior is not directly reproducible in test environment, instead an irrecoverable 'internal' error will be produced as soon as an archived entry is accessed, and the test will `panic`:
160
+
Persistent entries are more subtle: when a transaction that is executed on-chain contains a persistent entry that has been archived (i.e., it has its TTL expired) in the footprint, then the entry will be automatically restored. Automatic restoration is mostly transparent, the main side effect is the increased fees. (see [`test_persistent_entry_auto_restored`](https://github.com/stellar/soroban-examples/blob/v23.0.0/ttl/src/test.rs#L136) test for the full scenario):
149
161
150
162
```rust
151
-
#[test]
152
-
#[should_panic(expected ="[testing-only] Accessed contract instance key that has been archived.")]
// Bump the ledger sequence by 10001 ledgers (one ledger past TTL).
161
-
env.ledger().with_mut(|li| {
162
-
li.sequence_number =100_000+10_001;
163
-
});
164
-
// Now any call involving the expired contract (such as `extend_instance`
165
-
// call here) will panic as soon as that contract is accessed.
166
-
client.extend_instance();
167
-
}
163
+
// Extend the persistent entry TTL to 5000 ledgers.
164
+
client.extend_persistent();
165
+
// Bump the ledger sequence by 5001 ledgers (one ledger past TTL).
166
+
env.ledger().with_mut(|li| {
167
+
li.sequence_number +=5001;
168
+
});
169
+
// Now any call involving the expired persistent data will cause automatic
170
+
// restoration.
171
+
client.extend_persistent();
172
+
173
+
// Notice that disk read bytes and write bytes are increased even though the
174
+
// function itself is read-only.
175
+
letresources=env.cost_estimate().resources();
176
+
assert!(resources.disk_read_bytes >0);
177
+
assert!(resources.write_bytes >0);
178
+
assert_eq!(resources.write_entries, 1);
168
179
```
169
180
170
181
## Testing TTL extension for other contract instances
171
182
172
-
Sometimes a contract may want to extend TTL of another contracts and/or their Wasm entries (usually that would happen in factory contracts). This logic may be covered in a similar fashion to the example above using `env.deployer().get_contract_instance_ttl(&contract)` to get TTL of any contract's instance, and `env.deployer().get_contract_code_ttl(&contract)` to get TTL of any contract's Wasm entry. You can find an example of using these function in the SDK [test suite](https://github.com/stellar/rs-soroban-sdk/blob/ff05c3d4cbed97db50142372e9d7a4fa4a8d1d5d/soroban-sdk/src/tests/storage_testutils.rs#L76).
183
+
Sometimes a contract may want to extend TTL of another contracts and/or their Wasm entries (usually that would happen in factory contracts). This logic may be covered in a similar fashion to the example above using `env.deployer().get_contract_instance_ttl(&contract)` to get TTL of any contract's instance, and `env.deployer().get_contract_code_ttl(&contract)` to get TTL of any contract's Wasm entry. You can find an example of using these functions in the SDK [test suite](https://github.com/stellar/rs-soroban-sdk/blob/v23.4.1/soroban-sdk/src/tests/storage_testutils.rs#L76).
0 commit comments