Skip to content

Commit c26a5f2

Browse files
committed
Add SDK support for CAP-78 host functions (limited TTL extensions).
This introduces the wrappers for persistent (including contract code) and instance storage extensions only, the temporary storage is technically supported by host, but it doesn't seem useful (most likely using it would be a footgun).
1 parent 0e3eb16 commit c26a5f2

File tree

7 files changed

+781
-4
lines changed

7 files changed

+781
-4
lines changed

soroban-sdk/src/deploy.rs

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,9 @@
124124
//! ```
125125
126126
use crate::{
127-
env::internal::Env as _, unwrap::UnwrapInfallible, Address, Bytes, BytesN, ConstructorArgs,
128-
Env, IntoVal,
127+
env::internal::{ContractTtlExtension, Env as _},
128+
unwrap::UnwrapInfallible,
129+
Address, Bytes, BytesN, ConstructorArgs, Env, IntoVal,
129130
};
130131

131132
/// Deployer provides access to deploying contracts.
@@ -272,6 +273,77 @@ impl Deployer {
272273
)
273274
.unwrap_infallible();
274275
}
276+
277+
/// Extend the TTL of the contract instance and code with limits on the extension.
278+
///
279+
/// Extends the TTL of the instance and code to be up to `extend_to` ledgers.
280+
/// The extension only happens if it exceeds `min_extension` ledgers, otherwise
281+
/// this is a no-op. The amount of extension will not exceed `max_extension` ledgers.
282+
///
283+
/// Note that the extension is applied to both the contract code and contract instance,
284+
/// so it's possible that one is extended but not the other depending on their current TTLs.
285+
///
286+
/// The TTL is the number of ledgers between the current ledger and the final ledger
287+
/// the data can still be accessed.
288+
pub fn extend_ttl_with_limits(
289+
&self,
290+
contract_address: Address,
291+
extend_to: u32,
292+
min_extension: u32,
293+
max_extension: u32,
294+
) {
295+
self.env
296+
.extend_contract_instance_and_code_ttl_v2(
297+
contract_address.to_object(),
298+
ContractTtlExtension::InstanceAndCode,
299+
extend_to.into(),
300+
min_extension.into(),
301+
max_extension.into(),
302+
)
303+
.unwrap_infallible();
304+
}
305+
306+
/// Extend the TTL of the contract instance with limits on the extension.
307+
///
308+
/// Same as [`extend_ttl_with_limits`](Self::extend_ttl_with_limits) but only for contract instance.
309+
pub fn extend_ttl_for_contract_instance_with_limits(
310+
&self,
311+
contract_address: Address,
312+
extend_to: u32,
313+
min_extension: u32,
314+
max_extension: u32,
315+
) {
316+
self.env
317+
.extend_contract_instance_and_code_ttl_v2(
318+
contract_address.to_object(),
319+
ContractTtlExtension::Instance,
320+
extend_to.into(),
321+
min_extension.into(),
322+
max_extension.into(),
323+
)
324+
.unwrap_infallible();
325+
}
326+
327+
/// Extend the TTL of the contract code with limits on the extension.
328+
///
329+
/// Same as [`extend_ttl_with_limits`](Self::extend_ttl_with_limits) but only for contract code.
330+
pub fn extend_ttl_for_code_with_limits(
331+
&self,
332+
contract_address: Address,
333+
extend_to: u32,
334+
min_extension: u32,
335+
max_extension: u32,
336+
) {
337+
self.env
338+
.extend_contract_instance_and_code_ttl_v2(
339+
contract_address.to_object(),
340+
ContractTtlExtension::Code,
341+
extend_to.into(),
342+
min_extension.into(),
343+
max_extension.into(),
344+
)
345+
.unwrap_infallible();
346+
}
275347
}
276348

277349
/// A deployer that deploys a contract that has its ID derived from the provided

soroban-sdk/src/storage.rs

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
use core::fmt::Debug;
33

