Skip to content

Commit a6fa69b

Browse files
add docs for experimental_spec_shaking_v2 feature
1 parent b6e838c commit a6fa69b

File tree

2 files changed

+168
-2
lines changed

2 files changed

+168
-2
lines changed

soroban-sdk/src/_features.rs

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
//! # Features
2+
//!
3+
//! The SDK provides several Cargo features that enable additional functionality.
4+
//!
5+
//! ## `testutils`
6+
//!
7+
//! Enables test utilities for writing tests that interact with contracts.
8+
//! Required for using [`Env::default()`] in tests, generating test addresses,
9+
//! and other test helpers. Only available for non-Wasm targets.
10+
//!
11+
//! ## `alloc`
12+
//!
13+
//! Enables the [`alloc`][crate::alloc] module, providing access to the global
14+
//! allocator for use in contracts.
15+
//!
16+
//! ## `hazmat-crypto`
17+
//!
18+
//! Exposes low-level cryptographic primitives (e.g.
19+
//! [`CryptoHazmat`][crate::crypto::CryptoHazmat]) that are easy to misuse.
20+
//! Use with care.
21+
//!
22+
//! ## `hazmat-address`
23+
//!
24+
//! Exposes low-level address primitives (e.g.
25+
//! [`Address::to_payload`][crate::Address::to_payload],
26+
//! [`Address::from_payload`][crate::Address::from_payload]) that are easy to
27+
//! misuse. Use with care.
28+
//!
29+
//! ## `experimental_spec_shaking_v2`
30+
//!
31+
//! Enables spec shaking, a mechanism for stripping unused type and event
32+
//! definitions from a contract's spec after building.
33+
//!
34+
//! A contract's spec (the `contractspecv0` custom section in the Wasm binary)
35+
//! contains entries for every function, type, and event defined by the contract.
36+
//! When types or events are defined but not actually used at a contract boundary
37+
//! (parameters, return values, error returns, or event publishes), their spec
38+
//! entries are dead weight. Spec shaking removes them.
39+
//!
40+
//! ### How It Works
41+
//!
42+
//! When this feature is enabled, the SDK embeds 14-byte **markers** in the Wasm
43+
//! data section for each exported type and event. A marker consists of a
44+
//! `SpEcV1` magic prefix followed by 8 bytes of a SHA-256 hash of the spec
45+
//! entry's XDR.
46+
//!
47+
//! Markers are placed inside functions that are only called when the type is
48+
//! actually used:
49+
//! - **Function parameters**: marker is triggered when deserializing the input.
50+
//! - **Function return values**: marker is triggered when serializing the output.
51+
//! - **Error returns**: marker is triggered via `Result<T, E>` serialization.
52+
//! - **Event publishes**: marker is triggered inside the `publish()` call.
53+
//! - **Nested types**: a type's marker function calls the marker functions of
54+
//! its field types, so nested types are transitively marked.
55+
//! - **Container types**: `Vec<T>`, `Map<K, V>`, `Option<T>`, and `Result<T, E>`
56+
//! propagate markers to their inner types.
57+
//!
58+
//! The Rust compiler's dead code elimination (DCE) removes markers for types
59+
//! that are never used, while keeping markers for types that are.
60+
//!
61+
//! Post-build tools (e.g. `stellar-cli`) scan the Wasm data section for
62+
//! `SpEcV1` markers, match them against spec entries, and strip any entries
63+
//! without a corresponding marker.
64+
//!
65+
//! ### Changed Behaviour
66+
//!
67+
//! When this feature is enabled the following macros change behaviour:
68+
//!
69+
//! #### [`contracttype`]
70+
//!
71+
//! Without this feature, spec entries are only generated for `pub` types (or
72+
//! when `export = true` is explicitly set). With this feature, spec entries
73+
//! and markers are generated for all types regardless of visibility, unless
74+
//! `export = false` is explicitly set. This ensures all types can participate
75+
//! in spec shaking.
76+
//!
77+
//! #### [`contracterror`]
78+
//!
79+
//! Same as [`contracttype`]: without this feature, spec entries are only
80+
//! generated for `pub` types. With this feature, spec entries and markers are
81+
//! generated for all error enums regardless of visibility, unless
82+
//! `export = false` is explicitly set.
83+
//!
84+
//! #### [`contractevent`]
85+
//!
86+
//! Markers are embedded for all events, allowing post-build tools to strip
87+
//! spec entries for events that are never published at a contract boundary.
88+
//!
89+
//! #### [`contractimport!`]
90+
//!
91+
//! Without this feature, [`contractimport!`] generates imported types with
92+
//! `export = false`. Imported types do not produce spec entries in the
93+
//! importing contract's spec. They are purely local Rust types used for
94+
//! serialization. The importing contract's spec only contains its own function
95+
//! definitions, and callers must look at the imported contract's spec to find
96+
//! the type definitions.
97+
//!
98+
//! With this feature, [`contractimport!`] generates imported types with
99+
//! `export = true`. Imported types produce spec entries and markers in the
100+
//! importing contract, just like locally defined types. This changes the
101+
//! contract's spec to be self-contained — it includes the type definitions for
102+
//! all types used at the contract boundary, regardless of where those types
103+
//! were originally defined. Specifically:
104+
//!
105+
//! - Imported types that are used in the contract's function signatures or
106+
//! events will have their markers survive DCE and their spec entries will be
107+
//! kept after shaking.
108+
//! - Imported types that are **not** used at any contract boundary will have
109+
//! their markers eliminated by DCE and their spec entries will be stripped.
110+
//!
111+
//! This ensures that a contract importing a large interface only includes spec
112+
//! entries for the types it actually uses, while still producing a
113+
//! self-contained spec.
114+
//!
115+
//! ### Build Requirements
116+
//!
117+
//! This feature requires building with `stellar contract build` from
118+
//! `stellar-cli` v26 or newer. Building directly with `cargo build` will
119+
//! produce a build error unless the
120+
//! `SOROBAN_SDK_BUILD_SYSTEM_SUPPORTS_SPEC_SHAKING_V2` environment variable is
121+
//! set.
122+
//!
123+
//! [`contracttype`]: crate::contracttype
124+
//! [`contracterror`]: crate::contracterror
125+
//! [`contractevent`]: crate::contractevent
126+
//! [`contractimport!`]: crate::contractimport

