Skip to content

stellar contract build should strip contract specs, removing types that are not referenced by functions or events #2030

@leighmcculloch

Description

@leighmcculloch

What problem does your feature solve?

Contract WASM files can contain unused type definitions in the contractspecv0 custom section. These unused types increase WASM binary size unnecessarily.

Any exported contracttypes defined in the SDK, or any library for that matter, that don't get used in the importing contract still end up in the contract spec. This results in some awkward behaviour where we avoid exporting contracttypes in the SDK, even though doing so would be convenient and enable using contracttypes more frequently there.

Because of how proc-macros run in isolation and cannot coordinate in wasm builds in Rust (the ctor crate cannot be used like we use it in non-wasm builds in tests to coordinate), there's nothing the soroban-sdk can do to identify whether a contracttype that sometimes needs to be exported hasn't been used and can be excluded.

Examples of unused types that bloat the spec:

  • Error enums from imported libraries (e.g., #[contracterror] types from dependencies) that are never used by any function
  • Types that are defined but never referenced by any function inputs/outputs
  • Transitive type dependencies that no longer apply after refactoring

What would you like to see?

During stellar contract build, automatically filter the contractspecv0 section to remove unused types:

  1. Parse the spec entries from the compiled WASM after cargo build
  2. Perform reachability analysis starting from all functions using fixed-point iteration
  3. Keep:
    • All functions (FunctionV0)
    • All events (EventV0)
    • All UDTs (UdtStructV0, UdtUnionV0, UdtEnumV0, UdtErrorEnumV0) that are directly or transitively referenced by function inputs/outputs
  4. Remove: UDT types that are defined but never referenced by any function
  5. Replace the contractspecv0 custom section with the filtered version using wasm-encoder

Types reference other types via ScSpecTypeDef::Udt(name). The reachability analysis recursively traverses Vec, Map, Option, Result, and Tuple type definitions to find all referenced UDTs.

This will require rewriting the wasm file after build. Currently the stellar-cli does modify the wasm (for meta injection), but only in an append fashion. The new approach uses wasm-encoder with RawSection to copy sections verbatim and replace only the target custom section.

What alternatives are there?

  • Manual cleanup: Developers could manually remove unused type imports, but this is error-prone and tedious
  • SDK-level filtering: The Soroban SDK could avoid emitting unused types, but proc-macros run in isolation and cannot coordinate to identify unused types
  • Filter by library: Only filter types exported from the soroban-sdk (types can specify what library they came from), but filtering all unused types is more comprehensive

Related

Metadata

Metadata

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

Status
Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions