From 5c3b6c305d9b93b69090996f659d5043e2a4329a Mon Sep 17 00:00:00 2001 From: marc Date: Fri, 28 Nov 2025 08:04:37 +0100 Subject: [PATCH 1/5] - replace workspace rand import with strict 0.8.5 (versions above has changed api) - make default implementation of random in StableAbi trait, compatible with rust edition 2024 - add re-exports to rand, rand_chacha and bincode (narrows StableAbi strict versions) --- frozen-abi/Cargo.toml | 5 ++++- frozen-abi/src/lib.rs | 10 ++++++++++ frozen-abi/src/stable_abi.rs | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/frozen-abi/Cargo.toml b/frozen-abi/Cargo.toml index d7dedcddf..5eb7adb4b 100644 --- a/frozen-abi/Cargo.toml +++ b/frozen-abi/Cargo.toml @@ -37,7 +37,10 @@ thiserror = { workspace = true } [target.'cfg(not(target_os = "solana"))'.dependencies] im = { workspace = true, features = ["rayon", "serde"] } memmap2 = { workspace = true } -rand = { workspace = true } +# these are re-exports for StableAbi +rand = "0.8.5" +rand_chacha = "0.3.1" +bincode = "1.3.3" [target.'cfg(not(target_os = "solana"))'.dev-dependencies] bitflags = { workspace = true, features = ["serde"] } diff --git a/frozen-abi/src/lib.rs b/frozen-abi/src/lib.rs index 43037ac51..ecc18fd76 100644 --- a/frozen-abi/src/lib.rs +++ b/frozen-abi/src/lib.rs @@ -19,6 +19,16 @@ pub mod stable_abi; #[macro_use] extern crate solana_frozen_abi_macro; +#[cfg(feature = "frozen-abi")] +#[cfg(not(target_os = "solana"))] +pub use bincode; +#[cfg(feature = "frozen-abi")] +#[cfg(not(target_os = "solana"))] +pub use rand; +#[cfg(feature = "frozen-abi")] +#[cfg(not(target_os = "solana"))] +pub use rand_chacha; + // Not public API. Previously referenced by macro-generated code. Remove the // `log` dependency from Cargo.toml when this is cleaned up in the next major // version bump diff --git a/frozen-abi/src/stable_abi.rs b/frozen-abi/src/stable_abi.rs index e479f629a..475ae86a3 100644 --- a/frozen-abi/src/stable_abi.rs +++ b/frozen-abi/src/stable_abi.rs @@ -5,6 +5,6 @@ pub trait StableAbi: Sized { where Standard: rand::distributions::Distribution, { - rng.gen::() + rng.r#gen::() } } From d15f5186662a12a3d1f9fb847c689bb00ae98746 Mon Sep 17 00:00:00 2001 From: marc Date: Fri, 28 Nov 2025 09:37:11 +0100 Subject: [PATCH 2/5] update test_abi_digest to reference frozen-abi re-exports --- frozen-abi-macro/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frozen-abi-macro/src/lib.rs b/frozen-abi-macro/src/lib.rs index 8e2d70009..d82830116 100644 --- a/frozen-abi-macro/src/lib.rs +++ b/frozen-abi-macro/src/lib.rs @@ -345,9 +345,9 @@ fn quote_for_test( quote! { #[test] fn test_abi_digest() { - use ::rand::{SeedableRng, RngCore}; - use ::rand_chacha::ChaCha8Rng; - use ::bincode; + use ::solana_frozen_abi::rand::{SeedableRng, RngCore}; + use ::solana_frozen_abi::rand_chacha::ChaCha8Rng; + use ::solana_frozen_abi::bincode; use ::solana_frozen_abi::stable_abi::StableAbi; let mut rng = ChaCha8Rng::seed_from_u64(20666175621446498); From 026aefc31c5879ca2361d56a1b9e0c193450d00a Mon Sep 17 00:00:00 2001 From: marc Date: Fri, 28 Nov 2025 12:24:34 +0100 Subject: [PATCH 3/5] add better explination why frozen-abi re-exports rand, rand_chacha and bincode --- Cargo.lock | 2 ++ frozen-abi/Cargo.toml | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5b3311fdd..fac3bf1f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3041,6 +3041,7 @@ dependencies = [ name = "solana-frozen-abi" version = "3.1.0" dependencies = [ + "bincode", "bitflags 2.8.0", "boxcar", "bs58", @@ -3051,6 +3052,7 @@ dependencies = [ "log", "memmap2", "rand", + "rand_chacha", "serde", "serde_bytes", "serde_derive", diff --git a/frozen-abi/Cargo.toml b/frozen-abi/Cargo.toml index 5eb7adb4b..7d8e851ac 100644 --- a/frozen-abi/Cargo.toml +++ b/frozen-abi/Cargo.toml @@ -35,12 +35,14 @@ solana-frozen-abi-macro = { workspace = true } thiserror = { workspace = true } [target.'cfg(not(target_os = "solana"))'.dependencies] +# This dependency is used only to back `frozen-abi` StableAbi API +bincode = "1.3.3" im = { workspace = true, features = ["rayon", "serde"] } memmap2 = { workspace = true } -# these are re-exports for StableAbi +# These dependencies are used only to back `frozen-abi` StableAbi API, +# to avoid version skew and keep digest computation stable regardless of consumer dependencies. rand = "0.8.5" rand_chacha = "0.3.1" -bincode = "1.3.3" [target.'cfg(not(target_os = "solana"))'.dev-dependencies] bitflags = { workspace = true, features = ["serde"] } From 31151bdc5c6ce6b313ae0ea1d14fe3486813322c Mon Sep 17 00:00:00 2001 From: marc Date: Sat, 29 Nov 2025 16:33:53 +0100 Subject: [PATCH 4/5] fix bug in the frozen-abi script causing skipped test_abi tests --- scripts/test-frozen-abi.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/test-frozen-abi.sh b/scripts/test-frozen-abi.sh index 0fa7f4f62..12431017a 100755 --- a/scripts/test-frozen-abi.sh +++ b/scripts/test-frozen-abi.sh @@ -5,5 +5,5 @@ here="$(dirname "$0")" src_root="$(readlink -f "${here}/..")" cd "${src_root}" -./cargo nightly hack --features frozen-abi --ignore-unknown-features test --lib -- test_abi_digest --nocapture -./cargo nightly hack --features frozen-abi --ignore-unknown-features test --lib -- test_api_digest --nocapture +./cargo nightly test --features frozen-abi --lib -- test_abi_digest --nocapture +./cargo nightly test --features frozen-abi --lib -- test_api_digest --nocapture From 66633d4959d824f65f4e4b66f437b7b361c92c71 Mon Sep 17 00:00:00 2001 From: marc Date: Sat, 29 Nov 2025 17:15:47 +0100 Subject: [PATCH 5/5] enable StableAbi for Transaction --- transaction/src/lib.rs | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/transaction/src/lib.rs b/transaction/src/lib.rs index c27f28680..e988680e1 100644 --- a/transaction/src/lib.rs +++ b/transaction/src/lib.rs @@ -110,6 +110,9 @@ //! # Ok::<(), anyhow::Error>(()) //! ``` +#[cfg(feature = "frozen-abi")] +use solana_frozen_abi_macro::{frozen_abi, AbiExample, StableAbi}; + #[cfg(feature = "serde")] use { serde_derive::{Deserialize, Serialize}, @@ -176,8 +179,11 @@ const NONCED_TX_MARKER_IX_INDEX: u8 = 0; /// redundantly specifying the fee-payer is not strictly required. #[cfg_attr( feature = "frozen-abi", - derive(solana_frozen_abi_macro::AbiExample), - solana_frozen_abi_macro::frozen_abi(digest = "BLig4G2ysd7dcensK9bhKtnKvCQc1n65XdanyzsdWGXN") + derive(AbiExample, StableAbi), + frozen_abi( + api_digest = "BLig4G2ysd7dcensK9bhKtnKvCQc1n65XdanyzsdWGXN", + abi_digest = "BrQZ2jZhf9FDME3M3yNdhDBga8bHuLiAwWvZRvGwFrGh" + ) )] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] #[derive(Debug, PartialEq, Default, Eq, Clone)] @@ -198,6 +204,37 @@ pub struct Transaction { pub message: Message, } +#[cfg(feature = "frozen-abi")] +impl solana_frozen_abi::rand::prelude::Distribution + for solana_frozen_abi::rand::distributions::Standard +{ + fn sample(&self, rng: &mut R) -> Transaction { + let signatures: Vec = (0..rng.r#gen_range(1..100)) + .map(|_| Signature::from(std::array::from_fn(|_| rng.r#gen::()))) + .collect(); + let accounts: Vec = (0..rng.r#gen_range(1..100)) + .map(|_| AccountMeta { + pubkey: Address::new_from_array(rng.r#gen()), + is_signer: rng.r#gen(), + is_writable: rng.r#gen(), + }) + .collect(); + let data: Vec = (0..rng.r#gen_range(1..1000)).map(|_| rng.r#gen()).collect(); + let instructions: Vec = (0..rng.r#gen_range(1..100)) + .map(|_| Instruction { + program_id: Address::new_from_array(rng.r#gen()), + accounts: accounts.clone(), + data: data.clone(), + }) + .collect(); + + Transaction { + signatures, + message: Message::new(&instructions, Some(&Address::new_from_array(rng.r#gen()))), + } + } +} + impl Sanitize for Transaction { fn sanitize(&self) -> result::Result<(), SanitizeError> { if self.message.header.num_required_signatures as usize > self.signatures.len() {