soroban-sdk/src/lib.rs

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
//! [Stellar]: https://stellar.org
1010
//! [Soroban]: https://stellar.org/soroban
1111
//!
12+
//! ### Features
13+
//!
14+
//! See [_features] for a list of all Cargo features and what they do.
15+
//!
1216
//! ### Migrating Major Versions
1317
//!
1418
//! See [_migrating] for a summary of how to migrate from one major version to another.
@@ -53,6 +57,7 @@
5357
#![cfg_attr(feature = "docs", feature(doc_cfg))]
5458
#![allow(dead_code)]
5559

60+
pub mod _features;
5661
pub mod _migrating;
5762

5863
#[cfg(all(target_family = "wasm", feature = "testutils"))]
@@ -172,7 +177,16 @@ pub use soroban_sdk_macros::symbol_short;
172177
/// - Enum variants must have a value convertible to u32.
173178
///
174179
/// Includes the type in the contract spec so that clients can generate bindings
175-
/// for the type.
180+
/// for the type. By default, spec entries are only generated for `pub` types
181+
/// (or when `export = true` is explicitly set).
182+
///
183+
/// ### `experimental_spec_shaking_v2`
184+
///
185+
/// When the [`experimental_spec_shaking_v2`][_features#experimental_spec_shaking_v2]
186+
/// feature is enabled, spec entries are generated for all types regardless of
187+
/// visibility, and markers are embedded that allow post-build tools to strip
188+
/// entries for types that are not used at a contract boundary. See
189+
/// [`_features`] for details.
176190
///
177191
/// ### Examples
178192
///
@@ -279,6 +293,16 @@ pub use soroban_sdk_macros::contracterror;
279293
/// contract.
280294
/// - Types for all contract types defined in the contract.
281295
///
296+
/// ### `experimental_spec_shaking_v2`
297+
///
298+
/// When the [`experimental_spec_shaking_v2`][_features#experimental_spec_shaking_v2]
299+
/// feature is enabled, imported types are generated with `export = true` so
300+
/// they produce spec entries and markers in the importing contract. Post-build
301+
/// tools strip entries for imported types that are not used at the importing
302+
/// contract's boundary. Without this feature, imported types use
303+
/// `export = false` and do not produce spec entries. See [`_features`] for
304+
/// details.
305+
///
282306
/// ### Examples
283307
///
284308
/// ```ignore
@@ -534,7 +558,16 @@ pub use soroban_sdk_macros::contractmeta;
534558
/// less in length.
535559
///
536560
/// Includes the type in the contract spec so that clients can generate bindings
537-
/// for the type.
561+
/// for the type. By default, spec entries are only generated for `pub` types
562+
/// (or when `export = true` is explicitly set).
563+
///
564+
/// ### `experimental_spec_shaking_v2`
565+
///
566+
/// When the [`experimental_spec_shaking_v2`][_features#experimental_spec_shaking_v2]
567+
/// feature is enabled, spec entries are generated for all types regardless of
568+
/// visibility, and markers are embedded that allow post-build tools to strip
569+
/// entries for types that are not used at a contract boundary. See
570+
/// [`_features`] for details.
538571
///
539572
/// ### Examples
540573
///
@@ -683,6 +716,13 @@ pub use soroban_sdk_macros::contracttype;
683716
/// Includes the event in the contract spec so that clients can generate bindings
684717
/// for the type and downstream systems can understand the meaning of the event.
685718
///
719+
/// ### `experimental_spec_shaking_v2`
720+
///
721+
/// When the [`experimental_spec_shaking_v2`][_features#experimental_spec_shaking_v2]
722+
/// feature is enabled, markers are embedded that allow post-build tools to strip
723+
/// spec entries for events that are never published at a contract boundary. See
724+
/// [`_features`] for details.
725+
///
686726
/// ### Examples
687727
///
688728
/// #### Define an Event

0 commit comments

Comments
 (0)