Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
16 changes: 14 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,21 @@ build: build-libs build-test-wasms
build-libs: fmt
cargo hack build --release $(foreach c,$(LIB_CRATES),--package $(c))

# First, build crate used as WASM deps to other test crates.
# Then, build `test_spec_shaking_v2` without the spec shaking v2 env var to verify
# that it falls back to spec_shaking_v1 behaviour.
# Then, build the test wasms with MSRV by default, with some meta disabled for
# binary stability for tests.
build-test-wasms: fmt
# Build the test wasms with MSRV by default, with some meta disabled for
# binary stability for tests.
SOROBAN_SDK_BUILD_SYSTEM_SUPPORTS_SPEC_SHAKING_V2=1 \
RUSTUP_TOOLCHAIN=$(TEST_CRATES_RUSTUP_TOOLCHAIN) \
RUSTFLAGS='--cfg soroban_sdk_internal_no_rssdkver_meta' \
cargo build --release --target wasm32v1-none --package test_spec_import
RUSTUP_TOOLCHAIN=$(TEST_CRATES_RUSTUP_TOOLCHAIN) \
RUSTFLAGS='--cfg soroban_sdk_internal_no_rssdkver_meta' \
cargo build --release --target wasm32v1-none --package test_spec_shaking_v2
cp target/wasm32v1-none/release/test_spec_shaking_v2.wasm \
target/wasm32v1-none/release/test_spec_shaking_v2_no_env.wasm
SOROBAN_SDK_BUILD_SYSTEM_SUPPORTS_SPEC_SHAKING_V2=1 \
RUSTUP_TOOLCHAIN=$(TEST_CRATES_RUSTUP_TOOLCHAIN) \
RUSTFLAGS='--cfg soroban_sdk_internal_no_rssdkver_meta' \
Expand Down
11 changes: 7 additions & 4 deletions soroban-sdk-macros/src/derive_enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ use stellar_xdr::{
ScSpecUdtUnionCaseVoidV0, ScSpecUdtUnionV0, StringM, VecM, WriteXdr, SCSYMBOL_LIMIT,
};

use crate::{doc::docs_from_attrs, map_type::map_type, shaking, DEFAULT_XDR_RW_LIMITS};
use crate::{
doc::docs_from_attrs, map_type::map_type, shaking, spec_shaking_v2_enabled,
DEFAULT_XDR_RW_LIMITS,
};

