Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 31 additions & 26 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,5 @@ lto = true
inherits = "release"
panic = "unwind"

[patch.crates-io.soroban-spec]
path = "../rs-soroban-sdk-spec-markers/soroban-spec"
1 change: 1 addition & 0 deletions cmd/crates/soroban-spec-tools/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ hex = { workspace = true }
wasmparser = { workspace = true }
base64 = { workspace = true }
thiserror = "1.0.31"
wasm-encoder = "0.235.0"


[dev-dependencies]
Expand Down
87 changes: 87 additions & 0 deletions cmd/crates/soroban-spec-tools/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,93 @@ impl Spec {
ScSpecEntry::read_xdr_iter(&mut read).collect::<Result<Vec<_>, xdr::Error>>()?,
))
}

/// Returns the filtered spec entries serialized as XDR bytes, filtering
/// based on markers in the WASM data section.
///
/// The SDK embeds markers in the data section for each type/event that is
/// actually used in the contract. These markers survive dead code elimination,
/// so we can filter out any spec entries that don't have corresponding markers.
///
/// Functions are always kept as they define the contract's API.
///
/// # Arguments
///
/// * `wasm_bytes` - The WASM binary to extract markers from
///
/// # Returns
///
/// XDR bytes of the filtered spec entries.
pub fn filtered_spec_xdr_with_markers(&self, wasm_bytes: &[u8]) -> Result<Vec<u8>, Error> {
use soroban_spec::marker;

// Extract markers from the WASM data section
let markers = marker::find_all(wasm_bytes);

// Filter all entries (types, events) based on markers
let filtered = marker::filter(self.spec.clone(), &markers);

let mut buffer = Vec::new();
let mut writer = Limited::new(Cursor::new(&mut buffer), Limits::none());
for entry in filtered {
entry.write_xdr(&mut writer)?;
}
Ok(buffer)
}
}

/// Replaces a custom section in WASM bytes with new content.
///
/// This function parses the WASM to find the target custom section, then rebuilds
/// the WASM by copying all other sections verbatim and appending the new custom
/// section at the end.
///
/// # Arguments
///
/// * `wasm_bytes` - The original WASM binary
/// * `section_name` - The name of the custom section to replace
/// * `new_content` - The new content for the custom section
///
/// # Returns
///
/// A new WASM binary with the custom section replaced.
pub fn replace_custom_section(
wasm_bytes: &[u8],
section_name: &str,
new_content: &[u8],
) -> Result<Vec<u8>, Error> {
use wasm_encoder::{CustomSection, Module, RawSection};
use wasmparser::Payload;

let mut module = Module::new();

let parser = wasmparser::Parser::new(0);
for payload in parser.parse_all(wasm_bytes) {
let payload = payload?;

// Skip the target custom section - we'll append the new one at the end
let is_target_section =
matches!(&payload, Payload::CustomSection(section) if section.name() == section_name);
if !is_target_section {
// For all other payloads that represent sections, copy them verbatim
if let Some((id, range)) = payload.as_section() {
let raw = RawSection {
id,
data: &wasm_bytes[range],
};
module.section(&raw);
}
}
}

// Append the new custom section
let custom = CustomSection {
name: section_name.into(),
data: new_content.into(),
};
module.section(&custom);

Ok(module.finish())
}

impl Display for Spec {
Expand Down
10 changes: 8 additions & 2 deletions cmd/crates/soroban-test/tests/it/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,21 +321,27 @@ fn parent_path() -> String {
}

fn with_flags(expected: &str) -> String {
const CFG_FLAG: &str =
"-- --cfg=soroban_sdk_build_system_supports_optimising_specs_using_data_markers";

let cargo_home = home::cargo_home().unwrap();
let registry_prefix = cargo_home.join("registry").join("src");
let registry_prefix = registry_prefix.display().to_string();
#[cfg(windows)]
let registry_prefix = registry_prefix.replace('\\', "/");

let vec: Vec<_> = if env::var("RUSTFLAGS").is_ok() {
expected.split('\n').map(ToString::to_string).collect()
expected
.split('\n')
.map(|x| format!("{x} {CFG_FLAG}"))
.collect()
} else {
expected
.split('\n')
.map(|x| {
let rustflags_value = format!("--remap-path-prefix={registry_prefix}=");
let escaped_value = escape(std::borrow::Cow::Borrowed(&rustflags_value));
format!("CARGO_BUILD_RUSTFLAGS={escaped_value} {x}")
format!("CARGO_BUILD_RUSTFLAGS={escaped_value} {x} {CFG_FLAG}")
})
.collect()
};
Expand Down
2 changes: 1 addition & 1 deletion cmd/soroban-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ glob = "0.3.1"
fqdn = "0.3.12"
open = "5.3.0"
url = "2.5.2"
wasm-gen = "0.1.4"
wasm-encoder = "0.235.0"
zeroize = "1.8.1"
keyring = { version = "3", features = ["apple-native", "windows-native", "sync-secret-service", "crypto-rust"], optional = true }
whoami = "1.5.2"
Expand Down
Loading
Loading