diff --git a/Cargo.lock b/Cargo.lock index f2799a7b69..b566a0e2e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2034,7 +2034,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.52.0", ] [[package]] @@ -4286,7 +4286,7 @@ dependencies = [ "once_cell", "socket2 0.6.4", "tracing", - "windows-sys 0.60.2", + "windows-sys 0.52.0", ] [[package]] @@ -4675,7 +4675,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.9.4", - "windows-sys 0.60.2", + "windows-sys 0.52.0", ] [[package]] @@ -5344,9 +5344,8 @@ dependencies = [ [[package]] name = "soroban-builtin-sdk-macros" -version = "28.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86ffd329211a50add3965a8f4a8f70e24fc5c8268c945566ab963029b12dce40" +version = "29.0.0" +source = "git+https://github.com/stellar/rs-soroban-env?rev=de68ee914401e70d3d8350a4d004c0442943324e#de68ee914401e70d3d8350a4d004c0442943324e" dependencies = [ "itertools 0.13.0", "proc-macro2", @@ -5449,9 +5448,8 @@ dependencies = [ [[package]] name = "soroban-env-common" -version = "28.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "610bb12ee937a56c2b629f8eb16efb7e47607cba4e79ab0c24132b9a53dd19a0" +version = "29.0.0" +source = "git+https://github.com/stellar/rs-soroban-env?rev=de68ee914401e70d3d8350a4d004c0442943324e#de68ee914401e70d3d8350a4d004c0442943324e" dependencies = [ "arbitrary", "crate-git-revision 0.0.9", @@ -5468,9 +5466,8 @@ dependencies = [ [[package]] name = "soroban-env-guest" -version = "28.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d383176b27bb286f718ab0ff5713bd9b01132089151266359bd9b20f38684cf" +version = "29.0.0" +source = "git+https://github.com/stellar/rs-soroban-env?rev=de68ee914401e70d3d8350a4d004c0442943324e#de68ee914401e70d3d8350a4d004c0442943324e" dependencies = [ "soroban-env-common", "static_assertions", @@ -5478,9 +5475,8 @@ dependencies = [ [[package]] name = "soroban-env-host" -version = "28.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36d7e5920c200939164cc58038224e2d90d7e2fabbfa505d6e2129d648dce7e2" +version = "29.0.0" +source = "git+https://github.com/stellar/rs-soroban-env?rev=de68ee914401e70d3d8350a4d004c0442943324e#de68ee914401e70d3d8350a4d004c0442943324e" dependencies = [ "ark-bls12-381", "ark-bn254", @@ -5515,9 +5511,8 @@ dependencies = [ [[package]] name = "soroban-env-macros" -version = "28.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "077600bb175ea54592c1ac5983b8fb34ec9ab7a65f298af11d687b61e9d646a4" +version = "29.0.0" +source = "git+https://github.com/stellar/rs-soroban-env?rev=de68ee914401e70d3d8350a4d004c0442943324e#de68ee914401e70d3d8350a4d004c0442943324e" dependencies = [ "itertools 0.13.0", "proc-macro2", @@ -5535,8 +5530,7 @@ version = "28.0.0" [[package]] name = "soroban-ledger-snapshot" version = "28.0.0-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e68b020e9838df2affe8488998943b81d183c7ea4990691a863b39c13d3516e" +source = "git+https://github.com/stellar/rs-soroban-sdk?rev=7093a641145329526b221e683fbb5e74f9710053#7093a641145329526b221e683fbb5e74f9710053" dependencies = [ "serde", "serde_json", @@ -5549,8 +5543,7 @@ dependencies = [ [[package]] name = "soroban-sdk" version = "28.0.0-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "864a530b8a1eb07c364f3f4b2f069b737ae87df203fd290baebddb9119f2dfe5" +source = "git+https://github.com/stellar/rs-soroban-sdk?rev=7093a641145329526b221e683fbb5e74f9710053#7093a641145329526b221e683fbb5e74f9710053" dependencies = [ "arbitrary", "bytes-lit", @@ -5566,15 +5559,16 @@ dependencies = [ "soroban-env-host", "soroban-ledger-snapshot", "soroban-sdk-macros", + "soroban-spec", "stellar-strkey 0.0.16", + "stellar-xdr", "visibility", ] [[package]] name = "soroban-sdk-macros" version = "28.0.0-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66c2bfe91c8ec2179dcab5284ee99215d9271fed2eb8b9819bcd45001ac861f" +source = "git+https://github.com/stellar/rs-soroban-sdk?rev=7093a641145329526b221e683fbb5e74f9710053#7093a641145329526b221e683fbb5e74f9710053" dependencies = [ "darling 0.20.11", "heck 0.5.0", @@ -5584,7 +5578,6 @@ dependencies = [ "quote", "sha2 0.10.9", "soroban-env-common", - "soroban-spec", "soroban-spec-rust", "stellar-xdr", "syn 2.0.118", @@ -5593,11 +5586,9 @@ dependencies = [ [[package]] name = "soroban-spec" version = "28.0.0-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f20e3c44fa7939fece5c8988efa7c9e062ab5596ae7497035a2bc59ffd48816" +source = "git+https://github.com/stellar/rs-soroban-sdk?rev=7093a641145329526b221e683fbb5e74f9710053#7093a641145329526b221e683fbb5e74f9710053" dependencies = [ "base64 0.22.1", - "sha2 0.10.9", "stellar-xdr", "thiserror 1.0.69", "wasmparser 0.116.1", @@ -5606,8 +5597,7 @@ dependencies = [ [[package]] name = "soroban-spec-rust" version = "28.0.0-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43eb9293928c35e949818f83fe5eacfe0cf45ebb32552304aaea66279b7c8403" +source = "git+https://github.com/stellar/rs-soroban-sdk?rev=7093a641145329526b221e683fbb5e74f9710053#7093a641145329526b221e683fbb5e74f9710053" dependencies = [ "prettyplease", "proc-macro2", @@ -5705,8 +5695,7 @@ dependencies = [ [[package]] name = "soroban-token-sdk" version = "28.0.0-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7053541ed1cf2cbfc78625d2b619c496c0748d20d75aee019b2f68169386f4c" +source = "git+https://github.com/stellar/rs-soroban-sdk?rev=7093a641145329526b221e683fbb5e74f9710053#7093a641145329526b221e683fbb5e74f9710053" dependencies = [ "soroban-sdk", ] @@ -5714,8 +5703,7 @@ dependencies = [ [[package]] name = "soroban-token-spec" version = "28.0.0-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27fe6acb049550f221fcb294c8ca3ede0e89609ea3d480c63b84b8cf4197c416" +source = "git+https://github.com/stellar/rs-soroban-sdk?rev=7093a641145329526b221e683fbb5e74f9710053#7093a641145329526b221e683fbb5e74f9710053" dependencies = [ "soroban-sdk", "soroban-token-sdk", @@ -5724,8 +5712,7 @@ dependencies = [ [[package]] name = "soroban-wasmi" version = "0.31.1-soroban.20.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "710403de32d0e0c35375518cb995d4fc056d0d48966f2e56ea471b8cb8fc9719" +source = "git+https://github.com/stellar/wasmi?rev=0ed3f3dee30dc41ebe21972399e0a73a41944aa0#0ed3f3dee30dc41ebe21972399e0a73a41944aa0" dependencies = [ "smallvec", "spin", @@ -5765,8 +5752,7 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "stellar-asset-spec" version = "28.0.0-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4194d1b54a5337c277a0656c2d4da940439f9eb3f2e17a919bc686a870429250" +source = "git+https://github.com/stellar/rs-soroban-sdk?rev=7093a641145329526b221e683fbb5e74f9710053#7093a641145329526b221e683fbb5e74f9710053" dependencies = [ "soroban-sdk", "soroban-token-sdk", @@ -5882,8 +5868,7 @@ dependencies = [ [[package]] name = "stellar-xdr" version = "28.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93d09ff8b9f919b084f664003c4c546ac66a76affd5429460dbe29f4b326f8e" +source = "git+https://github.com/stellar/rs-stellar-xdr?rev=9c6c2f8c09b678d1ebed87b3f41f621068badcf4#9c6c2f8c09b678d1ebed87b3f41f621068badcf4" dependencies = [ "arbitrary", "base64 0.22.1", @@ -6071,7 +6056,7 @@ dependencies = [ "getrandom 0.3.3", "once_cell", "rustix 1.0.8", - "windows-sys 0.60.2", + "windows-sys 0.52.0", ] [[package]] @@ -7091,15 +7076,13 @@ dependencies = [ [[package]] name = "wasmi_arena" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "104a7f73be44570cac297b3035d76b169d6599637631cf37a1703326a0727073" +version = "0.4.0" +source = "git+https://github.com/stellar/wasmi?rev=0ed3f3dee30dc41ebe21972399e0a73a41944aa0#0ed3f3dee30dc41ebe21972399e0a73a41944aa0" [[package]] name = "wasmi_core" version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf1a7db34bff95b85c261002720c00c3a6168256dcb93041d3fa2054d19856a" +source = "git+https://github.com/stellar/wasmi?rev=0ed3f3dee30dc41ebe21972399e0a73a41944aa0#0ed3f3dee30dc41ebe21972399e0a73a41944aa0" dependencies = [ "downcast-rs", "libm", diff --git a/Cargo.toml b/Cargo.toml index 023d794096..76b6384b0a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -121,6 +121,26 @@ testcontainers = "0.27.2" httpmock = "0.7.0" astral-tokio-tar = "0.6.0" +[patch.crates-io] +# Pending https://github.com/stellar/rs-stellar-xdr/pull/566, which widens the +# user-defined type name limit so that a fully qualified type name fits. Pinned +# to the same rev rs-soroban-sdk#1970 uses so the graph has one stellar-xdr. +stellar-xdr = { git = "https://github.com/stellar/rs-stellar-xdr", rev = "9c6c2f8c09b678d1ebed87b3f41f621068badcf4" } +# Pending https://github.com/stellar/rs-soroban-sdk/pull/1970, which names +# user-defined types in contract specs by their fully qualified path. +soroban-spec = { git = "https://github.com/stellar/rs-soroban-sdk", rev = "7093a641145329526b221e683fbb5e74f9710053" } +soroban-spec-rust = { git = "https://github.com/stellar/rs-soroban-sdk", rev = "7093a641145329526b221e683fbb5e74f9710053" } +soroban-sdk = { git = "https://github.com/stellar/rs-soroban-sdk", rev = "7093a641145329526b221e683fbb5e74f9710053" } +soroban-token-sdk = { git = "https://github.com/stellar/rs-soroban-sdk", rev = "7093a641145329526b221e683fbb5e74f9710053" } +stellar-asset-spec = { git = "https://github.com/stellar/rs-soroban-sdk", rev = "7093a641145329526b221e683fbb5e74f9710053" } +soroban-ledger-snapshot = { git = "https://github.com/stellar/rs-soroban-sdk", rev = "7093a641145329526b221e683fbb5e74f9710053" } +# Pending https://github.com/stellar/rs-soroban-env/pull/1733, which adapts the +# host to the XDR constants that rs-stellar-xdr#580 changes from u64 to u32. +# rs-soroban-sdk#1970 is on that 29.x line, so pin to the same rev it uses. +soroban-env-common = { git = "https://github.com/stellar/rs-soroban-env", rev = "de68ee914401e70d3d8350a4d004c0442943324e" } +soroban-env-guest = { git = "https://github.com/stellar/rs-soroban-env", rev = "de68ee914401e70d3d8350a4d004c0442943324e" } +soroban-env-host = { git = "https://github.com/stellar/rs-soroban-env", rev = "de68ee914401e70d3d8350a4d004c0442943324e" } + [profile.release] overflow-checks = true diff --git a/Makefile b/Makefile index 397040e81d..9f1ddbd4ea 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,7 @@ build: cargo build build-test-wasms: - SOROBAN_SDK_BUILD_SYSTEM_SUPPORTS_SPEC_SHAKING_V2=1 cargo build --package 'test_*' --profile test-wasms --target wasm32v1-none + SOROBAN_SDK_BUILD_SYSTEM_SUPPORTS_SPEC_SHAKING_V2=1 SOROBAN_SDK_BUILD_SYSTEM_SUPPORTS_REDUCING_FULL_NAMES=1 cargo build --package 'test_*' --profile test-wasms --target wasm32v1-none build-test: build-test-wasms build-fixtures install diff --git a/cmd/crates/soroban-spec-tools/src/contract.rs b/cmd/crates/soroban-spec-tools/src/contract.rs index bf877dccc1..89ef225fd6 100644 --- a/cmd/crates/soroban-spec-tools/src/contract.rs +++ b/cmd/crates/soroban-spec-tools/src/contract.rs @@ -316,7 +316,7 @@ fn indent(s: &str, n: usize) -> String { .join("\n") } -fn format_name(lib: &StringM<80>, name: &StringM<60>) -> String { +fn format_name(lib: &StringM<80>, name: &StringM<{ crate::UDT_NAME_LIMIT }>) -> String { if lib.is_empty() { sanitize(&name.to_utf8_string_lossy()) } else { diff --git a/cmd/crates/soroban-spec-tools/src/event.rs b/cmd/crates/soroban-spec-tools/src/event.rs index 496cdb1ccf..3cd5fc1df6 100644 --- a/cmd/crates/soroban-spec-tools/src/event.rs +++ b/cmd/crates/soroban-spec-tools/src/event.rs @@ -294,7 +294,7 @@ mod tests { ScSpecEventV0 { doc: StringM::default(), lib: StringM::default(), - name: make_symbol(name), + name: name.try_into().unwrap(), prefix_topics: prefix_topics .into_iter() .map(make_symbol) diff --git a/cmd/crates/soroban-spec-tools/src/lib.rs b/cmd/crates/soroban-spec-tools/src/lib.rs index bccf21828a..9563c38407 100644 --- a/cmd/crates/soroban-spec-tools/src/lib.rs +++ b/cmd/crates/soroban-spec-tools/src/lib.rs @@ -12,7 +12,7 @@ use stellar_xdr::{ ScSpecTypeTuple, ScSpecTypeUdt, ScSpecTypeVec, ScSpecUdtEnumV0, ScSpecUdtErrorEnumCaseV0, ScSpecUdtErrorEnumV0, ScSpecUdtStructV0, ScSpecUdtUnionCaseTupleV0, ScSpecUdtUnionCaseV0, ScSpecUdtUnionCaseVoidV0, ScSpecUdtUnionV0, ScString, ScSymbol, ScVal, ScVec, StringM, - UInt128Parts, UInt256Parts, Uint256, VecM, + UInt128Parts, UInt256Parts, Uint256, VecM, SC_SPEC_TYPE_NAME_LIMIT, }; pub mod contract; @@ -25,6 +25,12 @@ pub mod wasm; pub use contract::sanitize; pub use verify::SpecWarning; +/// The XDR limit on the length of a user-defined type name +/// ([`SC_SPEC_TYPE_NAME_LIMIT`]), as the `u32` that `StringM`'s const generic +/// expects. +#[allow(clippy::cast_possible_truncation)] +pub const UDT_NAME_LIMIT: u32 = SC_SPEC_TYPE_NAME_LIMIT as u32; + #[derive(thiserror::Error, Debug)] pub enum Error { #[error("an unknown error occurred")] @@ -372,7 +378,7 @@ impl Spec { Ok(val) } - fn parse_udt(&self, name: &StringM<60>, value: &Value) -> Result { + fn parse_udt(&self, name: &StringM, value: &Value) -> Result { let name = &name.to_utf8_string_lossy(); match (self.find(name)?, value) { (ScSpecEntry::UdtStructV0(strukt), Value::Object(map)) => { @@ -649,7 +655,11 @@ impl Spec { /// # Panics /// /// May panic - pub fn udt_to_json(&self, name: &StringM<60>, sc_obj: &ScVal) -> Result { + pub fn udt_to_json( + &self, + name: &StringM, + sc_obj: &ScVal, + ) -> Result { let name = &name.to_utf8_string_lossy(); let udt = self.find(name)?; Ok(match (sc_obj, udt) { @@ -2345,7 +2355,7 @@ mod tests { ScSpecEventV0 { doc: StringM::default(), lib: StringM::default(), - name: ScSymbol(name.try_into().unwrap()), + name: name.try_into().unwrap(), prefix_topics: VecM::default(), params: VecM::default(), data_format: stellar_xdr::ScSpecEventDataFormat::SingleValue, diff --git a/cmd/crates/soroban-test/tests/it/build.rs b/cmd/crates/soroban-test/tests/it/build.rs index 84c42fd32c..0e1605269e 100644 --- a/cmd/crates/soroban-test/tests/it/build.rs +++ b/cmd/crates/soroban-test/tests/it/build.rs @@ -736,7 +736,11 @@ fn parent_path() -> String { } fn with_flags(expected: &str) -> String { - const ENV_VAR: &str = "SOROBAN_SDK_BUILD_SYSTEM_SUPPORTS_SPEC_SHAKING_V2=1"; + // Serialized in sorted key order, so REDUCING_FULL_NAMES precedes SPEC_SHAKING_V2. + const ENV_VARS: &str = concat!( + "SOROBAN_SDK_BUILD_SYSTEM_SUPPORTS_REDUCING_FULL_NAMES=1 ", + "SOROBAN_SDK_BUILD_SYSTEM_SUPPORTS_SPEC_SHAKING_V2=1" + ); let cargo_home = home::cargo_home().unwrap(); let registry_prefix = cargo_home.join("registry").join("src"); @@ -747,7 +751,7 @@ fn with_flags(expected: &str) -> String { let vec: Vec<_> = if env::var("RUSTFLAGS").is_ok() { expected .split('\n') - .map(|x| format!("{ENV_VAR} {x}")) + .map(|x| format!("{ENV_VARS} {x}")) .collect() } else { expected @@ -755,7 +759,7 @@ fn with_flags(expected: &str) -> String { .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} {ENV_VAR} {x}") + format!("CARGO_BUILD_RUSTFLAGS={escaped_value} {ENV_VARS} {x}") }) .collect() }; diff --git a/cmd/soroban-cli/src/commands/contract/arg_parsing.rs b/cmd/soroban-cli/src/commands/contract/arg_parsing.rs index c97cfa551f..6ffdb34436 100644 --- a/cmd/soroban-cli/src/commands/contract/arg_parsing.rs +++ b/cmd/soroban-cli/src/commands/contract/arg_parsing.rs @@ -1074,7 +1074,8 @@ mod tests { }; // Build a minimal Spec with a union type: enum MyEnum { Unit } - let union_name: StringM<60> = "MyEnum".try_into().unwrap(); + let union_name: StringM<{ soroban_spec_tools::UDT_NAME_LIMIT }> = + "MyEnum".try_into().unwrap(); let case_name: StringM<60> = "Unit".try_into().unwrap(); let spec = Spec(Some(vec![ScSpecEntry::UdtUnionV0(ScSpecUdtUnionV0 { doc: StringM::default(), @@ -1123,7 +1124,8 @@ mod tests { ScSpecUdtUnionCaseV0, ScSpecUdtUnionCaseVoidV0, ScSpecUdtUnionV0, StringM, }; - let union_name: StringM<60> = "MyEnum".try_into().unwrap(); + let union_name: StringM<{ soroban_spec_tools::UDT_NAME_LIMIT }> = + "MyEnum".try_into().unwrap(); let spec = Spec(Some(vec![ScSpecEntry::UdtUnionV0(ScSpecUdtUnionV0 { doc: StringM::default(), lib: StringM::default(), @@ -1190,7 +1192,7 @@ mod tests { use stellar_xdr::{ ScSpecEntry, ScSpecTypeUdt, ScSpecUdtStructFieldV0, ScSpecUdtStructV0, StringM, }; - let struct_name: StringM<60> = name.try_into().unwrap(); + let struct_name: StringM<{ soroban_spec_tools::UDT_NAME_LIMIT }> = name.try_into().unwrap(); let fields_xdr: Vec = fields .iter() .map(|(n, t)| ScSpecUdtStructFieldV0 { @@ -1324,7 +1326,8 @@ mod tests { ScSpecUdtUnionV0, StringM, }; - let union_name: StringM<60> = "Choice".try_into().unwrap(); + let union_name: StringM<{ soroban_spec_tools::UDT_NAME_LIMIT }> = + "Choice".try_into().unwrap(); let spec = Spec(Some(vec![ScSpecEntry::UdtUnionV0(ScSpecUdtUnionV0 { doc: StringM::default(), lib: StringM::default(), @@ -1362,7 +1365,8 @@ mod tests { ScSpecUdtUnionV0, StringM, }; - let union_name: StringM<60> = "OneOf".try_into().unwrap(); + let union_name: StringM<{ soroban_spec_tools::UDT_NAME_LIMIT }> = + "OneOf".try_into().unwrap(); let spec = Spec(Some(vec![ScSpecEntry::UdtUnionV0(ScSpecUdtUnionV0 { doc: StringM::default(), lib: StringM::default(), diff --git a/cmd/soroban-cli/src/commands/contract/build.rs b/cmd/soroban-cli/src/commands/contract/build.rs index 5a00d1894b..ab0e5f57af 100644 --- a/cmd/soroban-cli/src/commands/contract/build.rs +++ b/cmd/soroban-cli/src/commands/contract/build.rs @@ -346,6 +346,11 @@ impl Cmd { // optimization using markers. cmd.env("SOROBAN_SDK_BUILD_SYSTEM_SUPPORTS_SPEC_SHAKING_V2", "1"); + // Set env var to inform the SDK that this CLI reduces fully + // qualified user-defined type names in the spec down to their + // simple names. + cmd.env("SOROBAN_SDK_BUILD_SYSTEM_SUPPORTS_REDUCING_FULL_NAMES", "1"); + let cmd_str = serialize_command(&cmd); if self.print_commands_only { @@ -366,6 +371,7 @@ impl Cmd { self.inject_meta(&target_file_path)?; Self::filter_spec(&target_file_path)?; + Self::reduce_spec(&print, &p.name, &target_file_path)?; let final_path = if let Some(out_dir) = &self.out_dir { fs::create_dir_all(out_dir).map_err(Error::CreatingOutDir)?; @@ -535,6 +541,65 @@ impl Cmd { fs::write(target_file_path, new_wasm).map_err(Error::WritingWasmFile) } + /// Reduces user-defined type names in the contract spec to their simple + /// form, rewriting the `contractspecv0` section in place. + /// + /// Contract specs may name user-defined types by their fully qualified path + /// (e.g. `my_contract::inner::State`). This follows each to its simple name + /// (e.g. `State`), rewriting every reference, so the on-chain spec and every + /// downstream tool see the short names. Names that would collide are + /// disambiguated with a numeric suffix, which is warned about. + /// + /// Runs after `filter_spec` so only the entries that survive shaking are + /// reduced, but is otherwise independent of spec shaking. + fn reduce_spec(print: &Print, name: &str, target_file_path: &PathBuf) -> Result<(), Error> { + use soroban_spec_tools::contract::Spec; + use soroban_spec_tools::wasm::replace_custom_section; + + let wasm_bytes = fs::read(target_file_path).map_err(Error::ReadingWasmFile)?; + let spec = Spec::new(&wasm_bytes)?; + + let reduced = soroban_spec::reduce::reduce(&spec.spec); + + // If every name was already simple, leave the wasm untouched. + if reduced.renames().all(|r| !r.renamed()) { + return Ok(()); + } + + let collisions: Vec<_> = reduced.renames().filter(|r| r.collision()).collect(); + if !collisions.is_empty() { + use std::fmt::Write as _; + let mut msg = format!( + "{name}: reduced type names collided and were disambiguated with a numeric suffix:" + ); + for rename in collisions { + let _ = write!( + msg, + "\n {} -> {}", + String::from_utf8_lossy(&rename.from), + String::from_utf8_lossy(&rename.to), + ); + } + print.warnln(msg); + } + + // Encode the reduced entries and replace the contractspecv0 section. + let mut reduced_xdr = Vec::new(); + let mut writer = Limited::new( + Cursor::new(&mut reduced_xdr), + Limits::depth(XDR_DEPTH_LIMIT), + ); + for entry in reduced.into_entries() { + entry.write_xdr(&mut writer)?; + } + + let new_wasm = replace_custom_section(&wasm_bytes, "contractspecv0", &reduced_xdr) + .map_err(|e| Error::WasmParsing(e.to_string()))?; + + fs::remove_file(target_file_path).map_err(Error::DeletingArtifact)?; + fs::write(target_file_path, new_wasm).map_err(Error::WritingWasmFile) + } + fn encoded_new_meta(&self) -> Result, Error> { let mut new_meta: Vec = Vec::new(); @@ -936,6 +1001,46 @@ mod tests { assert!(Cmd::try_parse_from(["build", "--pull"]).is_err()); } + #[test] + fn reduce_spec_shortens_qualified_names_in_wasm() { + use soroban_spec_tools::contract::Spec; + use soroban_spec_tools::wasm::replace_custom_section; + use stellar_xdr::{ScSpecEntry, ScSpecUdtStructV0, VecM}; + + // A spec with a single struct whose name is fully qualified. + let entry = ScSpecEntry::UdtStructV0(ScSpecUdtStructV0 { + doc: StringM::default(), + lib: StringM::default(), + name: "mycrate::mymod::MyType".to_string().try_into().unwrap(), + fields: VecM::default(), + }); + let mut spec_xdr = Vec::new(); + entry + .write_xdr(&mut Limited::new( + Cursor::new(&mut spec_xdr), + Limits::depth(XDR_DEPTH_LIMIT), + )) + .unwrap(); + + // Embed the spec in a minimal (empty) wasm module and write it out. + let wasm = replace_custom_section(b"\0asm\x01\0\0\0", "contractspecv0", &spec_xdr).unwrap(); + let path = + env::temp_dir().join(format!("reduce_spec_test_{}.wasm", std::process::id())); + fs::write(&path, &wasm).unwrap(); + + Cmd::reduce_spec(&Print::new(true), "pkg", &path).unwrap(); + + let out = fs::read(&path).unwrap(); + fs::remove_file(&path).ok(); + let spec = Spec::new(&out).unwrap(); + + assert_eq!(spec.spec.len(), 1); + let ScSpecEntry::UdtStructV0(s) = &spec.spec[0] else { + panic!("expected a struct entry, got {:?}", spec.spec[0]); + }; + assert_eq!(s.name.to_vec(), b"MyType".to_vec()); + } + #[test] fn serialize_command_shell_escapes_args_with_metacharacters() { let raw_arg = "--manifest-path=/path/to/contract;touch PWNED;#/Cargo.toml"; diff --git a/cmd/soroban-cli/src/commands/contract/info/interface.rs b/cmd/soroban-cli/src/commands/contract/info/interface.rs index a2dfa1de38..2ab2aaf1c7 100644 --- a/cmd/soroban-cli/src/commands/contract/info/interface.rs +++ b/cmd/soroban-cli/src/commands/contract/info/interface.rs @@ -65,6 +65,8 @@ impl Cmd { } }; + // Type names in the spec are already reduced to simple names during + // `contract build`, so show the spec as it is stored in the contract. let res = match self.output { InfoOutput::XdrBase64 => base64, InfoOutput::Json => serde_json::to_string(&spec)?, diff --git a/deny.toml b/deny.toml index dd05ae3b5b..6ae9eaf1b2 100644 --- a/deny.toml +++ b/deny.toml @@ -231,7 +231,15 @@ allow-registry = ["https://github.com/rust-lang/crates.io-index"] # List of URLs for allowed Git repositories allow-git = [ # Only used by the unpublished doc-gen crate, temporarily until PR is merged: https://github.com/ConnorGray/clap-markdown/pull/48 - "https://github.com/ConnorGray/clap-markdown?rev=42956b342cef3325d9060fc43995d595e7c8aa66" + "https://github.com/ConnorGray/clap-markdown?rev=42956b342cef3325d9060fc43995d595e7c8aa66", + + # Temporary patches, remove once merged and released: + # https://github.com/stellar/rs-stellar-xdr/pull/566, which widens the + # user-defined type name limit so a fully qualified type name fits. + "https://github.com/stellar/rs-stellar-xdr?rev=82677e1dfe49b6b94fc6440d9c58be74d2a33bff", + # https://github.com/stellar/rs-soroban-sdk/pull/1970, which names + # user-defined types in contract specs by their fully qualified path. + "https://github.com/stellar/rs-soroban-sdk?rev=788b536af88a1b0a4d473dc8050b6a44c668e80e", ] [sources.allow-org]