From 8c148868912bcb7e8ea419965d0fc37dcaab4b67 Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Wed, 2 Aug 2023 23:15:24 +0200 Subject: [PATCH] sdk: Limited Borsh 0.9 support (Pubkey and helpers) (#32511) * sdk: Implement Borsh 0.9 traits on Pubkey * Alphabetize cargo.toml * Add backwards-compatible borsh file * Add borsh0_10.rs for more clarity * Deprecate `borsh` utils, use borsh0_10 everywhere * Mark borsh 0.9 helpers as deprecated * Add macros for deriving helper impls * Add borsh 0.9 tests * Refactor tests into macro --- Cargo.lock | 1 + cost-model/src/cost_model.rs | 2 +- program-runtime/src/compute_budget.rs | 2 +- programs/sbf/Cargo.lock | 1 + sdk/program/Cargo.toml | 1 + sdk/program/src/borsh.rs | 517 +++++++++++++------------- sdk/program/src/borsh0_10.rs | 17 + sdk/program/src/borsh0_9.rs | 39 ++ sdk/program/src/lib.rs | 2 + sdk/program/src/pubkey.rs | 42 +++ sdk/program/src/stake/state.rs | 2 +- sdk/src/lib.rs | 20 +- 12 files changed, 368 insertions(+), 278 deletions(-) create mode 100644 sdk/program/src/borsh0_10.rs create mode 100644 sdk/program/src/borsh0_9.rs diff --git a/Cargo.lock b/Cargo.lock index 4b4adacef..575420b76 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6386,6 +6386,7 @@ dependencies = [ "bitflags 2.3.3", "blake3", "borsh 0.10.3", + "borsh 0.9.3", "bs58", "bv", "bytemuck", diff --git a/cost-model/src/cost_model.rs b/cost-model/src/cost_model.rs index 5a817670b..e321719e9 100644 --- a/cost-model/src/cost_model.rs +++ b/cost-model/src/cost_model.rs @@ -12,7 +12,7 @@ use { ComputeBudget, DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT, MAX_COMPUTE_UNIT_LIMIT, }, solana_sdk::{ - borsh::try_from_slice_unchecked, + borsh0_10::try_from_slice_unchecked, compute_budget::{self, ComputeBudgetInstruction}, feature_set::{ add_set_tx_loaded_accounts_data_size_instruction, diff --git a/program-runtime/src/compute_budget.rs b/program-runtime/src/compute_budget.rs index 3664a3046..ff217f079 100644 --- a/program-runtime/src/compute_budget.rs +++ b/program-runtime/src/compute_budget.rs @@ -1,7 +1,7 @@ use { crate::prioritization_fee::{PrioritizationFeeDetails, PrioritizationFeeType}, solana_sdk::{ - borsh::try_from_slice_unchecked, + borsh0_10::try_from_slice_unchecked, compute_budget::{self, ComputeBudgetInstruction}, entrypoint::HEAP_LENGTH as MIN_HEAP_FRAME_BYTES, feature_set::{ diff --git a/programs/sbf/Cargo.lock b/programs/sbf/Cargo.lock index a9b12c405..170666613 100644 --- a/programs/sbf/Cargo.lock +++ b/programs/sbf/Cargo.lock @@ -5232,6 +5232,7 @@ dependencies = [ "bitflags 2.3.3", "blake3", "borsh 0.10.3", + "borsh 0.9.3", "bs58", "bv", "bytemuck", diff --git a/sdk/program/Cargo.toml b/sdk/program/Cargo.toml index 7ddb537df..4b86478e4 100644 --- a/sdk/program/Cargo.toml +++ b/sdk/program/Cargo.toml @@ -15,6 +15,7 @@ rust-version = "1.68.0" # solana platform-tools rust version bincode = { workspace = true } blake3 = { workspace = true, features = ["digest", "traits-preview"] } borsh = { workspace = true } +borsh0-9 = { package = "borsh", version = "0.9.3" } bs58 = { workspace = true } bv = { workspace = true, features = ["serde"] } bytemuck = { workspace = true, features = ["derive"] } diff --git a/sdk/program/src/borsh.rs b/sdk/program/src/borsh.rs index 608ef1e95..90ce42f66 100644 --- a/sdk/program/src/borsh.rs +++ b/sdk/program/src/borsh.rs @@ -1,69 +1,25 @@ -#![allow(clippy::integer_arithmetic)] //! Utilities for the [borsh] serialization format. //! +//! To avoid backwards-incompatibilities when the Solana SDK changes its dependency +//! on borsh, it's recommended to instead use the version-specific file directly, +//! ie. `borsh0_10`. +//! +//! This file remains for developers who use these borsh helpers, but it will +//! be removed in a future release +//! //! [borsh]: https://borsh.io/ -use { - borsh::{ - maybestd::io::{Error, Write}, - schema::{BorshSchema, Declaration, Definition, Fields}, - BorshDeserialize, BorshSerialize, - }, - std::collections::HashMap, -}; - -/// Get packed length for the given BorchSchema Declaration -fn get_declaration_packed_len( - declaration: &str, - definitions: &HashMap, -) -> usize { - match definitions.get(declaration) { - Some(Definition::Array { length, elements }) => { - *length as usize * get_declaration_packed_len(elements, definitions) - } - Some(Definition::Enum { variants }) => { - 1 + variants - .iter() - .map(|(_, declaration)| get_declaration_packed_len(declaration, definitions)) - .max() - .unwrap_or(0) - } - Some(Definition::Struct { fields }) => match fields { - Fields::NamedFields(named_fields) => named_fields - .iter() - .map(|(_, declaration)| get_declaration_packed_len(declaration, definitions)) - .sum(), - Fields::UnnamedFields(declarations) => declarations - .iter() - .map(|declaration| get_declaration_packed_len(declaration, definitions)) - .sum(), - Fields::Empty => 0, - }, - Some(Definition::Sequence { - elements: _elements, - }) => panic!("Missing support for Definition::Sequence"), - Some(Definition::Tuple { elements }) => elements - .iter() - .map(|element| get_declaration_packed_len(element, definitions)) - .sum(), - None => match declaration { - "bool" | "u8" | "i8" => 1, - "u16" | "i16" => 2, - "u32" | "i32" => 4, - "u64" | "i64" => 8, - "u128" | "i128" => 16, - "nil" => 0, - _ => panic!("Missing primitive type: {declaration}"), - }, - } -} +use borsh::{maybestd::io::Error, BorshDeserialize, BorshSchema, BorshSerialize}; /// Get the worst-case packed length for the given BorshSchema /// /// Note: due to the serializer currently used by Borsh, this function cannot /// be used on-chain in the Solana SBF execution environment. +#[deprecated( + since = "1.17.0", + note = "Please use `borsh0_10::get_packed_len` instead" +)] pub fn get_packed_len() -> usize { - let schema_container = S::schema_container(); - get_declaration_packed_len(&schema_container.declaration, &schema_container.definitions) + crate::borsh0_10::get_packed_len::() } /// Deserializes without checking that the entire slice has been consumed @@ -75,28 +31,12 @@ pub fn get_packed_len() -> usize { /// or equal to the expected size will properly deserialize. For example, if the /// user passes a buffer destined for a different type, the error won't get caught /// as easily. +#[deprecated( + since = "1.17.0", + note = "Please use `borsh0_10::try_from_slice_unchecked` instead" +)] pub fn try_from_slice_unchecked(data: &[u8]) -> Result { - let mut data_mut = data; - let result = T::deserialize(&mut data_mut)?; - Ok(result) -} - -/// Helper struct which to count how much data would be written during serialization -#[derive(Default)] -struct WriteCounter { - count: usize, -} - -impl Write for WriteCounter { - fn write(&mut self, data: &[u8]) -> Result { - let amount = data.len(); - self.count += amount; - Ok(amount) - } - - fn flush(&mut self) -> Result<(), Error> { - Ok(()) - } + crate::borsh0_10::try_from_slice_unchecked::(data) } /// Get the packed length for the serialized form of this object instance. @@ -105,199 +45,246 @@ impl Write for WriteCounter { /// sequence, such as a Vec or HashMap. Since it is impossible to know the packed /// length only from the type's schema, this can be used when an instance already /// exists, to figure out how much space to allocate in an account. +#[deprecated( + since = "1.17.0", + note = "Please use `borsh0_10::get_instance_packed_len` instead" +)] pub fn get_instance_packed_len(instance: &T) -> Result { - let mut counter = WriteCounter::default(); - instance.serialize(&mut counter)?; - Ok(counter.count) + crate::borsh0_10::get_instance_packed_len(instance) } -#[cfg(test)] -mod tests { - use { - super::*, - borsh::{maybestd::io::ErrorKind, BorshSchema, BorshSerialize}, - std::{collections::HashMap, mem::size_of}, - }; +macro_rules! impl_get_packed_len { + ($borsh:ident $(,#[$meta:meta])?) => { + /// Get the worst-case packed length for the given BorshSchema + /// + /// Note: due to the serializer currently used by Borsh, this function cannot + /// be used on-chain in the Solana SBF execution environment. + $(#[$meta])? + pub fn get_packed_len() -> usize { + let $borsh::schema::BorshSchemaContainer { declaration, definitions } = + &S::schema_container(); + get_declaration_packed_len(declaration, definitions) + } - #[derive(PartialEq, Eq, Clone, Debug, BorshSerialize, BorshDeserialize, BorshSchema)] - enum TestEnum { - NoValue, - Number(u32), - Struct { - #[allow(dead_code)] - number: u64, - #[allow(dead_code)] - array: [u8; 8], - }, - } - - // for test simplicity - impl Default for TestEnum { - fn default() -> Self { - Self::NoValue + /// Get packed length for the given BorshSchema Declaration + fn get_declaration_packed_len( + declaration: &str, + definitions: &std::collections::HashMap<$borsh::schema::Declaration, $borsh::schema::Definition>, + ) -> usize { + match definitions.get(declaration) { + Some($borsh::schema::Definition::Array { length, elements }) => { + *length as usize * get_declaration_packed_len(elements, definitions) + } + Some($borsh::schema::Definition::Enum { variants }) => { + 1 + variants + .iter() + .map(|(_, declaration)| get_declaration_packed_len(declaration, definitions)) + .max() + .unwrap_or(0) + } + Some($borsh::schema::Definition::Struct { fields }) => match fields { + $borsh::schema::Fields::NamedFields(named_fields) => named_fields + .iter() + .map(|(_, declaration)| get_declaration_packed_len(declaration, definitions)) + .sum(), + $borsh::schema::Fields::UnnamedFields(declarations) => declarations + .iter() + .map(|declaration| get_declaration_packed_len(declaration, definitions)) + .sum(), + $borsh::schema::Fields::Empty => 0, + }, + Some($borsh::schema::Definition::Sequence { + elements: _elements, + }) => panic!("Missing support for Definition::Sequence"), + Some($borsh::schema::Definition::Tuple { elements }) => elements + .iter() + .map(|element| get_declaration_packed_len(element, definitions)) + .sum(), + None => match declaration { + "bool" | "u8" | "i8" => 1, + "u16" | "i16" => 2, + "u32" | "i32" => 4, + "u64" | "i64" => 8, + "u128" | "i128" => 16, + "nil" => 0, + _ => panic!("Missing primitive type: {declaration}"), + }, + } } } +} +pub(crate) use impl_get_packed_len; - #[derive(Default, BorshSerialize, BorshDeserialize, BorshSchema)] - struct TestStruct { - pub array: [u64; 16], - pub number_u128: u128, - pub number_u32: u32, - pub tuple: (u8, u16), - pub enumeration: TestEnum, - pub r#bool: bool, - } - - #[derive(Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize, BorshSchema)] - struct Child { - pub data: [u8; 64], - } - - #[derive(Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize, BorshSchema)] - struct Parent { - pub data: Vec, - } - - #[test] - fn unchecked_deserialization() { - let data = vec![ - Child { data: [0u8; 64] }, - Child { data: [1u8; 64] }, - Child { data: [2u8; 64] }, - ]; - let parent = Parent { data }; - - // exact size, both work - let mut byte_vec = vec![0u8; 4 + get_packed_len::() * 3]; - let mut bytes = byte_vec.as_mut_slice(); - parent.serialize(&mut bytes).unwrap(); - let deserialized = Parent::try_from_slice(&byte_vec).unwrap(); - assert_eq!(deserialized, parent); - let deserialized = try_from_slice_unchecked::(&byte_vec).unwrap(); - assert_eq!(deserialized, parent); - - // too big, only unchecked works - let mut byte_vec = vec![0u8; 4 + get_packed_len::() * 10]; - let mut bytes = byte_vec.as_mut_slice(); - parent.serialize(&mut bytes).unwrap(); - let err = Parent::try_from_slice(&byte_vec).unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidData); - let deserialized = try_from_slice_unchecked::(&byte_vec).unwrap(); - assert_eq!(deserialized, parent); - } - - #[test] - fn packed_len() { - assert_eq!( - get_packed_len::(), - size_of::() + size_of::() + u8::BITS as usize - ); - assert_eq!( - get_packed_len::(), - size_of::() * 16 - + size_of::() - + size_of::() - + size_of::() - + size_of::() - + size_of::() - + get_packed_len::() - ); - } - - #[test] - fn instance_packed_len_matches_packed_len() { - let enumeration = TestEnum::Struct { - number: u64::MAX, - array: [255; 8], - }; - assert_eq!( - get_packed_len::(), - get_instance_packed_len(&enumeration).unwrap(), - ); - let test_struct = TestStruct { - enumeration, - ..TestStruct::default() - }; - assert_eq!( - get_packed_len::(), - get_instance_packed_len(&test_struct).unwrap(), - ); - assert_eq!( - get_packed_len::(), - get_instance_packed_len(&0u8).unwrap(), - ); - assert_eq!( - get_packed_len::(), - get_instance_packed_len(&0u16).unwrap(), - ); - assert_eq!( - get_packed_len::(), - get_instance_packed_len(&0u32).unwrap(), - ); - assert_eq!( - get_packed_len::(), - get_instance_packed_len(&0u64).unwrap(), - ); - assert_eq!( - get_packed_len::(), - get_instance_packed_len(&0u128).unwrap(), - ); - assert_eq!( - get_packed_len::<[u8; 10]>(), - get_instance_packed_len(&[0u8; 10]).unwrap(), - ); - assert_eq!( - get_packed_len::<(i8, i16, i32, i64, i128)>(), - get_instance_packed_len(&(i8::MAX, i16::MAX, i32::MAX, i64::MAX, i128::MAX)).unwrap(), - ); - } - - #[test] - fn instance_packed_len_with_vec() { - let data = vec![ - Child { data: [0u8; 64] }, - Child { data: [1u8; 64] }, - Child { data: [2u8; 64] }, - Child { data: [3u8; 64] }, - Child { data: [4u8; 64] }, - Child { data: [5u8; 64] }, - ]; - let parent = Parent { data }; - assert_eq!( - get_instance_packed_len(&parent).unwrap(), - 4 + parent.data.len() * get_packed_len::() - ); - } - - #[derive(Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize, BorshSchema)] - struct StructWithHashMap { - data: HashMap, - } - - #[test] - fn instance_packed_len_with_varying_sizes_in_hashmap() { - let mut data = HashMap::new(); - let string1 = "the first string, it's actually really really long".to_string(); - let enum1 = TestEnum::NoValue; - let string2 = "second string, shorter".to_string(); - let enum2 = TestEnum::Number(u32::MAX); - let string3 = "third".to_string(); - let enum3 = TestEnum::Struct { - number: 0, - array: [0; 8], - }; - data.insert(string1.clone(), enum1.clone()); - data.insert(string2.clone(), enum2.clone()); - data.insert(string3.clone(), enum3.clone()); - let instance = StructWithHashMap { data }; - assert_eq!( - get_instance_packed_len(&instance).unwrap(), - 4 + get_instance_packed_len(&string1).unwrap() - + get_instance_packed_len(&enum1).unwrap() - + get_instance_packed_len(&string2).unwrap() - + get_instance_packed_len(&enum2).unwrap() - + get_instance_packed_len(&string3).unwrap() - + get_instance_packed_len(&enum3).unwrap() - ); +macro_rules! impl_try_from_slice_unchecked { + ($borsh:ident $(,#[$meta:meta])?) => { + /// Deserializes without checking that the entire slice has been consumed + /// + /// Normally, `try_from_slice` checks the length of the final slice to ensure + /// that the deserialization uses up all of the bytes in the slice. + /// + /// Note that there is a potential issue with this function. Any buffer greater than + /// or equal to the expected size will properly deserialize. For example, if the + /// user passes a buffer destined for a different type, the error won't get caught + /// as easily. + $(#[$meta])? + pub fn try_from_slice_unchecked(data: &[u8]) -> Result { + let mut data_mut = data; + let result = T::deserialize(&mut data_mut)?; + Ok(result) + } } } +pub(crate) use impl_try_from_slice_unchecked; + +macro_rules! impl_get_instance_packed_len { + ($borsh:ident $(,#[$meta:meta])?) => { + /// Helper struct which to count how much data would be written during serialization + #[derive(Default)] + struct WriteCounter { + count: usize, + } + + impl $borsh::maybestd::io::Write for WriteCounter { + fn write(&mut self, data: &[u8]) -> Result { + let amount = data.len(); + self.count += amount; + Ok(amount) + } + + fn flush(&mut self) -> Result<(), $borsh::maybestd::io::Error> { + Ok(()) + } + } + + /// Get the packed length for the serialized form of this object instance. + /// + /// Useful when working with instances of types that contain a variable-length + /// sequence, such as a Vec or HashMap. Since it is impossible to know the packed + /// length only from the type's schema, this can be used when an instance already + /// exists, to figure out how much space to allocate in an account. + $(#[$meta])? + pub fn get_instance_packed_len(instance: &T) -> Result { + let mut counter = WriteCounter::default(); + instance.serialize(&mut counter)?; + Ok(counter.count) + } + } +} +pub(crate) use impl_get_instance_packed_len; + +#[cfg(test)] +macro_rules! impl_tests { + ($borsh:ident) => { + use { + super::*, + std::{collections::HashMap, mem::size_of}, + $borsh::{maybestd::io::ErrorKind, BorshDeserialize, BorshSerialize}, + }; + + type Child = [u8; 64]; + type Parent = Vec; + + #[test] + fn unchecked_deserialization() { + let parent = vec![[0u8; 64], [1u8; 64], [2u8; 64]]; + + // exact size, both work + let mut byte_vec = vec![0u8; 4 + get_packed_len::() * 3]; + let mut bytes = byte_vec.as_mut_slice(); + parent.serialize(&mut bytes).unwrap(); + let deserialized = Parent::try_from_slice(&byte_vec).unwrap(); + assert_eq!(deserialized, parent); + let deserialized = try_from_slice_unchecked::(&byte_vec).unwrap(); + assert_eq!(deserialized, parent); + + // too big, only unchecked works + let mut byte_vec = vec![0u8; 4 + get_packed_len::() * 10]; + let mut bytes = byte_vec.as_mut_slice(); + parent.serialize(&mut bytes).unwrap(); + let err = Parent::try_from_slice(&byte_vec).unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidData); + let deserialized = try_from_slice_unchecked::(&byte_vec).unwrap(); + assert_eq!(deserialized, parent); + } + + #[test] + fn packed_len() { + assert_eq!(get_packed_len::(), size_of::()); + assert_eq!(get_packed_len::(), size_of::() * 64); + } + + #[test] + fn instance_packed_len_matches_packed_len() { + let child = [0u8; 64]; + assert_eq!( + get_packed_len::(), + get_instance_packed_len(&child).unwrap(), + ); + assert_eq!( + get_packed_len::(), + get_instance_packed_len(&0u8).unwrap(), + ); + assert_eq!( + get_packed_len::(), + get_instance_packed_len(&0u16).unwrap(), + ); + assert_eq!( + get_packed_len::(), + get_instance_packed_len(&0u32).unwrap(), + ); + assert_eq!( + get_packed_len::(), + get_instance_packed_len(&0u64).unwrap(), + ); + assert_eq!( + get_packed_len::(), + get_instance_packed_len(&0u128).unwrap(), + ); + assert_eq!( + get_packed_len::<[u8; 10]>(), + get_instance_packed_len(&[0u8; 10]).unwrap(), + ); + assert_eq!( + get_packed_len::<(i8, i16, i32, i64, i128)>(), + get_instance_packed_len(&(i8::MAX, i16::MAX, i32::MAX, i64::MAX, i128::MAX)) + .unwrap(), + ); + } + + #[test] + fn instance_packed_len_with_vec() { + let parent = vec![ + [0u8; 64], [1u8; 64], [2u8; 64], [3u8; 64], [4u8; 64], [5u8; 64], + ]; + assert_eq!( + get_instance_packed_len(&parent).unwrap(), + 4 + parent.len() * get_packed_len::() + ); + } + + #[test] + fn instance_packed_len_with_varying_sizes_in_hashmap() { + let mut data = HashMap::new(); + let key1 = "the first string, it's actually really really long".to_string(); + let value1 = "".to_string(); + let key2 = "second string, shorter".to_string(); + let value2 = "a real value".to_string(); + let key3 = "third".to_string(); + let value3 = "an even longer value".to_string(); + data.insert(key1.clone(), value1.clone()); + data.insert(key2.clone(), value2.clone()); + data.insert(key3.clone(), value3.clone()); + assert_eq!( + get_instance_packed_len(&data).unwrap(), + 4 + get_instance_packed_len(&key1).unwrap() + + get_instance_packed_len(&value1).unwrap() + + get_instance_packed_len(&key2).unwrap() + + get_instance_packed_len(&value2).unwrap() + + get_instance_packed_len(&key3).unwrap() + + get_instance_packed_len(&value3).unwrap() + ); + } + }; +} +#[cfg(test)] +pub(crate) use impl_tests; diff --git a/sdk/program/src/borsh0_10.rs b/sdk/program/src/borsh0_10.rs new file mode 100644 index 000000000..d4830fa2b --- /dev/null +++ b/sdk/program/src/borsh0_10.rs @@ -0,0 +1,17 @@ +#![allow(clippy::integer_arithmetic)] +//! Utilities for the [borsh] serialization format, version 0.10. +//! +//! [borsh]: https://borsh.io/ +use crate::borsh::{ + impl_get_instance_packed_len, impl_get_packed_len, impl_try_from_slice_unchecked, +}; + +impl_get_packed_len!(borsh); +impl_try_from_slice_unchecked!(borsh); +impl_get_instance_packed_len!(borsh); + +#[cfg(test)] +mod tests { + use crate::borsh::impl_tests; + impl_tests!(borsh); +} diff --git a/sdk/program/src/borsh0_9.rs b/sdk/program/src/borsh0_9.rs new file mode 100644 index 000000000..83f62bc00 --- /dev/null +++ b/sdk/program/src/borsh0_9.rs @@ -0,0 +1,39 @@ +#![allow(clippy::integer_arithmetic)] +//! Utilities for the [borsh] serialization format, version 0.9. +//! +//! This file is provided for backwards compatibility with types that still use +//! borsh 0.9, even though this crate canonically uses borsh 0.10. +//! +//! [borsh]: https://borsh.io/ +use crate::borsh::{ + impl_get_instance_packed_len, impl_get_packed_len, impl_try_from_slice_unchecked, +}; + +impl_get_packed_len!( + borsh0_9, + #[deprecated( + since = "1.17.0", + note = "Please upgrade to Borsh 0.10 and use `borsh0_10::get_packed_len` instead" + )] +); +impl_try_from_slice_unchecked!( + borsh0_9, + #[deprecated( + since = "1.17.0", + note = "Please upgrade to Borsh 0.10 and use `borsh0_10::try_from_slice_unchecked` instead" + )] +); +impl_get_instance_packed_len!( + borsh0_9, + #[deprecated( + since = "1.17.0", + note = "Please upgrade to Borsh 0.10 and use `borsh0_10::get_instance_packed_len` instead" + )] +); + +#[cfg(test)] +#[allow(deprecated)] +mod tests { + use crate::borsh::impl_tests; + impl_tests!(borsh0_9); +} diff --git a/sdk/program/src/lib.rs b/sdk/program/src/lib.rs index 2d0a679e4..b1d331331 100644 --- a/sdk/program/src/lib.rs +++ b/sdk/program/src/lib.rs @@ -477,6 +477,8 @@ pub(crate) mod atomic_u64; pub mod big_mod_exp; pub mod blake3; pub mod borsh; +pub mod borsh0_10; +pub mod borsh0_9; pub mod bpf_loader; pub mod bpf_loader_deprecated; pub mod bpf_loader_upgradeable; diff --git a/sdk/program/src/pubkey.rs b/sdk/program/src/pubkey.rs index da9b65bb5..f98b44fc2 100644 --- a/sdk/program/src/pubkey.rs +++ b/sdk/program/src/pubkey.rs @@ -668,6 +668,48 @@ impl fmt::Display for Pubkey { } } +impl borsh0_9::de::BorshDeserialize for Pubkey { + fn deserialize(buf: &mut &[u8]) -> ::core::result::Result { + Ok(Self(borsh0_9::BorshDeserialize::deserialize(buf)?)) + } +} +impl borsh0_9::BorshSchema for Pubkey +where + [u8; 32]: borsh0_9::BorshSchema, +{ + fn declaration() -> borsh0_9::schema::Declaration { + "Pubkey".to_string() + } + fn add_definitions_recursively( + definitions: &mut borsh0_9::maybestd::collections::HashMap< + borsh0_9::schema::Declaration, + borsh0_9::schema::Definition, + >, + ) { + let fields = borsh0_9::schema::Fields::UnnamedFields(<[_]>::into_vec( + borsh0_9::maybestd::boxed::Box::new([ + <[u8; 32] as borsh0_9::BorshSchema>::declaration(), + ]), + )); + let definition = borsh0_9::schema::Definition::Struct { fields }; + ::add_definition( + ::declaration(), + definition, + definitions, + ); + <[u8; 32] as borsh0_9::BorshSchema>::add_definitions_recursively(definitions); + } +} +impl borsh0_9::ser::BorshSerialize for Pubkey { + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh0_9::maybestd::io::Error> { + borsh0_9::BorshSerialize::serialize(&self.0, writer)?; + Ok(()) + } +} + #[cfg(test)] mod tests { use {super::*, std::str::from_utf8}; diff --git a/sdk/program/src/stake/state.rs b/sdk/program/src/stake/state.rs index 3dbd34efa..d763651e1 100644 --- a/sdk/program/src/stake/state.rs +++ b/sdk/program/src/stake/state.rs @@ -580,7 +580,7 @@ impl Stake { #[cfg(test)] mod test { use { - super::*, crate::borsh::try_from_slice_unchecked, assert_matches::assert_matches, + super::*, crate::borsh0_10::try_from_slice_unchecked, assert_matches::assert_matches, bincode::serialize, }; diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index 97bd36bc7..d0e5e8ec0 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -43,16 +43,16 @@ pub use signer::signers; #[cfg(not(target_os = "solana"))] pub use solana_program::program_stubs; pub use solana_program::{ - account_info, address_lookup_table_account, alt_bn128, big_mod_exp, blake3, borsh, bpf_loader, - bpf_loader_deprecated, bpf_loader_upgradeable, clock, config, custom_heap_default, - custom_panic_default, debug_account_data, declare_deprecated_sysvar_id, declare_sysvar_id, - decode_error, ed25519_program, epoch_rewards, epoch_schedule, fee_calculator, impl_sysvar_get, - incinerator, instruction, keccak, lamports, loader_instruction, loader_upgradeable_instruction, - loader_v4, loader_v4_instruction, message, msg, native_token, nonce, program, program_error, - program_memory, program_option, program_pack, rent, sanitize, sdk_ids, secp256k1_program, - secp256k1_recover, serde_varint, serialize_utils, short_vec, slot_hashes, slot_history, - stable_layout, stake, stake_history, syscalls, system_instruction, system_program, sysvar, - unchecked_div_by_const, vote, wasm_bindgen, + account_info, address_lookup_table_account, alt_bn128, big_mod_exp, blake3, borsh, borsh0_10, + borsh0_9, bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, clock, config, + custom_heap_default, custom_panic_default, debug_account_data, declare_deprecated_sysvar_id, + declare_sysvar_id, decode_error, ed25519_program, epoch_rewards, epoch_schedule, + fee_calculator, impl_sysvar_get, incinerator, instruction, keccak, lamports, + loader_instruction, loader_upgradeable_instruction, loader_v4, loader_v4_instruction, message, + msg, native_token, nonce, program, program_error, program_memory, program_option, program_pack, + rent, sanitize, sdk_ids, secp256k1_program, secp256k1_recover, serde_varint, serialize_utils, + short_vec, slot_hashes, slot_history, stable_layout, stake, stake_history, syscalls, + system_instruction, system_program, sysvar, unchecked_div_by_const, vote, wasm_bindgen, }; pub mod account;