From 5c3b6c305d9b93b69090996f659d5043e2a4329a Mon Sep 17 00:00:00 2001 From: marc Date: Fri, 28 Nov 2025 08:04:37 +0100 Subject: [PATCH 01/10] - 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 02/10] 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 03/10] 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 d89dc1e209b05076cd7f1a2e412b2ae635ddb00e Mon Sep 17 00:00:00 2001 From: marc Date: Sat, 29 Nov 2025 14:38:52 +0100 Subject: [PATCH 04/10] enable StableAbi for VoteStateV4 --- vote-interface/src/state/vote_state_v4.rs | 49 +++++++++++++++++++++-- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/vote-interface/src/state/vote_state_v4.rs b/vote-interface/src/state/vote_state_v4.rs index e15d3465c..0392e8bab 100644 --- a/vote-interface/src/state/vote_state_v4.rs +++ b/vote-interface/src/state/vote_state_v4.rs @@ -7,7 +7,7 @@ use serde_derive::{Deserialize, Serialize}; #[cfg(feature = "serde")] use serde_with::serde_as; #[cfg(feature = "frozen-abi")] -use solana_frozen_abi_macro::{frozen_abi, AbiExample}; +use solana_frozen_abi_macro::{frozen_abi, AbiExample, StableAbi}; #[cfg(any(target_os = "solana", feature = "bincode"))] use solana_instruction::error::InstructionError; use { @@ -20,8 +20,11 @@ use { #[cfg_attr( feature = "frozen-abi", - frozen_abi(digest = "2H9WgTh7LgdnpinvEwxzP3HF6SDuKp6qdwFmJk9jHDRP"), - derive(AbiExample) + frozen_abi( + api_digest = "2H9WgTh7LgdnpinvEwxzP3HF6SDuKp6qdwFmJk9jHDRP", + abi_digest = "4g7TRPnQxr9X61b5LHDB29LVL89EDQnZyFXbKivMccFQ" + ), + derive(AbiExample, StableAbi) )] #[cfg_attr(feature = "serde", cfg_eval::cfg_eval, serde_as)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] @@ -70,6 +73,46 @@ pub struct VoteStateV4 { pub last_timestamp: BlockTimestamp, } +#[cfg(feature = "frozen-abi")] +impl solana_frozen_abi::rand::prelude::Distribution + for solana_frozen_abi::rand::distributions::Standard +{ + fn sample(&self, rng: &mut R) -> VoteStateV4 { + let bls_pubkey_compressed = Some(std::array::from_fn(|_| rng.gen())); + let votes: VecDeque<_> = (0..rng.gen_range(0..1000)) + .map(|_| LandedVote { + latency: rng.gen(), + lockout: crate::state::Lockout::new(rng.gen()), + }) + .collect(); + let epoch_credits: Vec<_> = (0..rng.gen_range(0..1000)) + .map(|_| (rng.gen(), rng.gen(), rng.gen())) + .collect(); + + VoteStateV4 { + node_pubkey: Pubkey::new_from_array(rng.r#gen()), + authorized_withdrawer: Pubkey::new_from_array(rng.r#gen()), + inflation_rewards_collector: Pubkey::new_from_array(rng.r#gen()), + block_revenue_collector: Pubkey::new_from_array(rng.r#gen()), + inflation_rewards_commission_bps: rng.r#gen(), + block_revenue_commission_bps: rng.r#gen(), + pending_delegator_rewards: rng.r#gen(), + bls_pubkey_compressed, + votes, + root_slot: Some(rng.r#gen()), + authorized_voters: AuthorizedVoters::new( + rng.r#gen(), + Pubkey::new_from_array(rng.r#gen()), + ), + epoch_credits, + last_timestamp: BlockTimestamp { + slot: rng.r#gen(), + timestamp: rng.r#gen(), + }, + } + } +} + impl VoteStateV4 { /// Upper limit on the size of the Vote State /// when votes.len() is MAX_LOCKOUT_HISTORY. From cce4c412cf05ede6f4eb91c779b966e034292e90 Mon Sep 17 00:00:00 2001 From: marc Date: Sat, 29 Nov 2025 14:56:25 +0100 Subject: [PATCH 05/10] enable StableAbi in VoteStateV3 --- vote-interface/src/state/vote_state_v3.rs | 53 +++++++++++++++++++++-- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/vote-interface/src/state/vote_state_v3.rs b/vote-interface/src/state/vote_state_v3.rs index bb0ca85da..e269c0c25 100644 --- a/vote-interface/src/state/vote_state_v3.rs +++ b/vote-interface/src/state/vote_state_v3.rs @@ -5,7 +5,7 @@ use arbitrary::Arbitrary; #[cfg(feature = "serde")] use serde_derive::{Deserialize, Serialize}; #[cfg(feature = "frozen-abi")] -use solana_frozen_abi_macro::{frozen_abi, AbiExample}; +use solana_frozen_abi_macro::{frozen_abi, AbiExample, StableAbi}; use { super::{ BlockTimestamp, CircBuf, LandedVote, Lockout, VoteInit, MAX_EPOCH_CREDITS_HISTORY, @@ -23,8 +23,11 @@ use { #[cfg_attr( feature = "frozen-abi", - frozen_abi(digest = "pZqasQc6duzMYzpzU7eriHH9cMXmubuUP4NmCrkWZjt"), - derive(AbiExample) + frozen_abi( + api_digest = "pZqasQc6duzMYzpzU7eriHH9cMXmubuUP4NmCrkWZjt", + abi_digest = "7YQhTLmxbPdzyT8k5iMm2uecz2Y4cYQfbZr3zaaSyy3o" + ), + derive(AbiExample, StableAbi) )] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] #[derive(Debug, Default, PartialEq, Eq, Clone)] @@ -61,6 +64,50 @@ pub struct VoteStateV3 { pub last_timestamp: BlockTimestamp, } +#[cfg(feature = "frozen-abi")] +impl solana_frozen_abi::rand::prelude::Distribution + for solana_frozen_abi::rand::distributions::Standard +{ + fn sample(&self, rng: &mut R) -> VoteStateV3 { + let votes: VecDeque<_> = (0..rng.r#gen_range(0..1000)) + .map(|_| LandedVote { + latency: rng.r#gen(), + lockout: crate::state::Lockout::new(rng.r#gen()), + }) + .collect(); + + let mut prior_voters: CircBuf<(Pubkey, Epoch, Epoch)> = CircBuf::default(); + for _ in 0..rng.r#gen_range(0..1000) { + prior_voters.append(( + Pubkey::new_from_array(rng.r#gen()), + rng.r#gen(), + rng.r#gen(), + )); + } + let epoch_credits: Vec<_> = (0..rng.gen_range(0..1000)) + .map(|_| (rng.r#gen(), rng.r#gen(), rng.r#gen())) + .collect(); + + VoteStateV3 { + node_pubkey: Pubkey::new_from_array(rng.r#gen()), + authorized_withdrawer: Pubkey::new_from_array(rng.r#gen()), + commission: rng.r#gen(), + votes, + root_slot: Some(rng.r#gen()), + authorized_voters: AuthorizedVoters::new( + rng.r#gen(), + Pubkey::new_from_array(rng.r#gen()), + ), + prior_voters, + epoch_credits, + last_timestamp: BlockTimestamp { + slot: rng.r#gen(), + timestamp: rng.r#gen(), + }, + } + } +} + impl VoteStateV3 { pub fn new(vote_init: &VoteInit, clock: &Clock) -> Self { Self { From 56b4f152b67c838543b9756c1e19b3565565ab34 Mon Sep 17 00:00:00 2001 From: marc Date: Sat, 29 Nov 2025 15:08:23 +0100 Subject: [PATCH 06/10] enable StableAbi for VoteState1_14_11 --- .../src/state/vote_state_1_14_11.rs | 47 ++++++++++++++++++- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/vote-interface/src/state/vote_state_1_14_11.rs b/vote-interface/src/state/vote_state_1_14_11.rs index 6d7606f84..c37149b7c 100644 --- a/vote-interface/src/state/vote_state_1_14_11.rs +++ b/vote-interface/src/state/vote_state_1_14_11.rs @@ -2,13 +2,19 @@ use super::*; #[cfg(feature = "dev-context-only-utils")] use arbitrary::Arbitrary; +#[cfg(feature = "frozen-abi")] +use solana_frozen_abi_macro::{frozen_abi, AbiExample, StableAbi}; + // Offset used for VoteState version 1_14_11 const DEFAULT_PRIOR_VOTERS_OFFSET: usize = 82; #[cfg_attr( feature = "frozen-abi", - solana_frozen_abi_macro::frozen_abi(digest = "2rjXSWaNeAdoUNJDC5otC7NPR1qXHvLMuAs5faE4DPEt"), - derive(solana_frozen_abi_macro::AbiExample) + frozen_abi( + api_digest = "2rjXSWaNeAdoUNJDC5otC7NPR1qXHvLMuAs5faE4DPEt", + abi_digest = "DEmsGurYNiQfW2bkPBuxEKoMfxbPgkGejpBiNj8HywAS" + ), + derive(AbiExample, StableAbi) )] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] #[derive(Debug, Default, PartialEq, Eq, Clone)] @@ -45,6 +51,43 @@ pub struct VoteState1_14_11 { pub last_timestamp: BlockTimestamp, } +#[cfg(feature = "frozen-abi")] +impl solana_frozen_abi::rand::prelude::Distribution + for solana_frozen_abi::rand::distributions::Standard +{ + fn sample(&self, rng: &mut R) -> VoteState1_14_11 { + let votes: VecDeque<_> = (0..rng.gen_range(0..1000)) + .map(|_| Lockout::new(rng.gen())) + .collect(); + + let mut prior_voters: CircBuf<(Pubkey, Epoch, Epoch)> = CircBuf::default(); + for _ in 0..rng.gen_range(0..1000) { + prior_voters.append((Pubkey::new_from_array(rng.gen()), rng.gen(), rng.gen())); + } + let epoch_credits: Vec<_> = (0..rng.gen_range(0..1000)) + .map(|_| (rng.gen(), rng.gen(), rng.gen())) + .collect(); + + VoteState1_14_11 { + node_pubkey: Pubkey::new_from_array(rng.r#gen()), + authorized_withdrawer: Pubkey::new_from_array(rng.r#gen()), + commission: rng.r#gen(), + votes, + root_slot: Some(rng.r#gen()), + authorized_voters: AuthorizedVoters::new( + rng.r#gen(), + Pubkey::new_from_array(rng.r#gen()), + ), + prior_voters, + epoch_credits, + last_timestamp: BlockTimestamp { + slot: rng.r#gen(), + timestamp: rng.r#gen(), + }, + } + } +} + impl VoteState1_14_11 { pub fn get_rent_exempt_reserve(rent: &Rent) -> u64 { rent.minimum_balance(Self::size_of()) From 46cc6ffaaf61363a1d50ddec59bff6869723a3f8 Mon Sep 17 00:00:00 2001 From: marc Date: Mon, 1 Dec 2025 13:27:07 +0100 Subject: [PATCH 07/10] more concise cfg attributes for re-exported types / StableAbi mod --- frozen-abi/src/lib.rs | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/frozen-abi/src/lib.rs b/frozen-abi/src/lib.rs index ecc18fd76..1497bcf59 100644 --- a/frozen-abi/src/lib.rs +++ b/frozen-abi/src/lib.rs @@ -11,23 +11,16 @@ pub mod abi_digester; pub mod abi_example; #[cfg(feature = "frozen-abi")] pub mod hash; -#[cfg(feature = "frozen-abi")] -#[cfg(not(target_os = "solana"))] + +#[cfg(all(feature = "frozen-abi", not(target_os = "solana")))] pub mod stable_abi; #[cfg(feature = "frozen-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; +#[cfg(all(feature = "frozen-abi", not(target_os = "solana")))] +pub use {bincode, rand, 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 From 7f70a55144a83232c6646157cca822128f01d2ee Mon Sep 17 00:00:00 2001 From: marc Date: Mon, 1 Dec 2025 13:29:33 +0100 Subject: [PATCH 08/10] align re-export deps commentary --- frozen-abi/Cargo.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frozen-abi/Cargo.toml b/frozen-abi/Cargo.toml index 7d8e851ac..7a5497947 100644 --- a/frozen-abi/Cargo.toml +++ b/frozen-abi/Cargo.toml @@ -35,7 +35,8 @@ 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 +# These dependencies are used only to back `frozen-abi` StableAbi API, +# to avoid version skew and keep digest computation stable regardless of consumer dependencies. bincode = "1.3.3" im = { workspace = true, features = ["rayon", "serde"] } memmap2 = { workspace = true } From 9af843b60db97b8e060e6bd041a57c5d43ff4192 Mon Sep 17 00:00:00 2001 From: marc Date: Mon, 1 Dec 2025 13:30:57 +0100 Subject: [PATCH 09/10] add edition 2024 lints --- frozen-abi/src/lib.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/frozen-abi/src/lib.rs b/frozen-abi/src/lib.rs index 1497bcf59..bf02cbbfb 100644 --- a/frozen-abi/src/lib.rs +++ b/frozen-abi/src/lib.rs @@ -1,6 +1,13 @@ #![allow(incomplete_features)] #![cfg_attr(docsrs, feature(doc_cfg))] #![cfg_attr(feature = "frozen-abi", feature(specialization))] +// Activate some of the Rust 2024 lints to make the future migration easier. +#![warn(if_let_rescope)] +#![warn(keyword_idents_2024)] +#![warn(rust_2024_incompatible_pat)] +#![warn(tail_expr_drop_order)] +#![warn(unsafe_attr_outside_unsafe)] +#![warn(unsafe_op_in_unsafe_fn)] // Allows macro expansion of `use ::solana_frozen_abi::*` to work within this crate extern crate self as solana_frozen_abi; From 099844f32258bf7adc1904229368f41a431cff98 Mon Sep 17 00:00:00 2001 From: marc Date: Sat, 29 Nov 2025 15:27:58 +0100 Subject: [PATCH 10/10] enable StableAbi in Vote, VoteUpdate and TowerSync --- .../src/state/vote_instruction_data.rs | 75 +++++++++++++++++-- 1 file changed, 68 insertions(+), 7 deletions(-) diff --git a/vote-interface/src/state/vote_instruction_data.rs b/vote-interface/src/state/vote_instruction_data.rs index 262293c9c..2e11cb6e0 100644 --- a/vote-interface/src/state/vote_instruction_data.rs +++ b/vote-interface/src/state/vote_instruction_data.rs @@ -1,5 +1,5 @@ #[cfg(feature = "frozen-abi")] -use solana_frozen_abi_macro::{frozen_abi, AbiExample}; +use solana_frozen_abi_macro::{frozen_abi, AbiExample, StableAbi}; use { crate::state::{ Lockout, BLS_PROOF_OF_POSSESSION_COMPRESSED_SIZE, BLS_PUBLIC_KEY_COMPRESSED_SIZE, @@ -18,8 +18,11 @@ use { #[cfg_attr( feature = "frozen-abi", - frozen_abi(digest = "GvUzgtcxhKVVxPAjSntXGPqjLZK5ovgZzCiUP1tDpB9q"), - derive(AbiExample) + frozen_abi( + api_digest = "GvUzgtcxhKVVxPAjSntXGPqjLZK5ovgZzCiUP1tDpB9q", + abi_digest = "BbtfeZFE7Fesk4LdkMAu2NCp4DpMLTAmAd31mcuewGJn" + ), + derive(AbiExample, StableAbi) )] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] #[derive(Default, Debug, PartialEq, Eq, Clone)] @@ -32,6 +35,23 @@ pub struct Vote { pub timestamp: Option, } +#[cfg(feature = "frozen-abi")] +impl solana_frozen_abi::rand::prelude::Distribution + for solana_frozen_abi::rand::distributions::Standard +{ + fn sample(&self, rng: &mut R) -> Vote { + let slots: Vec = (0..rng.r#gen_range(0..1000)) + .map(|_| rng.r#gen::().into()) + .collect(); + + Vote { + slots, + hash: Hash::new_from_array(rng.r#gen()), + timestamp: Some(rng.r#gen()), + } + } +} + impl Vote { pub fn new(slots: Vec, hash: Hash) -> Self { Self { @@ -48,8 +68,11 @@ impl Vote { #[cfg_attr( feature = "frozen-abi", - frozen_abi(digest = "CxyuwbaEdzP7jDCZyxjgQvLGXadBUZF3LoUvbSpQ6tYN"), - derive(AbiExample) + frozen_abi( + api_digest = "CxyuwbaEdzP7jDCZyxjgQvLGXadBUZF3LoUvbSpQ6tYN", + abi_digest = "7zwscqJMVfyoS4cJdcZa4fuCgwKYM3GUZhvQsFfpKm7e" + ), + derive(AbiExample, StableAbi) )] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] #[derive(Default, Debug, PartialEq, Eq, Clone)] @@ -64,6 +87,23 @@ pub struct VoteStateUpdate { pub timestamp: Option, } +#[cfg(feature = "frozen-abi")] +impl solana_frozen_abi::rand::prelude::Distribution + for solana_frozen_abi::rand::distributions::Standard +{ + fn sample(&self, rng: &mut R) -> VoteStateUpdate { + let lockouts: VecDeque<_> = (0..rng.r#gen_range(0..1000)) + .map(|_| Lockout::new(rng.r#gen())) + .collect(); + VoteStateUpdate { + lockouts, + root: Some(rng.r#gen::().into()), + hash: Hash::new_from_array(rng.r#gen()), + timestamp: Some(rng.r#gen()), + } + } +} + impl From> for VoteStateUpdate { fn from(recent_slots: Vec<(Slot, u32)>) -> Self { let lockouts: VecDeque = recent_slots @@ -102,8 +142,11 @@ impl VoteStateUpdate { #[cfg_attr( feature = "frozen-abi", - frozen_abi(digest = "6UDiQMH4wbNwkMHosPMtekMYu2Qa6CHPZ2ymK4mc6FGu"), - derive(AbiExample) + frozen_abi( + api_digest = "6UDiQMH4wbNwkMHosPMtekMYu2Qa6CHPZ2ymK4mc6FGu", + abi_digest = "H4XQ8ftqobHG3jNoCnVgJN4wRJJq1wnUQy8vGK3mp9PX" + ), + derive(AbiExample, StableAbi) )] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] #[derive(Default, Debug, PartialEq, Eq, Clone)] @@ -122,6 +165,24 @@ pub struct TowerSync { pub block_id: Hash, } +#[cfg(feature = "frozen-abi")] +impl solana_frozen_abi::rand::prelude::Distribution + for solana_frozen_abi::rand::distributions::Standard +{ + fn sample(&self, rng: &mut R) -> TowerSync { + let lockouts: VecDeque<_> = (0..rng.r#gen_range(0..1000)) + .map(|_| Lockout::new(rng.r#gen())) + .collect(); + TowerSync { + lockouts, + root: Some(rng.r#gen()), + hash: Hash::new_from_array(rng.r#gen()), + timestamp: Some(rng.r#gen()), + block_id: Hash::new_from_array(rng.r#gen()), + } + } +} + impl From> for TowerSync { fn from(recent_slots: Vec<(Slot, u32)>) -> Self { let lockouts: VecDeque = recent_slots