From a2e182832bbe82b3b0855d7c26dd83bae89f2d26 Mon Sep 17 00:00:00 2001 From: Leigh <351529+leighmcculloch@users.noreply.github.com> Date: Tue, 18 Aug 2026 21:20:54 +0000 Subject: [PATCH 1/2] document env upload/upload_at and v28 code entry change --- .../guides/archival/test-ttl-extension.mdx | 23 +++++++++++++++++++ ...differential-tests-with-test-snapshots.mdx | 6 +++++ 2 files changed, 29 insertions(+) diff --git a/docs/build/guides/archival/test-ttl-extension.mdx b/docs/build/guides/archival/test-ttl-extension.mdx index f74747c634..d49ca66861 100644 --- a/docs/build/guides/archival/test-ttl-extension.mdx +++ b/docs/build/guides/archival/test-ttl-extension.mdx @@ -181,3 +181,26 @@ assert_eq!(resources.write_entries, 1); ## Testing TTL extension for other contract instances 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). + +## Testing multiple contract instances sharing one code entry + +Prior to SDK v28, contracts registered natively (via `Env::register`) all shared a single contract code entry. Starting with SDK v28 (protocol 28), each natively registered contract gets its own contract code entry instead. + +This means the code-entry TTL scenario described above, where extending one native contract's code TTL also extends another's because they share an entry, no longer applies by default in SDK v28+, since natively registered contracts no longer share an entry. + +If you want to specifically test that scenario, i.e. multiple contract instances sharing one code entry, you can opt into it by uploading the contract once with `env.upload(contract)` and then deploying multiple instances from the resulting Wasm hash using the deployer's `deploy_v2`: + +```rust +let wasm_hash = env.upload(Contract); +let deployer_address = Address::generate(&env); +let contract_a = env + .deployer() + .with_address(deployer_address.clone(), [0u8; 32]) + .deploy_v2(wasm_hash.clone(), ()); +let contract_b = env + .deployer() + .with_address(deployer_address, [1u8; 32]) + .deploy_v2(wasm_hash, ()); +``` + +Both `contract_a` and `contract_b` now share the one code entry created by `upload`. If you want to control the Wasm hash yourself rather than have one generated, use `env.upload_at(wasm_hash, contract)` instead. diff --git a/docs/build/guides/testing/differential-tests-with-test-snapshots.mdx b/docs/build/guides/testing/differential-tests-with-test-snapshots.mdx index 8877adf34d..82fbec7dac 100644 --- a/docs/build/guides/testing/differential-tests-with-test-snapshots.mdx +++ b/docs/build/guides/testing/differential-tests-with-test-snapshots.mdx @@ -21,6 +21,12 @@ The Soroban Rust SDK generates test snapshots on every test involving an `Env`. Most tests have a single `Env` and will result in a single test snapshot. Tests that have multiple `Env`s will write multiple test snapshots, one for each `Env`. Test snapshot files are named with a incrementing number on the end to separate the test snapshots for each `Env`. +:::info + +Contracts registered natively (via `Env::register`) will have different Wasm hash values recorded in existing committed test snapshots after upgrading the SDK past the version where each natively registered contract gets its own contract code entry (SDK v28 / protocol 28). Regenerate these snapshots by re-running the tests and re-committing the updated files. + +::: + ### How to Use Test Snapshots 1. Write tests using the default `Env`. For example: From 37f2ee7ee031bad82c14f36277c51b374b1343eb Mon Sep 17 00:00:00 2001 From: Leigh <351529+leighmcculloch@users.noreply.github.com> Date: Tue, 18 Aug 2026 21:23:52 +0000 Subject: [PATCH 2/2] fix auth and casing in upload code example --- docs/build/guides/archival/test-ttl-extension.mdx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/build/guides/archival/test-ttl-extension.mdx b/docs/build/guides/archival/test-ttl-extension.mdx index d49ca66861..040d2d58dc 100644 --- a/docs/build/guides/archival/test-ttl-extension.mdx +++ b/docs/build/guides/archival/test-ttl-extension.mdx @@ -186,11 +186,15 @@ Sometimes a contract may want to extend TTL of another contracts and/or their Wa Prior to SDK v28, contracts registered natively (via `Env::register`) all shared a single contract code entry. Starting with SDK v28 (protocol 28), each natively registered contract gets its own contract code entry instead. -This means the code-entry TTL scenario described above, where extending one native contract's code TTL also extends another's because they share an entry, no longer applies by default in SDK v28+, since natively registered contracts no longer share an entry. +This means the code-entry TTL scenario described above, where extending one native contract's code TTL also extends another's, no longer applies by default in SDK v28+. -If you want to specifically test that scenario, i.e. multiple contract instances sharing one code entry, you can opt into it by uploading the contract once with `env.upload(contract)` and then deploying multiple instances from the resulting Wasm hash using the deployer's `deploy_v2`: +If you want to specifically test that scenario, i.e. multiple contract instances sharing one code entry, you can opt into it by uploading the contract once with `env.upload(Contract)` and then deploying multiple instances from the resulting Wasm hash using the deployer's `deploy_v2`: ```rust +use soroban_sdk::testutils::Address as _; + +env.mock_all_auths(); + let wasm_hash = env.upload(Contract); let deployer_address = Address::generate(&env); let contract_a = env @@ -203,4 +207,4 @@ let contract_b = env .deploy_v2(wasm_hash, ()); ``` -Both `contract_a` and `contract_b` now share the one code entry created by `upload`. If you want to control the Wasm hash yourself rather than have one generated, use `env.upload_at(wasm_hash, contract)` instead. +Both `contract_a` and `contract_b` now share the one code entry created by `upload`. If you want to control the Wasm hash yourself rather than have one generated, use `env.upload_at(wasm_hash, Contract)` instead.