pub fn derive_type_enum(
path: &Path,
Expand Down Expand Up @@ -175,9 +178,9 @@ pub fn derive_type_enum(
None
};

// SpecShakingMarker impl - only generated when spec is true and the
// experimental_spec_shaking_v2 feature is enabled.
let spec_shaking_impl = if cfg!(feature = "experimental_spec_shaking_v2") {
// SpecShakingMarker impl - only generated when spec is true and
// spec shaking v2 is enabled.
let spec_shaking_impl = if spec_shaking_v2_enabled() {
spec_xdr.as_ref().map(|spec_xdr| {
// Flatten all variant field types for shaking calls, deduplicating
// to avoid redundant calls for types that appear in multiple variants.
Expand Down
8 changes: 4 additions & 4 deletions soroban-sdk-macros/src/derive_enum_int.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use syn::{spanned::Spanned, Attribute, DataEnum, Error, ExprLit, Ident, Lit, Pat

use stellar_xdr::{ScSpecEntry, ScSpecUdtEnumCaseV0, WriteXdr};

use crate::{doc::docs_from_attrs, shaking, DEFAULT_XDR_RW_LIMITS};
use crate::{doc::docs_from_attrs, shaking, spec_shaking_v2_enabled, DEFAULT_XDR_RW_LIMITS};

// TODO: Add conversions to/from ScVal types.

Expand Down Expand Up @@ -97,9 +97,9 @@ pub fn derive_type_enum_int(
None
};

// SpecShakingMarker impl - only generated when spec is true and the
// experimental_spec_shaking_v2 feature is enabled.
let spec_shaking_impl = if cfg!(feature = "experimental_spec_shaking_v2") {
// SpecShakingMarker impl - only generated when spec is true and
// spec shaking v2 is enabled.
let spec_shaking_impl = if spec_shaking_v2_enabled() {
spec_xdr.as_ref().map(|spec_xdr| {
shaking::generate_marker_impl(
path,
Expand Down
8 changes: 4 additions & 4 deletions soroban-sdk-macros/src/derive_error_enum_int.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use stellar_xdr::curr as stellar_xdr;
use stellar_xdr::{ScSpecEntry, ScSpecUdtErrorEnumCaseV0, ScSpecUdtErrorEnumV0, StringM, WriteXdr};
use syn::{spanned::Spanned, Attribute, DataEnum, Error, ExprLit, Ident, Lit, Path};

use crate::{doc::docs_from_attrs, shaking, DEFAULT_XDR_RW_LIMITS};
use crate::{doc::docs_from_attrs, shaking, spec_shaking_v2_enabled, DEFAULT_XDR_RW_LIMITS};

pub fn derive_type_error_enum_int(
path: &Path,
Expand Down Expand Up @@ -95,9 +95,9 @@ pub fn derive_type_error_enum_int(
None
};

// SpecShakingMarker impl - only generated when spec is true and the
// experimental_spec_shaking_v2 feature is enabled.
let spec_shaking_impl = if cfg!(feature = "experimental_spec_shaking_v2") {
// SpecShakingMarker impl - only generated when spec is true and
// spec shaking v2 is enabled.
let spec_shaking_impl = if spec_shaking_v2_enabled() {
spec_xdr.as_ref().map(|spec_xdr| {
shaking::generate_marker_impl(
path,
Expand Down
10 changes: 5 additions & 5 deletions soroban-sdk-macros/src/derive_event.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
attribute::remove_attributes_from_item, default_crate_path, doc::docs_from_attrs,
map_type::map_type, shaking, symbol, DEFAULT_XDR_RW_LIMITS,
map_type::map_type, shaking, spec_shaking_v2_enabled, symbol, DEFAULT_XDR_RW_LIMITS,
};
use darling::{ast::NestedMeta, Error, FromMeta};
use heck::ToSnakeCase;
Expand Down Expand Up @@ -197,7 +197,7 @@ fn derive_impls(args: &ContractEventArgs, input: &DeriveInput) -> Result<TokenSt
"__SPEC_XDR_EVENT_{}",
input.ident.to_string().to_uppercase()
);
let spec_shaking_call = if export && cfg!(feature = "experimental_spec_shaking_v2") {
let spec_shaking_call = if export && spec_shaking_v2_enabled() {
Some(quote! { <Self as #path::SpecShakingMarker>::spec_shaking_marker(); })
} else {
None
Expand All @@ -215,9 +215,9 @@ fn derive_impls(args: &ContractEventArgs, input: &DeriveInput) -> Result<TokenSt
}
};

// SpecShakingMarker impl - only generated when export is true and the
// experimental_spec_shaking_v2 feature is enabled.
let spec_shaking_impl = if export && cfg!(feature = "experimental_spec_shaking_v2") {
// SpecShakingMarker impl - only generated when export is true and
// spec shaking v2 is enabled.
let spec_shaking_impl = if export && spec_shaking_v2_enabled() {
Some(shaking::generate_marker_impl(
path,
quote!(#ident),
Expand Down
11 changes: 7 additions & 4 deletions soroban-sdk-macros/src/derive_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ use stellar_xdr::{
ScSpecEntry, ScSpecTypeDef, ScSpecUdtStructFieldV0, ScSpecUdtStructV0, StringM, WriteXdr,
};

use crate::{doc::docs_from_attrs, map_type::map_type, shaking, DEFAULT_XDR_RW_LIMITS};
use crate::{
doc::docs_from_attrs, map_type::map_type, shaking, spec_shaking_v2_enabled,
DEFAULT_XDR_RW_LIMITS,
};

// TODO: Add field attribute for including/excluding fields in types.
// TODO: Better handling of partial types and types without all their fields and
Expand Down Expand Up @@ -107,9 +110,9 @@ pub fn derive_type_struct(
None
};

// SpecShakingMarker impl - only generated when spec is true and the
// experimental_spec_shaking_v2 feature is enabled.
let spec_shaking_impl = if cfg!(feature = "experimental_spec_shaking_v2") {
// SpecShakingMarker impl - only generated when spec is true and
// spec shaking v2 is enabled.
let spec_shaking_impl = if spec_shaking_v2_enabled() {
spec_xdr.as_ref().map(|spec_xdr| {
shaking::generate_marker_impl(
path,
Expand Down
11 changes: 7 additions & 4 deletions soroban-sdk-macros/src/derive_struct_tuple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ use stellar_xdr::{
ScSpecEntry, ScSpecTypeDef, ScSpecUdtStructFieldV0, ScSpecUdtStructV0, StringM, WriteXdr,
};

use crate::{doc::docs_from_attrs, map_type::map_type, shaking, DEFAULT_XDR_RW_LIMITS};
use crate::{
doc::docs_from_attrs, map_type::map_type, shaking, spec_shaking_v2_enabled,
DEFAULT_XDR_RW_LIMITS,
};

pub fn derive_type_struct_tuple(
path: &Path,
Expand Down Expand Up @@ -96,9 +99,9 @@ pub fn derive_type_struct_tuple(
None
};

// SpecShakingMarker impl - only generated when spec is true and the
// experimental_spec_shaking_v2 feature is enabled.
let spec_shaking_impl = if cfg!(feature = "experimental_spec_shaking_v2") {
// SpecShakingMarker impl - only generated when spec is true and
// spec shaking v2 is enabled.
let spec_shaking_impl = if spec_shaking_v2_enabled() {
spec_xdr.as_ref().map(|spec_xdr| {
shaking::generate_marker_impl(
path,
Expand Down
22 changes: 15 additions & 7 deletions soroban-sdk-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,15 @@ pub(crate) fn default_crate_path() -> Path {
parse_str("soroban_sdk").unwrap()
}

/// Returns true if spec shaking v2 should be used. Requires both the
/// `experimental_spec_shaking_v2` feature to be enabled on the macro crate AND
/// the `SOROBAN_SDK_BUILD_SYSTEM_SUPPORTS_SPEC_SHAKING_V2` env var to be set
/// at the time the macro expands (i.e. when the consumer crate is compiled).
fn spec_shaking_v2_enabled() -> bool {
cfg!(feature = "experimental_spec_shaking_v2")
&& std::env::var("SOROBAN_SDK_BUILD_SYSTEM_SUPPORTS_SPEC_SHAKING_V2").is_ok()
}

#[derive(Debug, FromMeta)]
struct ContractSpecArgs {
name: Type,
Expand Down Expand Up @@ -428,10 +437,10 @@ pub fn contracttype(metadata: TokenStream, input: TokenStream) -> TokenStream {
}
// If the export argument has a value, do as it instructs regarding
// exporting. If it does not have a value, export if the type is pub,
// or always export when spec shaking is enabled.
// or always export when spec shaking v2 is enabled.
let gen_spec = if let Some(export) = args.export {
export
} else if cfg!(feature = "experimental_spec_shaking_v2") {
} else if spec_shaking_v2_enabled() {
true
} else {
matches!(input.vis, Visibility::Public(_))
Expand Down Expand Up @@ -502,10 +511,10 @@ pub fn contracterror(metadata: TokenStream, input: TokenStream) -> TokenStream {
let attrs = &input.attrs;
// If the export argument has a value, do as it instructs regarding
// exporting. If it does not have a value, export if the type is pub,
// or always export when spec shaking is enabled.
// or always export when spec shaking v2 is enabled.
let gen_spec = if let Some(export) = args.export {
export
} else if cfg!(feature = "experimental_spec_shaking_v2") {
} else if spec_shaking_v2_enabled() {
true
} else {
matches!(input.vis, Visibility::Public(_))
Expand Down Expand Up @@ -691,10 +700,9 @@ pub fn contractimport(metadata: TokenStream) -> TokenStream {
}
};

// Generate with options based on whether the experimental_spec_shaking_v2
// feature is enabled.
// Generate with options based on whether spec shaking v2 is enabled
let opts = GenerateOptions {
export: cfg!(feature = "experimental_spec_shaking_v2"),
export: spec_shaking_v2_enabled(),
};
match generate_from_wasm_with_options(&wasm, &args.file, args.sha256.as_deref(), &opts) {
Ok(code) => quote! { #code },
Expand Down
30 changes: 14 additions & 16 deletions soroban-sdk/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,23 @@ pub fn main() {
}

// When the experimental_spec_shaking_v2 feature is enabled, check for an env var from the
// build system (Stellar CLI) that indicates it supports spec optimization using markers.
// build system (like Stellar CLI) that indicates it supports spec optimization using markers.
// If the env var is set, enable spec_shaking_v2 cfg for the crate. If not, fall back to
// spec shaking v1 behavior and emit a warning on wasm targets.
println!("cargo::rustc-check-cfg=cfg(spec_shaking_v2)");
if std::env::var("CARGO_FEATURE_EXPERIMENTAL_SPEC_SHAKING_V2").is_ok() {
let env_name = "SOROBAN_SDK_BUILD_SYSTEM_SUPPORTS_SPEC_SHAKING_V2";
println!("cargo::rerun-if-env-changed={env_name}");
if std::env::var(env_name).is_err()
&& std::env::var("CARGO_CFG_TARGET_FAMILY").unwrap_or_default() == "wasm"
{
panic!(
"\
\n\nerror: soroban-sdk feature 'experimental_spec_shaking_v2' requires stellar-cli v25.2.0+\
\n\
\nThe soroban-sdk 'experimental_spec_shaking_v2' feature requires building\
\nwith `stellar contract build` from stellar-cli v25.2.0 or newer.\
\n\
\nTo fix, either:\
\n - Build with `stellar contract build` using stellar-cli v25.2.0+\
\n - Disable the feature by removing 'experimental_spec_shaking_v2' from\
\n the soroban-sdk import features list in Cargo.toml.\
\n"
if std::env::var(env_name).is_ok() {
println!("cargo::rustc-cfg=spec_shaking_v2");
} else if std::env::var("CARGO_CFG_TARGET_FAMILY").unwrap_or_default() == "wasm" {
println!(
"cargo::warning=soroban-sdk: feature 'experimental_spec_shaking_v2' was enabled but not used, \
because this build was not started by a tool that supports spec shaking v2. \
Falling back to spec shaking v1. To use v2, use a build tool that supports \
spec shaking v2 such as stellar-cli v25.2.0+ with `stellar contract build`. \
To manually use v2 without a supporting build tool, set the env var \
SOROBAN_SDK_BUILD_SYSTEM_SUPPORTS_SPEC_SHAKING_V2 before building."
);
}
}
Expand Down
15 changes: 10 additions & 5 deletions soroban-sdk/src/_features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,16 @@
//!
//! ### Build Requirements
//!
//! This feature requires building with `stellar contract build` from
//! `stellar-cli` v25.2.0 or newer. Building directly with `cargo build` will
//! produce a build error unless the
//! `SOROBAN_SDK_BUILD_SYSTEM_SUPPORTS_SPEC_SHAKING_V2` environment variable is
//! set.
//! Spec shaking v2 requires the
//! `SOROBAN_SDK_BUILD_SYSTEM_SUPPORTS_SPEC_SHAKING_V2` environment variable to
//! be set at build time. This is automatically set by `stellar contract build`
//! from `stellar-cli` v25.2.0 or newer.
//!
//! When the `experimental_spec_shaking_v2` feature is enabled but the env var
//! is not set, the SDK falls back to spec shaking v1 behavior and emits a
//! compiler warning on wasm targets. This allows contracts to build with plain
//! `cargo build` without errors, while still benefiting from v2 when built
//! with compatible tooling.
//!
//! [`contracttype`]: crate::contracttype
//! [`contracterror`]: crate::contracterror
Expand Down
4 changes: 2 additions & 2 deletions soroban-sdk/src/into_val_for_contract_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub trait IntoValForContractFn {
fn into_val_for_contract_fn(self, env: &Env) -> Val;
}

#[cfg(feature = "experimental_spec_shaking_v2")]
#[cfg(spec_shaking_v2)]
#[doc(hidden)]
#[allow(deprecated)]
impl<T> IntoValForContractFn for T
Expand All @@ -33,7 +33,7 @@ where
}
}

#[cfg(not(feature = "experimental_spec_shaking_v2"))]
#[cfg(not(spec_shaking_v2))]
#[doc(hidden)]
#[allow(deprecated)]
impl<T> IntoValForContractFn for T
Expand Down
8 changes: 4 additions & 4 deletions soroban-sdk/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,11 @@ const _: () = {
val = concat!(env!("CARGO_PKG_VERSION"), "#", env!("GIT_REVISION")),
);

// An indicator of the spec shaking version in use. Signals to the stellar-cli that the .wasm
// An indicator of the spec shaking version in use. Signals to the post-build system that the .wasm
// needs to have its spec shaken. See soroban_spec::shaking for constants and version detection.
// The contractmeta! macro requires string literals, so we assert the literals match the
// constants defined in soroban_spec::shaking.
#[cfg(feature = "experimental_spec_shaking_v2")]
#[cfg(spec_shaking_v2)]
contractmeta!(key = "rssdk_spec_shaking", val = "2");
};

Expand Down Expand Up @@ -1195,9 +1195,9 @@ mod into_val_for_contract_fn;
#[allow(deprecated)]
pub use into_val_for_contract_fn::IntoValForContractFn;

#[cfg(feature = "experimental_spec_shaking_v2")]
#[cfg(spec_shaking_v2)]
mod spec_shaking;
#[cfg(feature = "experimental_spec_shaking_v2")]
#[cfg(spec_shaking_v2)]
#[doc(hidden)]
pub use spec_shaking::SpecShakingMarker;

Expand Down
4 changes: 2 additions & 2 deletions soroban-sdk/src/try_from_val_for_contract_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub trait TryFromValForContractFn<E: Env, V: ?Sized>: Sized {
fn try_from_val_for_contract_fn(env: &E, v: &V) -> Result<Self, Self::Error>;
}

#[cfg(feature = "experimental_spec_shaking_v2")]
#[cfg(spec_shaking_v2)]
#[doc(hidden)]
#[allow(deprecated)]
impl<E: Env, T, U> TryFromValForContractFn<E, T> for U
Expand All @@ -44,7 +44,7 @@ where
}
}

#[cfg(not(feature = "experimental_spec_shaking_v2"))]
#[cfg(not(spec_shaking_v2))]
#[doc(hidden)]
#[allow(deprecated)]
impl<E: Env, T, U> TryFromValForContractFn<E, T> for U
Expand Down
5 changes: 0 additions & 5 deletions tests-expanded/test_account_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,6 @@ impl Error {
*b"\0\0\0\x04\0\0\0\0\0\0\0\0\0\0\0\x05Error\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\x04Fail\0\0\0\x01"
}
}
impl soroban_sdk::SpecShakingMarker for Error {
#[doc(hidden)]
#[inline(always)]
fn spec_shaking_marker() {}
}
impl TryFrom<soroban_sdk::Error> for Error {
type Error = soroban_sdk::Error;
#[inline(always)]
Expand Down
10 changes: 0 additions & 10 deletions tests-expanded/test_auth_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1124,11 +1124,6 @@ mod test_a {
*b"\0\0\0\x04\0\0\0\0\0\0\0\0\0\0\0\x05Error\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\x07Decline\0\0\0\0\x01"
}
}
impl soroban_sdk::SpecShakingMarker for Error {
#[doc(hidden)]
#[inline(always)]
fn spec_shaking_marker() {}
}
impl TryFrom<soroban_sdk::Error> for Error {
type Error = soroban_sdk::Error;
#[inline(always)]
Expand Down Expand Up @@ -2606,11 +2601,6 @@ mod test_b {
*b"\0\0\0\x04\0\0\0\0\0\0\0\0\0\0\0\x05Error\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\x07Decline\0\0\0\0\x01"
}
}
impl soroban_sdk::SpecShakingMarker for Error {
#[doc(hidden)]
#[inline(always)]
fn spec_shaking_marker() {}
}
impl TryFrom<soroban_sdk::Error> for Error {
type Error = soroban_sdk::Error;
#[inline(always)]
Expand Down
Loading
Loading