-
Notifications
You must be signed in to change notification settings - Fork 121
Add post-build stripping of unused types/events/errors from contract spec #2353
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds automatic filtering of unused types from contract specifications during the build process. It implements reachability analysis using fixed-point iteration to identify and preserve only types that are transitively referenced by contract functions, while always preserving functions and events. The implementation replaces wasm-gen with wasm-encoder for more flexible WASM manipulation capabilities.
Key changes:
- Implements a new filter module with reachability analysis to detect unused UDTs
- Refactors WASM manipulation to use wasm-encoder instead of wasm-gen, enabling section replacement
- Integrates filtering into the contract build pipeline after metadata injection
Reviewed changes
Copilot reviewed 6 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| cmd/soroban-cli/src/commands/contract/build.rs | Adds filter_spec call to build pipeline; refactors inject_meta to use wasm-encoder; adds new error types |
| cmd/soroban-cli/Cargo.toml | Replaces wasm-gen dependency with wasm-encoder 0.235.0 |
| cmd/crates/soroban-spec-tools/src/lib.rs | Exports new filter module |
| cmd/crates/soroban-spec-tools/src/filter.rs | Implements reachability analysis and filtering logic with comprehensive unit tests |
| cmd/crates/soroban-spec-tools/src/contract.rs | Adds filter_unused_types, filtered_spec_xdr methods and replace_custom_section utility; includes tests |
| cmd/crates/soroban-spec-tools/Cargo.toml | Adds wasm-encoder 0.235.0 dependency |
| Cargo.lock | Updates dependencies with wasm-encoder and wasmparser 0.235.0; removes obsolete wasm-gen dependencies |
What
Filter unused type and event definitions from the
contractspecv0WASM section duringstellar contract buildusing markers embedded by the SDK.Changes:
filtermodule insoroban-spec-toolswith marker extraction and filteringcompute_marker_hash(),extract_spec_markers(), andfilter_by_markers()functionsfiltered_spec_xdr_with_markers()method toSpecreplace_custom_section()function for WASM manipulationwasm-genwithwasm-encoderto enable section replacement (not just append)Why
Contract WASM files can contain unused type and event definitions in the
contractspecv0custom section that inflate binary size unnecessarily.The problem: Any exported
contracttypesorcontracteventsdefined in the SDK or any library that don't get used in the importing contract still end up in the contract spec. This results in awkward behaviour where we avoid exporting contracttypes in the SDK, even though doing so would be convenient and enable using contracttypes more frequently there.Why the SDK can't fix this alone: 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), 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.
Solution: The SDK now embeds markers in the regular data section for each type/event that is actually used. These markers survive dead code elimination only if the corresponding code is reachable. The CLI extracts these markers and filters the spec accordingly.
Examples of unused entries that get filtered:
Close #2030
Close stellar/rs-soroban-sdk#1569
Close stellar/rs-soroban-sdk#1330
How
The filtering uses markers embedded by the SDK:
Marker format (12 bytes):
SpEcmagic prefix (alternating case to avoid false positives)Filtering process:
SpEcmagic bytes)contractspecv0:contractspecv0custom section with the filtered versionWhy this works: The SDK's proc-macros generate code that references a static marker when a type/event is used. If that code path survives dead code elimination (DCE), the marker remains in the data section. If the type/event is never used, DCE removes the code and the marker disappears.
WASM manipulation: Previously the CLI only modified WASM in an append fashion. This PR uses
wasm-encoderwithRawSectionto copy sections verbatim and replace only the target custom section, enabling true section replacement.SDK Support Required
This feature requires SDK support for embedding markers. See: stellar/rs-soroban-sdk#1571
Try It Out
Install the modified
stellar-clithat strips unused specs:Import the modified
soroban-sdkthat marks used specs:Build using the stellar-cli:
Inspect the contract interface and it should only show types actually used at the boundary of the contract (inputs, outputs, and events):