44
use crate::{
5-
env::internal::{self, StorageType, Val},
5+
env::internal::{self, ContractTtlExtension, StorageType, Val},
66
unwrap::{UnwrapInfallible, UnwrapOptimized},
77
Env, IntoVal, TryFromVal,
88
};
@@ -274,6 +274,36 @@ impl Storage {
274274
.unwrap_infallible();
275275
}
276276

277+
/// Extend the TTL of the data with limits on the extension.
278+
///
279+
/// Extends the TTL of the data to be up to `extend_to` ledgers. The extension
280+
/// only happens if it exceeds `min_extension` ledgers, otherwise this is a no-op.
281+
/// The amount of extension will not exceed `max_extension` ledgers.
282+
///
283+
/// The TTL is the number of ledgers between the current ledger and the final
284+
/// ledger the data can still be accessed.
285+
pub(crate) fn extend_ttl_with_limits<K>(
286+
&self,
287+
key: &K,
288+
storage_type: StorageType,
289+
extend_to: u32,
290+
min_extension: u32,
291+
max_extension: u32,
292+
) where
293+
K: IntoVal<Env, Val>,
294+
{
295+
let env = &self.env;
296+
internal::Env::extend_contract_data_ttl_v2(
297+
env,
298+
key.into_val(env),
299+
storage_type,
300+
extend_to.into(),
301+
min_extension.into(),
302+
max_extension.into(),
303+
)
304+
.unwrap_infallible();
305+
}
306+
277307
/// Removes the key and the corresponding value from the currently executing
278308
/// contract's storage.
279309
///
@@ -378,6 +408,32 @@ impl Persistent {
378408
.extend_ttl(key, StorageType::Persistent, threshold, extend_to)
379409
}
380410

411+
/// Extend the TTL of the data under the key with limits on the extension.
412+
///
413+
/// Extends the TTL of the data to be up to `extend_to` ledgers. The extension
414+
/// only happens if it exceeds `min_extension` ledgers, otherwise this is a no-op.
415+
/// The amount of extension will not exceed `max_extension` ledgers.
416+
///
417+
/// The TTL is the number of ledgers between the current ledger and the final
418+
/// ledger the data can still be accessed.
419+
pub fn extend_ttl_with_limits<K>(
420+
&self,
421+
key: &K,
422+
extend_to: u32,
423+
min_extension: u32,
424+
max_extension: u32,
425+
) where
426+
K: IntoVal<Env, Val>,
427+
{
428+
self.storage.extend_ttl_with_limits(
429+
key,
430+
StorageType::Persistent,
431+
extend_to,
432+
min_extension,
433+
max_extension,
434+
)
435+
}
436+
381437
#[inline(always)]
382438
pub fn remove<K>(&self, key: &K)
383439
where
@@ -566,6 +622,29 @@ impl Instance {
566622
)
567623
.unwrap_infallible();
568624
}
625+
626+
/// Extend the TTL of the contract instance and code with limits on the extension.
627+
///
628+
/// Extends the TTL of the instance and code to be up to `extend_to` ledgers.
629+
/// The extension only happens if it exceeds `min_extension` ledgers, otherwise
630+
/// this is a no-op. The amount of extension will not exceed `max_extension` ledgers.
631+
///
632+
/// Note that the extension is applied to both the contract code and contract instance,
633+
/// so it's possible that one is extended but not the other depending on their current TTLs.
634+
///
635+
/// The TTL is the number of ledgers between the current ledger and the final ledger
636+
/// the data can still be accessed.
637+
pub fn extend_ttl_with_limits(&self, extend_to: u32, min_extension: u32, max_extension: u32) {
638+
internal::Env::extend_contract_instance_and_code_ttl_v2(
639+
&self.storage.env,
640+
self.storage.env.current_contract_address().to_object(),
641+
ContractTtlExtension::InstanceAndCode,
642+
extend_to.into(),
643+
min_extension.into(),
644+
max_extension.into(),
645+
)
646+
.unwrap_infallible();
647+
}
569648
}
570649

571650
#[cfg(any(test, feature = "testutils"))]

0 commit comments

Comments
 (0)