From cfb16ab76af712e1f7bb2c966a16d57eef96cfc1 Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Fri, 8 Dec 2023 13:18:10 +0100 Subject: [PATCH] sdk: Upgrade to borsh 1.2.1 (#34355) * sdk: Update to borsh 1, revert borsh 0.9 / 0.10 * Restore borsh 0.10 and 0.9 support * Update sbf lockfile * Add borsh 0.10 implementations for stake types * Fix weirdness on whitespace * Update to borsh 1.2.1 * Update changelog * compute-budget: Move `pack` under dev-context-only-utils * Revert test to use HashMap * transaction-status: Add comment about borsh version --- CHANGELOG.md | 3 + Cargo.lock | 79 ++- Cargo.toml | 2 +- cost-model/Cargo.toml | 1 + cost-model/src/cost_model.rs | 2 +- .../src/compute_budget_processor.rs | 2 +- programs/sbf/Cargo.lock | 85 +++- sdk/program/Cargo.toml | 1 + sdk/program/src/blake3.rs | 1 + sdk/program/src/borsh.rs | 91 +++- sdk/program/src/borsh0_10.rs | 38 +- sdk/program/src/borsh0_9.rs | 21 +- sdk/program/src/borsh1.rs | 20 + sdk/program/src/hash.rs | 1 + sdk/program/src/instruction.rs | 11 +- sdk/program/src/keccak.rs | 1 + sdk/program/src/lib.rs | 1 + sdk/program/src/message/legacy.rs | 3 + sdk/program/src/program_error.rs | 2 +- sdk/program/src/pubkey.rs | 94 ++-- sdk/program/src/secp256k1_recover.rs | 3 + sdk/program/src/stake/stake_flags.rs | 44 ++ sdk/program/src/stake/state.rs | 476 +++++++++++++++--- sdk/program/src/system_instruction.rs | 5 + sdk/src/compute_budget.rs | 6 +- sdk/src/lib.rs | 19 +- transaction-status/Cargo.toml | 4 +- 27 files changed, 840 insertions(+), 176 deletions(-) create mode 100644 sdk/program/src/borsh1.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e768ab83..2e8517a4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,10 @@ Release channels have their own copy of this changelog: * The default for `--use-snapshot-archives-at-startup` is now `when-newest` (#33883) * The default for `solana-ledger-tool`, however, remains `always` (#34228) * Added `central-scheduler` option for `--block-production-method` (#33890) + * Updated to Borsh v1 * Upgrade Notes + * `solana-program` and `solana-sdk` default to support for Borsh v1, with +limited backward compatibility for v0.10 and v0.9. Please upgrade to Borsh v1. ## [1.17.0] * Changes diff --git a/Cargo.lock b/Cargo.lock index dd74ea326..496820cb2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -726,6 +726,16 @@ dependencies = [ "hashbrown 0.13.2", ] +[[package]] +name = "borsh" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9897ef0f1bd2362169de6d7e436ea2237dc1085d7d1e4db75f4be34d86f309d1" +dependencies = [ + "borsh-derive 1.2.1", + "cfg_aliases", +] + [[package]] name = "borsh-derive" version = "0.9.3" @@ -752,6 +762,20 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "borsh-derive" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478b41ff04256c5c8330f3dfdaaae2a5cc976a8e75088bafa4625b0d0208de8c" +dependencies = [ + "once_cell", + "proc-macro-crate 2.0.0", + "proc-macro2", + "quote", + "syn 2.0.39", + "syn_derive", +] + [[package]] name = "borsh-derive-internal" version = "0.9.3" @@ -1029,6 +1053,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + [[package]] name = "chrono" version = "0.4.31" @@ -1530,7 +1560,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if 1.0.0", - "hashbrown 0.14.1", + "hashbrown 0.14.3", "lock_api", "once_cell", "parking_lot_core 0.9.8", @@ -2341,9 +2371,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.1" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" [[package]] name = "headers" @@ -2670,7 +2700,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown 0.14.1", + "hashbrown 0.14.3", "rayon", ] @@ -3488,7 +3518,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c11e44798ad209ccdd91fc192f0526a369a01234f7373e1b141c96d7cee4f0e" dependencies = [ - "proc-macro-crate 1.1.0", + "proc-macro-crate 2.0.0", "proc-macro2", "quote", "syn 2.0.39", @@ -4026,6 +4056,15 @@ dependencies = [ "toml 0.5.8", ] +[[package]] +name = "proc-macro-crate" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" +dependencies = [ + "toml_edit 0.20.7", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -5395,7 +5434,7 @@ dependencies = [ name = "solana-banks-client" version = "1.18.0" dependencies = [ - "borsh 0.10.3", + "borsh 1.2.1", "futures 0.3.29", "solana-banks-interface", "solana-banks-server", @@ -6652,6 +6691,7 @@ dependencies = [ "blake3", "borsh 0.10.3", "borsh 0.9.3", + "borsh 1.2.1", "bs58", "bv", "bytemuck", @@ -7089,7 +7129,7 @@ dependencies = [ "base64 0.21.5", "bincode", "bitflags 2.4.1", - "borsh 0.10.3", + "borsh 1.2.1", "bs58", "bytemuck", "byteorder", @@ -8073,6 +8113,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "sync_wrapper" version = "0.1.1" @@ -8542,7 +8594,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit", + "toml_edit 0.21.0", ] [[package]] @@ -8554,6 +8606,17 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_edit" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" +dependencies = [ + "indexmap 2.1.0", + "toml_datetime", + "winnow", +] + [[package]] name = "toml_edit" version = "0.21.0" diff --git a/Cargo.toml b/Cargo.toml index 122258fd8..631173aa5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -155,7 +155,7 @@ bincode = "1.3.3" bitflags = { version = "2.3.3", features = ["serde"] } blake3 = "1.5.0" block-buffer = "0.10.4" -borsh = "0.10.3" +borsh = { version = "1.2.1", features = ["derive", "unstable__schema"] } bs58 = "0.4.0" bv = "0.11.1" byte-unit = "4.0.19" diff --git a/cost-model/Cargo.toml b/cost-model/Cargo.toml index 6142f9be8..4a8b159bb 100644 --- a/cost-model/Cargo.toml +++ b/cost-model/Cargo.toml @@ -32,6 +32,7 @@ name = "solana_cost_model" [dev-dependencies] solana-logger = { workspace = true } +solana-sdk = { workspace = true, features = ["dev-context-only-utils"] } static_assertions = { workspace = true } test-case = { workspace = true } diff --git a/cost-model/src/cost_model.rs b/cost-model/src/cost_model.rs index bb3e296d6..1232e5c3c 100644 --- a/cost-model/src/cost_model.rs +++ b/cost-model/src/cost_model.rs @@ -16,7 +16,7 @@ use { }, }, solana_sdk::{ - borsh0_10::try_from_slice_unchecked, + borsh1::try_from_slice_unchecked, compute_budget::{self, ComputeBudgetInstruction}, feature_set::{include_loaded_accounts_data_size_in_fee_calculation, FeatureSet}, fee::FeeStructure, diff --git a/program-runtime/src/compute_budget_processor.rs b/program-runtime/src/compute_budget_processor.rs index b2c3a8924..3b705d334 100644 --- a/program-runtime/src/compute_budget_processor.rs +++ b/program-runtime/src/compute_budget_processor.rs @@ -5,7 +5,7 @@ use { prioritization_fee::{PrioritizationFeeDetails, PrioritizationFeeType}, }, solana_sdk::{ - borsh0_10::try_from_slice_unchecked, + borsh1::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 d429df77b..99eb6d6cb 100644 --- a/programs/sbf/Cargo.lock +++ b/programs/sbf/Cargo.lock @@ -686,6 +686,16 @@ dependencies = [ "hashbrown 0.13.2", ] +[[package]] +name = "borsh" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9897ef0f1bd2362169de6d7e436ea2237dc1085d7d1e4db75f4be34d86f309d1" +dependencies = [ + "borsh-derive 1.2.1", + "cfg_aliases", +] + [[package]] name = "borsh-derive" version = "0.9.3" @@ -712,6 +722,20 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "borsh-derive" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478b41ff04256c5c8330f3dfdaaae2a5cc976a8e75088bafa4625b0d0208de8c" +dependencies = [ + "once_cell", + "proc-macro-crate 2.0.1", + "proc-macro2", + "quote", + "syn 2.0.39", + "syn_derive", +] + [[package]] name = "borsh-derive-internal" version = "0.9.3" @@ -914,6 +938,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + [[package]] name = "chrono" version = "0.4.31" @@ -3119,7 +3149,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c11e44798ad209ccdd91fc192f0526a369a01234f7373e1b141c96d7cee4f0e" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate 2.0.1", "proc-macro2", "quote", "syn 2.0.39", @@ -3616,6 +3646,16 @@ dependencies = [ "toml", ] +[[package]] +name = "proc-macro-crate" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97dc5fea232fc28d2f597b37c4876b348a40e33f3b02cc975c8d006d78d94b1a" +dependencies = [ + "toml_datetime", + "toml_edit", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -4718,7 +4758,7 @@ dependencies = [ name = "solana-banks-client" version = "1.18.0" dependencies = [ - "borsh 0.10.3", + "borsh 1.2.1", "futures 0.3.29", "solana-banks-interface", "solana-program", @@ -5415,6 +5455,7 @@ dependencies = [ "blake3", "borsh 0.10.3", "borsh 0.9.3", + "borsh 1.2.1", "bs58", "bv", "bytemuck", @@ -6197,7 +6238,7 @@ dependencies = [ "base64 0.21.5", "bincode", "bitflags 2.4.1", - "borsh 0.10.3", + "borsh 1.2.1", "bs58", "bytemuck", "byteorder 1.5.0", @@ -6993,6 +7034,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "sync_wrapper" version = "0.1.1" @@ -7423,6 +7476,23 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" + +[[package]] +name = "toml_edit" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +dependencies = [ + "indexmap 2.1.0", + "toml_datetime", + "winnow", +] + [[package]] name = "tonic" version = "0.9.2" @@ -8058,6 +8128,15 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +[[package]] +name = "winnow" +version = "0.5.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e87b8dfbe3baffbe687eef2e164e32286eff31a5ee16463ce03d991643ec94" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.50.0" diff --git a/sdk/program/Cargo.toml b/sdk/program/Cargo.toml index f608ed619..ccd18701e 100644 --- a/sdk/program/Cargo.toml +++ b/sdk/program/Cargo.toml @@ -15,6 +15,7 @@ rust-version = "1.72.0" # solana platform-tools rust version bincode = { workspace = true } blake3 = { workspace = true, features = ["digest", "traits-preview"] } borsh = { workspace = true } +borsh0-10 = { package = "borsh", version = "0.10.3" } borsh0-9 = { package = "borsh", version = "0.9.3" } bs58 = { workspace = true } bv = { workspace = true, features = ["serde"] } diff --git a/sdk/program/src/blake3.rs b/sdk/program/src/blake3.rs index d8351b06c..cc50318e3 100644 --- a/sdk/program/src/blake3.rs +++ b/sdk/program/src/blake3.rs @@ -31,6 +31,7 @@ const MAX_BASE58_LEN: usize = 44; Hash, AbiExample, )] +#[borsh(crate = "borsh")] #[repr(transparent)] pub struct Hash(pub [u8; HASH_BYTES]); diff --git a/sdk/program/src/borsh.rs b/sdk/program/src/borsh.rs index 90ce42f66..0041aa806 100644 --- a/sdk/program/src/borsh.rs +++ b/sdk/program/src/borsh.rs @@ -8,7 +8,7 @@ //! be removed in a future release //! //! [borsh]: https://borsh.io/ -use borsh::{maybestd::io::Error, BorshDeserialize, BorshSchema, BorshSerialize}; +use borsh0_10::{maybestd::io::Error, BorshDeserialize, BorshSchema, BorshSerialize}; /// Get the worst-case packed length for the given BorshSchema /// @@ -19,6 +19,7 @@ use borsh::{maybestd::io::Error, BorshDeserialize, BorshSchema, BorshSerialize}; note = "Please use `borsh0_10::get_packed_len` instead" )] pub fn get_packed_len() -> usize { + #[allow(deprecated)] crate::borsh0_10::get_packed_len::() } @@ -36,6 +37,7 @@ pub fn get_packed_len() -> usize { note = "Please use `borsh0_10::try_from_slice_unchecked` instead" )] pub fn try_from_slice_unchecked(data: &[u8]) -> Result { + #[allow(deprecated)] crate::borsh0_10::try_from_slice_unchecked::(data) } @@ -50,10 +52,11 @@ pub fn try_from_slice_unchecked(data: &[u8]) -> Result(instance: &T) -> Result { + #[allow(deprecated)] crate::borsh0_10::get_instance_packed_len(instance) } -macro_rules! impl_get_packed_len { +macro_rules! impl_get_packed_len_v0 { ($borsh:ident $(,#[$meta:meta])?) => { /// Get the worst-case packed length for the given BorshSchema /// @@ -113,10 +116,72 @@ macro_rules! impl_get_packed_len { } } } -pub(crate) use impl_get_packed_len; +pub(crate) use impl_get_packed_len_v0; + +macro_rules! impl_get_packed_len_v1 { + ($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 container = $borsh::schema_container_of::(); + get_declaration_packed_len(container.declaration(), &container) + } + + /// Get packed length for the given BorshSchema Declaration + fn get_declaration_packed_len( + declaration: &str, + container: &$borsh::schema::BorshSchemaContainer, + ) -> usize { + match container.get_definition(declaration) { + Some($borsh::schema::Definition::Sequence { length_width, length_range, elements }) if *length_width == 0 => { + *length_range.end() as usize * get_declaration_packed_len(elements, container) + } + Some($borsh::schema::Definition::Enum { tag_width, variants }) => { + (*tag_width as usize) + variants + .iter() + .map(|(_, _, declaration)| get_declaration_packed_len(declaration, container)) + .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, container)) + .sum(), + $borsh::schema::Fields::UnnamedFields(declarations) => declarations + .iter() + .map(|declaration| get_declaration_packed_len(declaration, container)) + .sum(), + $borsh::schema::Fields::Empty => 0, + }, + Some($borsh::schema::Definition::Sequence { + .. + }) => panic!("Missing support for Definition::Sequence"), + Some($borsh::schema::Definition::Tuple { elements }) => elements + .iter() + .map(|element| get_declaration_packed_len(element, container)) + .sum(), + Some($borsh::schema::Definition::Primitive(size)) => *size as usize, + 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_v1; macro_rules! impl_try_from_slice_unchecked { - ($borsh:ident $(,#[$meta:meta])?) => { + ($borsh:ident, $borsh_io: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 @@ -127,7 +192,7 @@ macro_rules! impl_try_from_slice_unchecked { /// 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 { + pub fn try_from_slice_unchecked(data: &[u8]) -> Result { let mut data_mut = data; let result = T::deserialize(&mut data_mut)?; Ok(result) @@ -137,21 +202,21 @@ macro_rules! impl_try_from_slice_unchecked { pub(crate) use impl_try_from_slice_unchecked; macro_rules! impl_get_instance_packed_len { - ($borsh:ident $(,#[$meta:meta])?) => { + ($borsh:ident, $borsh_io: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 { + impl $borsh_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> { + fn flush(&mut self) -> Result<(), $borsh_io::Error> { Ok(()) } } @@ -163,7 +228,7 @@ macro_rules! impl_get_instance_packed_len { /// 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 { + pub fn get_instance_packed_len(instance: &T) -> Result { let mut counter = WriteCounter::default(); instance.serialize(&mut counter)?; Ok(counter.count) @@ -174,11 +239,13 @@ pub(crate) use impl_get_instance_packed_len; #[cfg(test)] macro_rules! impl_tests { - ($borsh:ident) => { + ($borsh:ident, $borsh_io:ident) => { + extern crate alloc; use { super::*, std::{collections::HashMap, mem::size_of}, - $borsh::{maybestd::io::ErrorKind, BorshDeserialize, BorshSerialize}, + $borsh::{BorshDeserialize, BorshSerialize}, + $borsh_io::ErrorKind, }; type Child = [u8; 64]; diff --git a/sdk/program/src/borsh0_10.rs b/sdk/program/src/borsh0_10.rs index f29640885..c7d190f82 100644 --- a/sdk/program/src/borsh0_10.rs +++ b/sdk/program/src/borsh0_10.rs @@ -2,16 +2,40 @@ //! 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, +use { + crate::borsh::{ + impl_get_instance_packed_len, impl_get_packed_len_v0, impl_try_from_slice_unchecked, + }, + borsh0_10::maybestd::io, }; -impl_get_packed_len!(borsh); -impl_try_from_slice_unchecked!(borsh); -impl_get_instance_packed_len!(borsh); +impl_get_packed_len_v0!( + borsh0_10, + #[deprecated( + since = "1.18.0", + note = "Please upgrade to Borsh 1.X and use `borsh1::get_packed_len` instead" + )] +); +impl_try_from_slice_unchecked!( + borsh0_10, + io, + #[deprecated( + since = "1.18.0", + note = "Please upgrade to Borsh 1.X and use `borsh1::try_from_slice_unchecked` instead" + )] +); +impl_get_instance_packed_len!( + borsh0_10, + io, + #[deprecated( + since = "1.18.0", + note = "Please upgrade to Borsh 1.X and use `borsh1::get_instance_packed_len` instead" + )] +); #[cfg(test)] +#[allow(deprecated)] mod tests { - use crate::borsh::impl_tests; - impl_tests!(borsh); + use {crate::borsh::impl_tests, borsh0_10::maybestd::io}; + impl_tests!(borsh0_10, io); } diff --git a/sdk/program/src/borsh0_9.rs b/sdk/program/src/borsh0_9.rs index dd9e401db..d7d1e9701 100644 --- a/sdk/program/src/borsh0_9.rs +++ b/sdk/program/src/borsh0_9.rs @@ -5,35 +5,40 @@ //! 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, +use { + crate::borsh::{ + impl_get_instance_packed_len, impl_get_packed_len_v0, impl_try_from_slice_unchecked, + }, + borsh0_9::maybestd::io, }; -impl_get_packed_len!( +impl_get_packed_len_v0!( borsh0_9, #[deprecated( since = "1.17.0", - note = "Please upgrade to Borsh 0.10 and use `borsh0_10::get_packed_len` instead" + note = "Please upgrade to Borsh 1.X and use `borsh1::get_packed_len` instead" )] ); impl_try_from_slice_unchecked!( borsh0_9, + io, #[deprecated( since = "1.17.0", - note = "Please upgrade to Borsh 0.10 and use `borsh0_10::try_from_slice_unchecked` instead" + note = "Please upgrade to Borsh 1.X and use `borsh1::try_from_slice_unchecked` instead" )] ); impl_get_instance_packed_len!( borsh0_9, + io, #[deprecated( since = "1.17.0", - note = "Please upgrade to Borsh 0.10 and use `borsh0_10::get_instance_packed_len` instead" + note = "Please upgrade to Borsh 1.X and use `borsh1::get_instance_packed_len` instead" )] ); #[cfg(test)] #[allow(deprecated)] mod tests { - use crate::borsh::impl_tests; - impl_tests!(borsh0_9); + use {crate::borsh::impl_tests, borsh0_9::maybestd::io}; + impl_tests!(borsh0_9, io); } diff --git a/sdk/program/src/borsh1.rs b/sdk/program/src/borsh1.rs new file mode 100644 index 000000000..a44ea5224 --- /dev/null +++ b/sdk/program/src/borsh1.rs @@ -0,0 +1,20 @@ +#![allow(clippy::arithmetic_side_effects)] +//! Utilities for the [borsh] serialization format, version 1. +//! +//! [borsh]: https://borsh.io/ +use { + crate::borsh::{ + impl_get_instance_packed_len, impl_get_packed_len_v1, impl_try_from_slice_unchecked, + }, + borsh::io, +}; + +impl_get_packed_len_v1!(borsh); +impl_try_from_slice_unchecked!(borsh, io); +impl_get_instance_packed_len!(borsh, io); + +#[cfg(test)] +mod tests { + use {crate::borsh::impl_tests, borsh::io}; + impl_tests!(borsh, io); +} diff --git a/sdk/program/src/hash.rs b/sdk/program/src/hash.rs index 27d481b62..288f696df 100644 --- a/sdk/program/src/hash.rs +++ b/sdk/program/src/hash.rs @@ -46,6 +46,7 @@ const MAX_BASE58_LEN: usize = 44; Pod, Zeroable, )] +#[borsh(crate = "borsh")] #[repr(transparent)] pub struct Hash(pub(crate) [u8; HASH_BYTES]); diff --git a/sdk/program/src/instruction.rs b/sdk/program/src/instruction.rs index e68fc198a..21b3e774a 100644 --- a/sdk/program/src/instruction.rs +++ b/sdk/program/src/instruction.rs @@ -364,6 +364,7 @@ impl Instruction { /// # use borsh::{BorshSerialize, BorshDeserialize}; /// # /// #[derive(BorshSerialize, BorshDeserialize)] + /// # #[borsh(crate = "borsh")] /// pub struct MyInstruction { /// pub lamports: u64, /// } @@ -391,7 +392,7 @@ impl Instruction { data: &T, accounts: Vec, ) -> Self { - let data = data.try_to_vec().unwrap(); + let data = borsh::to_vec(data).unwrap(); Self { program_id, accounts, @@ -466,10 +467,10 @@ impl Instruction { /// # pubkey::Pubkey, /// # instruction::{AccountMeta, Instruction}, /// # }; - /// # use borsh::{BorshSerialize, BorshDeserialize}; - /// # use anyhow::Result; + /// # use borsh::{io::Error, BorshSerialize, BorshDeserialize}; /// # /// #[derive(BorshSerialize, BorshDeserialize)] + /// # #[borsh(crate = "borsh")] /// pub struct MyInstruction { /// pub lamports: u64, /// } @@ -479,7 +480,7 @@ impl Instruction { /// from: &Pubkey, /// to: &Pubkey, /// lamports: u64, - /// ) -> Result { + /// ) -> Result { /// let instr = MyInstruction { lamports }; /// /// let mut instr_in_bytes: Vec = Vec::new(); @@ -558,6 +559,7 @@ impl AccountMeta { /// # use borsh::{BorshSerialize, BorshDeserialize}; /// # /// # #[derive(BorshSerialize, BorshDeserialize)] + /// # #[borsh(crate = "borsh")] /// # pub struct MyInstruction; /// # /// # let instruction = MyInstruction; @@ -593,6 +595,7 @@ impl AccountMeta { /// # use borsh::{BorshSerialize, BorshDeserialize}; /// # /// # #[derive(BorshSerialize, BorshDeserialize)] + /// # #[borsh(crate = "borsh")] /// # pub struct MyInstruction; /// # /// # let instruction = MyInstruction; diff --git a/sdk/program/src/keccak.rs b/sdk/program/src/keccak.rs index 17829485c..6a1cfaf11 100644 --- a/sdk/program/src/keccak.rs +++ b/sdk/program/src/keccak.rs @@ -29,6 +29,7 @@ const MAX_BASE58_LEN: usize = 44; Hash, AbiExample, )] +#[borsh(crate = "borsh")] #[repr(transparent)] pub struct Hash(pub [u8; HASH_BYTES]); diff --git a/sdk/program/src/lib.rs b/sdk/program/src/lib.rs index 0dfc8c324..504383374 100644 --- a/sdk/program/src/lib.rs +++ b/sdk/program/src/lib.rs @@ -479,6 +479,7 @@ pub mod blake3; pub mod borsh; pub mod borsh0_10; pub mod borsh0_9; +pub mod borsh1; pub mod bpf_loader; pub mod bpf_loader_deprecated; pub mod bpf_loader_upgradeable; diff --git a/sdk/program/src/message/legacy.rs b/sdk/program/src/message/legacy.rs index e81c7c485..868cb9bc9 100644 --- a/sdk/program/src/message/legacy.rs +++ b/sdk/program/src/message/legacy.rs @@ -193,6 +193,7 @@ impl Message { /// // another crate so it can be shared between the on-chain program and /// // the client. /// #[derive(BorshSerialize, BorshDeserialize)] + /// # #[borsh(crate = "borsh")] /// enum BankInstruction { /// Initialize, /// Deposit { lamports: u64 }, @@ -264,6 +265,7 @@ impl Message { /// // another crate so it can be shared between the on-chain program and /// // the client. /// #[derive(BorshSerialize, BorshDeserialize)] + /// # #[borsh(crate = "borsh")] /// enum BankInstruction { /// Initialize, /// Deposit { lamports: u64 }, @@ -363,6 +365,7 @@ impl Message { /// // another crate so it can be shared between the on-chain program and /// // the client. /// #[derive(BorshSerialize, BorshDeserialize)] + /// # #[borsh(crate = "borsh")] /// enum BankInstruction { /// Initialize, /// Deposit { lamports: u64 }, diff --git a/sdk/program/src/program_error.rs b/sdk/program/src/program_error.rs index 6eb7e9ecd..0840ee16b 100644 --- a/sdk/program/src/program_error.rs +++ b/sdk/program/src/program_error.rs @@ -3,7 +3,7 @@ #![allow(clippy::arithmetic_side_effects)] use { crate::{decode_error::DecodeError, instruction::InstructionError, msg, pubkey::PubkeyError}, - borsh::maybestd::io::Error as BorshIoError, + borsh::io::Error as BorshIoError, num_traits::{FromPrimitive, ToPrimitive}, std::convert::TryFrom, thiserror::Error, diff --git a/sdk/program/src/pubkey.rs b/sdk/program/src/pubkey.rs index ebbe52950..122c74dbe 100644 --- a/sdk/program/src/pubkey.rs +++ b/sdk/program/src/pubkey.rs @@ -84,6 +84,7 @@ impl From for PubkeyError { Serialize, Zeroable, )] +#[borsh(crate = "borsh")] pub struct Pubkey(pub(crate) [u8; 32]); impl crate::sanitize::Sanitize for Pubkey {} @@ -328,6 +329,7 @@ impl Pubkey { /// // The computed address of the PDA will be passed to this program via /// // the `accounts` vector of the `Instruction` type. /// #[derive(BorshSerialize, BorshDeserialize, Debug)] + /// # #[borsh(crate = "borsh")] /// pub struct InstructionData { /// pub vault_bump_seed: u8, /// pub lamports: u64, @@ -409,6 +411,7 @@ impl Pubkey { /// # use anyhow::Result; /// # /// # #[derive(BorshSerialize, BorshDeserialize, Debug)] + /// # #[borsh(crate = "borsh")] /// # struct InstructionData { /// # pub vault_bump_seed: u8, /// # pub lamports: u64, @@ -668,47 +671,70 @@ impl fmt::Display for Pubkey { } } +impl borsh0_10::de::BorshDeserialize for Pubkey { + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + Ok(Self(borsh0_10::BorshDeserialize::deserialize_reader( + reader, + )?)) + } +} 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); - } + +macro_rules! impl_borsh_schema { + ($borsh:ident) => { + impl $borsh::BorshSchema for Pubkey + where + [u8; 32]: $borsh::BorshSchema, + { + fn declaration() -> $borsh::schema::Declaration { + "Pubkey".to_string() + } + fn add_definitions_recursively( + definitions: &mut $borsh::maybestd::collections::HashMap< + $borsh::schema::Declaration, + $borsh::schema::Definition, + >, + ) { + let fields = $borsh::schema::Fields::UnnamedFields(<[_]>::into_vec( + $borsh::maybestd::boxed::Box::new([ + <[u8; 32] as $borsh::BorshSchema>::declaration(), + ]), + )); + let definition = $borsh::schema::Definition::Struct { fields }; + ::add_definition( + ::declaration(), + definition, + definitions, + ); + <[u8; 32] as $borsh::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(()) - } +impl_borsh_schema!(borsh0_10); +impl_borsh_schema!(borsh0_9); + +macro_rules! impl_borsh_serialize { + ($borsh:ident) => { + impl $borsh::ser::BorshSerialize for Pubkey { + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), $borsh::maybestd::io::Error> { + $borsh::BorshSerialize::serialize(&self.0, writer)?; + Ok(()) + } + } + }; } +impl_borsh_serialize!(borsh0_10); +impl_borsh_serialize!(borsh0_9); #[cfg(test)] mod tests { diff --git a/sdk/program/src/secp256k1_recover.rs b/sdk/program/src/secp256k1_recover.rs index 5bca285c2..8e2e3be05 100644 --- a/sdk/program/src/secp256k1_recover.rs +++ b/sdk/program/src/secp256k1_recover.rs @@ -78,6 +78,7 @@ pub const SECP256K1_PUBLIC_KEY_LENGTH: usize = 64; Hash, AbiExample, )] +#[borsh(crate = "borsh")] pub struct Secp256k1Pubkey(pub [u8; SECP256K1_PUBLIC_KEY_LENGTH]); impl Secp256k1Pubkey { @@ -254,6 +255,7 @@ impl Secp256k1Pubkey { /// use borsh::{BorshDeserialize, BorshSerialize}; /// /// #[derive(BorshSerialize, BorshDeserialize, Debug)] +/// # #[borsh(crate = "borsh")] /// pub struct DemoSecp256k1RecoverInstruction { /// pub message: Vec, /// pub signature: [u8; 64], @@ -348,6 +350,7 @@ impl Secp256k1Pubkey { /// }; /// # use borsh::{BorshDeserialize, BorshSerialize}; /// # #[derive(BorshSerialize, BorshDeserialize, Debug)] +/// # #[borsh(crate = "borsh")] /// # pub struct DemoSecp256k1RecoverInstruction { /// # pub message: Vec, /// # pub signature: [u8; 64], diff --git a/sdk/program/src/stake/stake_flags.rs b/sdk/program/src/stake/stake_flags.rs index 1d56c77fb..aa044ff92 100644 --- a/sdk/program/src/stake/stake_flags.rs +++ b/sdk/program/src/stake/stake_flags.rs @@ -17,9 +17,53 @@ use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; Hash, Debug, )] +#[borsh(crate = "borsh")] pub struct StakeFlags { bits: u8, } +impl borsh0_10::de::BorshDeserialize for StakeFlags { + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + Ok(Self { + bits: borsh0_10::BorshDeserialize::deserialize_reader(reader)?, + }) + } +} +impl borsh0_10::BorshSchema for StakeFlags { + fn declaration() -> borsh0_10::schema::Declaration { + "StakeFlags".to_string() + } + fn add_definitions_recursively( + definitions: &mut borsh0_10::maybestd::collections::HashMap< + borsh0_10::schema::Declaration, + borsh0_10::schema::Definition, + >, + ) { + let fields = borsh0_10::schema::Fields::NamedFields(<[_]>::into_vec( + borsh0_10::maybestd::boxed::Box::new([( + "bits".to_string(), + ::declaration(), + )]), + )); + let definition = borsh0_10::schema::Definition::Struct { fields }; + Self::add_definition( + ::declaration(), + definition, + definitions, + ); + ::add_definitions_recursively(definitions); + } +} +impl borsh0_10::ser::BorshSerialize for StakeFlags { + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh0_10::maybestd::io::Error> { + borsh0_10::BorshSerialize::serialize(&self.bits, writer)?; + Ok(()) + } +} /// Currently, only bit 1 is used. The other 7 bits are reserved for future usage. impl StakeFlags { diff --git a/sdk/program/src/stake/state.rs b/sdk/program/src/stake/state.rs index 4f94f73b3..11652446b 100644 --- a/sdk/program/src/stake/state.rs +++ b/sdk/program/src/stake/state.rs @@ -14,7 +14,7 @@ use { }, stake_history::{StakeHistory, StakeHistoryEntry}, }, - borsh::{maybestd::io, BorshDeserialize, BorshSchema, BorshSerialize}, + borsh::{io, BorshDeserialize, BorshSchema, BorshSerialize}, std::collections::HashSet, }; @@ -34,6 +34,49 @@ pub fn warmup_cooldown_rate(current_epoch: Epoch, new_rate_activation_epoch: Opt } } +macro_rules! impl_borsh_stake_state { + ($borsh:ident) => { + impl $borsh::BorshDeserialize for StakeState { + fn deserialize_reader(reader: &mut R) -> io::Result { + let enum_value: u32 = $borsh::BorshDeserialize::deserialize_reader(reader)?; + match enum_value { + 0 => Ok(StakeState::Uninitialized), + 1 => { + let meta: Meta = $borsh::BorshDeserialize::deserialize_reader(reader)?; + Ok(StakeState::Initialized(meta)) + } + 2 => { + let meta: Meta = $borsh::BorshDeserialize::deserialize_reader(reader)?; + let stake: Stake = $borsh::BorshDeserialize::deserialize_reader(reader)?; + Ok(StakeState::Stake(meta, stake)) + } + 3 => Ok(StakeState::RewardsPool), + _ => Err(io::Error::new( + io::ErrorKind::InvalidData, + "Invalid enum value", + )), + } + } + } + impl $borsh::BorshSerialize for StakeState { + fn serialize(&self, writer: &mut W) -> io::Result<()> { + match self { + StakeState::Uninitialized => writer.write_all(&0u32.to_le_bytes()), + StakeState::Initialized(meta) => { + writer.write_all(&1u32.to_le_bytes())?; + $borsh::BorshSerialize::serialize(&meta, writer) + } + StakeState::Stake(meta, stake) => { + writer.write_all(&2u32.to_le_bytes())?; + $borsh::BorshSerialize::serialize(&meta, writer)?; + $borsh::BorshSerialize::serialize(&stake, writer) + } + StakeState::RewardsPool => writer.write_all(&3u32.to_le_bytes()), + } + } + } + }; +} #[derive(Debug, Default, Serialize, Deserialize, PartialEq, Clone, Copy, AbiExample)] #[allow(clippy::large_enum_variant)] #[deprecated( @@ -47,45 +90,8 @@ pub enum StakeState { Stake(Meta, Stake), RewardsPool, } -impl BorshDeserialize for StakeState { - fn deserialize_reader(reader: &mut R) -> io::Result { - let enum_value = u32::deserialize_reader(reader)?; - match enum_value { - 0 => Ok(StakeState::Uninitialized), - 1 => { - let meta = Meta::deserialize_reader(reader)?; - Ok(StakeState::Initialized(meta)) - } - 2 => { - let meta: Meta = BorshDeserialize::deserialize_reader(reader)?; - let stake: Stake = BorshDeserialize::deserialize_reader(reader)?; - Ok(StakeState::Stake(meta, stake)) - } - 3 => Ok(StakeState::RewardsPool), - _ => Err(io::Error::new( - io::ErrorKind::InvalidData, - "Invalid enum value", - )), - } - } -} -impl BorshSerialize for StakeState { - fn serialize(&self, writer: &mut W) -> io::Result<()> { - match self { - StakeState::Uninitialized => writer.write_all(&0u32.to_le_bytes()), - StakeState::Initialized(meta) => { - writer.write_all(&1u32.to_le_bytes())?; - meta.serialize(writer) - } - StakeState::Stake(meta, stake) => { - writer.write_all(&2u32.to_le_bytes())?; - meta.serialize(writer)?; - stake.serialize(writer) - } - StakeState::RewardsPool => writer.write_all(&3u32.to_le_bytes()), - } - } -} +impl_borsh_stake_state!(borsh); +impl_borsh_stake_state!(borsh0_10); impl StakeState { /// The fixed number of bytes used to serialize each stake account pub const fn size_of() -> usize { @@ -136,49 +142,54 @@ pub enum StakeStateV2 { Stake(Meta, Stake, StakeFlags), RewardsPool, } - -impl BorshDeserialize for StakeStateV2 { - fn deserialize_reader(reader: &mut R) -> io::Result { - let enum_value = u32::deserialize_reader(reader)?; - match enum_value { - 0 => Ok(StakeStateV2::Uninitialized), - 1 => { - let meta = Meta::deserialize_reader(reader)?; - Ok(StakeStateV2::Initialized(meta)) +macro_rules! impl_borsh_stake_state_v2 { + ($borsh:ident) => { + impl $borsh::BorshDeserialize for StakeStateV2 { + fn deserialize_reader(reader: &mut R) -> io::Result { + let enum_value: u32 = $borsh::BorshDeserialize::deserialize_reader(reader)?; + match enum_value { + 0 => Ok(StakeStateV2::Uninitialized), + 1 => { + let meta: Meta = $borsh::BorshDeserialize::deserialize_reader(reader)?; + Ok(StakeStateV2::Initialized(meta)) + } + 2 => { + let meta: Meta = $borsh::BorshDeserialize::deserialize_reader(reader)?; + let stake: Stake = $borsh::BorshDeserialize::deserialize_reader(reader)?; + let stake_flags: StakeFlags = + $borsh::BorshDeserialize::deserialize_reader(reader)?; + Ok(StakeStateV2::Stake(meta, stake, stake_flags)) + } + 3 => Ok(StakeStateV2::RewardsPool), + _ => Err(io::Error::new( + io::ErrorKind::InvalidData, + "Invalid enum value", + )), + } } - 2 => { - let meta: Meta = BorshDeserialize::deserialize_reader(reader)?; - let stake: Stake = BorshDeserialize::deserialize_reader(reader)?; - let stake_flags: StakeFlags = BorshDeserialize::deserialize_reader(reader)?; - Ok(StakeStateV2::Stake(meta, stake, stake_flags)) - } - 3 => Ok(StakeStateV2::RewardsPool), - _ => Err(io::Error::new( - io::ErrorKind::InvalidData, - "Invalid enum value", - )), } - } -} - -impl BorshSerialize for StakeStateV2 { - fn serialize(&self, writer: &mut W) -> io::Result<()> { - match self { - StakeStateV2::Uninitialized => writer.write_all(&0u32.to_le_bytes()), - StakeStateV2::Initialized(meta) => { - writer.write_all(&1u32.to_le_bytes())?; - meta.serialize(writer) + impl $borsh::BorshSerialize for StakeStateV2 { + fn serialize(&self, writer: &mut W) -> io::Result<()> { + match self { + StakeStateV2::Uninitialized => writer.write_all(&0u32.to_le_bytes()), + StakeStateV2::Initialized(meta) => { + writer.write_all(&1u32.to_le_bytes())?; + $borsh::BorshSerialize::serialize(&meta, writer) + } + StakeStateV2::Stake(meta, stake, stake_flags) => { + writer.write_all(&2u32.to_le_bytes())?; + $borsh::BorshSerialize::serialize(&meta, writer)?; + $borsh::BorshSerialize::serialize(&stake, writer)?; + $borsh::BorshSerialize::serialize(&stake_flags, writer) + } + StakeStateV2::RewardsPool => writer.write_all(&3u32.to_le_bytes()), + } } - StakeStateV2::Stake(meta, stake, stake_flags) => { - writer.write_all(&2u32.to_le_bytes())?; - meta.serialize(writer)?; - stake.serialize(writer)?; - stake_flags.serialize(writer) - } - StakeStateV2::RewardsPool => writer.write_all(&3u32.to_le_bytes()), } - } + }; } +impl_borsh_stake_state_v2!(borsh); +impl_borsh_stake_state_v2!(borsh0_10); impl StakeStateV2 { /// The fixed number of bytes used to serialize each stake account @@ -241,6 +252,7 @@ pub enum StakeAuthorize { BorshSchema, BorshSerialize, )] +#[borsh(crate = "borsh")] pub struct Lockup { /// UnixTimestamp at which this stake will allow withdrawal, unless the /// transaction is signed by the custodian @@ -252,7 +264,6 @@ pub struct Lockup { /// lockup constraints pub custodian: Pubkey, } - impl Lockup { pub fn is_in_force(&self, clock: &Clock, custodian: Option<&Pubkey>) -> bool { if custodian == Some(&self.custodian) { @@ -261,6 +272,65 @@ impl Lockup { self.unix_timestamp > clock.unix_timestamp || self.epoch > clock.epoch } } +impl borsh0_10::de::BorshDeserialize for Lockup { + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + Ok(Self { + unix_timestamp: borsh0_10::BorshDeserialize::deserialize_reader(reader)?, + epoch: borsh0_10::BorshDeserialize::deserialize_reader(reader)?, + custodian: borsh0_10::BorshDeserialize::deserialize_reader(reader)?, + }) + } +} +impl borsh0_10::BorshSchema for Lockup { + fn declaration() -> borsh0_10::schema::Declaration { + "Lockup".to_string() + } + fn add_definitions_recursively( + definitions: &mut borsh0_10::maybestd::collections::HashMap< + borsh0_10::schema::Declaration, + borsh0_10::schema::Definition, + >, + ) { + let fields = borsh0_10::schema::Fields::NamedFields(<[_]>::into_vec( + borsh0_10::maybestd::boxed::Box::new([ + ( + "unix_timestamp".to_string(), + ::declaration(), + ), + ( + "epoch".to_string(), + ::declaration(), + ), + ( + "custodian".to_string(), + ::declaration(), + ), + ]), + )); + let definition = borsh0_10::schema::Definition::Struct { fields }; + Self::add_definition( + ::declaration(), + definition, + definitions, + ); + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + } +} +impl borsh0_10::ser::BorshSerialize for Lockup { + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh0_10::maybestd::io::Error> { + borsh0_10::BorshSerialize::serialize(&self.unix_timestamp, writer)?; + borsh0_10::BorshSerialize::serialize(&self.epoch, writer)?; + borsh0_10::BorshSerialize::serialize(&self.custodian, writer)?; + Ok(()) + } +} #[derive( Default, @@ -276,6 +346,7 @@ impl Lockup { BorshSchema, BorshSerialize, )] +#[borsh(crate = "borsh")] pub struct Authorized { pub staker: Pubkey, pub withdrawer: Pubkey, @@ -341,6 +412,58 @@ impl Authorized { Ok(()) } } +impl borsh0_10::de::BorshDeserialize for Authorized { + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + Ok(Self { + staker: borsh0_10::BorshDeserialize::deserialize_reader(reader)?, + withdrawer: borsh0_10::BorshDeserialize::deserialize_reader(reader)?, + }) + } +} +impl borsh0_10::BorshSchema for Authorized { + fn declaration() -> borsh0_10::schema::Declaration { + "Authorized".to_string() + } + fn add_definitions_recursively( + definitions: &mut borsh0_10::maybestd::collections::HashMap< + borsh0_10::schema::Declaration, + borsh0_10::schema::Definition, + >, + ) { + let fields = borsh0_10::schema::Fields::NamedFields(<[_]>::into_vec( + borsh0_10::maybestd::boxed::Box::new([ + ( + "staker".to_string(), + ::declaration(), + ), + ( + "withdrawer".to_string(), + ::declaration(), + ), + ]), + )); + let definition = borsh0_10::schema::Definition::Struct { fields }; + Self::add_definition( + ::declaration(), + definition, + definitions, + ); + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + } +} +impl borsh0_10::ser::BorshSerialize for Authorized { + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh0_10::maybestd::io::Error> { + borsh0_10::BorshSerialize::serialize(&self.staker, writer)?; + borsh0_10::BorshSerialize::serialize(&self.withdrawer, writer)?; + Ok(()) + } +} #[derive( Default, @@ -356,6 +479,7 @@ impl Authorized { BorshSchema, BorshSerialize, )] +#[borsh(crate = "borsh")] pub struct Meta { pub rent_exempt_reserve: u64, pub authorized: Authorized, @@ -398,6 +522,65 @@ impl Meta { } } } +impl borsh0_10::de::BorshDeserialize for Meta { + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + Ok(Self { + rent_exempt_reserve: borsh0_10::BorshDeserialize::deserialize_reader(reader)?, + authorized: borsh0_10::BorshDeserialize::deserialize_reader(reader)?, + lockup: borsh0_10::BorshDeserialize::deserialize_reader(reader)?, + }) + } +} +impl borsh0_10::BorshSchema for Meta { + fn declaration() -> borsh0_10::schema::Declaration { + "Meta".to_string() + } + fn add_definitions_recursively( + definitions: &mut borsh0_10::maybestd::collections::HashMap< + borsh0_10::schema::Declaration, + borsh0_10::schema::Definition, + >, + ) { + let fields = borsh0_10::schema::Fields::NamedFields(<[_]>::into_vec( + borsh0_10::maybestd::boxed::Box::new([ + ( + "rent_exempt_reserve".to_string(), + ::declaration(), + ), + ( + "authorized".to_string(), + ::declaration(), + ), + ( + "lockup".to_string(), + ::declaration(), + ), + ]), + )); + let definition = borsh0_10::schema::Definition::Struct { fields }; + Self::add_definition( + ::declaration(), + definition, + definitions, + ); + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + } +} +impl borsh0_10::ser::BorshSerialize for Meta { + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh0_10::maybestd::io::Error> { + borsh0_10::BorshSerialize::serialize(&self.rent_exempt_reserve, writer)?; + borsh0_10::BorshSerialize::serialize(&self.authorized, writer)?; + borsh0_10::BorshSerialize::serialize(&self.lockup, writer)?; + Ok(()) + } +} #[derive( Debug, @@ -411,6 +594,7 @@ impl Meta { BorshSchema, BorshSerialize, )] +#[borsh(crate = "borsh")] pub struct Delegation { /// to whom the stake is delegated pub voter_pubkey: Pubkey, @@ -644,6 +828,79 @@ impl Delegation { } } } +impl borsh0_10::de::BorshDeserialize for Delegation { + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + Ok(Self { + voter_pubkey: borsh0_10::BorshDeserialize::deserialize_reader(reader)?, + stake: borsh0_10::BorshDeserialize::deserialize_reader(reader)?, + activation_epoch: borsh0_10::BorshDeserialize::deserialize_reader(reader)?, + deactivation_epoch: borsh0_10::BorshDeserialize::deserialize_reader(reader)?, + warmup_cooldown_rate: borsh0_10::BorshDeserialize::deserialize_reader(reader)?, + }) + } +} +impl borsh0_10::BorshSchema for Delegation { + fn declaration() -> borsh0_10::schema::Declaration { + "Delegation".to_string() + } + fn add_definitions_recursively( + definitions: &mut borsh0_10::maybestd::collections::HashMap< + borsh0_10::schema::Declaration, + borsh0_10::schema::Definition, + >, + ) { + let fields = borsh0_10::schema::Fields::NamedFields(<[_]>::into_vec( + borsh0_10::maybestd::boxed::Box::new([ + ( + "voter_pubkey".to_string(), + ::declaration(), + ), + ( + "stake".to_string(), + ::declaration(), + ), + ( + "activation_epoch".to_string(), + ::declaration(), + ), + ( + "deactivation_epoch".to_string(), + ::declaration(), + ), + ( + "warmup_cooldown_rate".to_string(), + ::declaration(), + ), + ]), + )); + let definition = borsh0_10::schema::Definition::Struct { fields }; + Self::add_definition( + ::declaration(), + definition, + definitions, + ); + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + } +} +impl borsh0_10::ser::BorshSerialize for Delegation { + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh0_10::maybestd::io::Error> { + borsh0_10::BorshSerialize::serialize(&self.voter_pubkey, writer)?; + borsh0_10::BorshSerialize::serialize(&self.stake, writer)?; + borsh0_10::BorshSerialize::serialize(&self.activation_epoch, writer)?; + borsh0_10::BorshSerialize::serialize(&self.deactivation_epoch, writer)?; + borsh0_10::BorshSerialize::serialize(&self.warmup_cooldown_rate, writer)?; + Ok(()) + } +} #[derive( Debug, @@ -658,6 +915,7 @@ impl Delegation { BorshSchema, BorshSerialize, )] +#[borsh(crate = "borsh")] pub struct Stake { pub delegation: Delegation, /// credits observed is credits from vote account state when delegated or redeemed @@ -703,11 +961,63 @@ impl Stake { } } } +impl borsh0_10::de::BorshDeserialize for Stake { + fn deserialize_reader( + reader: &mut R, + ) -> ::core::result::Result { + Ok(Self { + delegation: borsh0_10::BorshDeserialize::deserialize_reader(reader)?, + credits_observed: borsh0_10::BorshDeserialize::deserialize_reader(reader)?, + }) + } +} +impl borsh0_10::BorshSchema for Stake { + fn declaration() -> borsh0_10::schema::Declaration { + "Stake".to_string() + } + fn add_definitions_recursively( + definitions: &mut borsh0_10::maybestd::collections::HashMap< + borsh0_10::schema::Declaration, + borsh0_10::schema::Definition, + >, + ) { + let fields = borsh0_10::schema::Fields::NamedFields(<[_]>::into_vec( + borsh0_10::maybestd::boxed::Box::new([ + ( + "delegation".to_string(), + ::declaration(), + ), + ( + "credits_observed".to_string(), + ::declaration(), + ), + ]), + )); + let definition = borsh0_10::schema::Definition::Struct { fields }; + Self::add_definition( + ::declaration(), + definition, + definitions, + ); + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + } +} +impl borsh0_10::ser::BorshSerialize for Stake { + fn serialize( + &self, + writer: &mut W, + ) -> ::core::result::Result<(), borsh0_10::maybestd::io::Error> { + borsh0_10::BorshSerialize::serialize(&self.delegation, writer)?; + borsh0_10::BorshSerialize::serialize(&self.credits_observed, writer)?; + Ok(()) + } +} #[cfg(test)] mod test { use { - super::*, crate::borsh0_10::try_from_slice_unchecked, assert_matches::assert_matches, + super::*, crate::borsh1::try_from_slice_unchecked, assert_matches::assert_matches, bincode::serialize, }; @@ -719,7 +1029,7 @@ mod test { fn check_borsh_serialization(stake: StakeStateV2) { let bincode_serialized = serialize(&stake).unwrap(); - let borsh_serialized = StakeStateV2::try_to_vec(&stake).unwrap(); + let borsh_serialized = borsh::to_vec(&stake).unwrap(); assert_eq!(bincode_serialized, borsh_serialized); } @@ -850,7 +1160,7 @@ mod test { ); let bincode_serialized = serialize(&stake).unwrap(); - let borsh_serialized = StakeStateV2::try_to_vec(&stake).unwrap(); + let borsh_serialized = borsh::to_vec(&stake).unwrap(); assert_eq!(bincode_serialized[FLAG_OFFSET], expected); assert_eq!(borsh_serialized[FLAG_OFFSET], expected); @@ -872,7 +1182,7 @@ mod test { fn check_borsh_serialization(stake: StakeState) { let bincode_serialized = serialize(&stake).unwrap(); - let borsh_serialized = StakeState::try_to_vec(&stake).unwrap(); + let borsh_serialized = borsh::to_vec(&stake).unwrap(); assert_eq!(bincode_serialized, borsh_serialized); } diff --git a/sdk/program/src/system_instruction.rs b/sdk/program/src/system_instruction.rs index 74646f7fb..da2065ccc 100644 --- a/sdk/program/src/system_instruction.rs +++ b/sdk/program/src/system_instruction.rs @@ -378,6 +378,7 @@ pub enum SystemInstruction { /// }; /// /// #[derive(BorshSerialize, BorshDeserialize, Debug)] +/// # #[borsh(crate = "borsh")] /// pub struct CreateAccountInstruction { /// /// The PDA seed used to distinguish the new account from other PDAs /// pub new_account_seed: [u8; 16], @@ -594,6 +595,7 @@ pub fn create_account_with_seed( /// }; /// /// #[derive(BorshSerialize, BorshDeserialize, Debug)] +/// # #[borsh(crate = "borsh")] /// pub struct CreateAccountInstruction { /// /// The PDA seed used to distinguish the new account from other PDAs /// pub new_account_seed: [u8; 16], @@ -804,6 +806,7 @@ pub fn assign_with_seed( /// }; /// /// #[derive(BorshSerialize, BorshDeserialize, Debug)] +/// # #[borsh(crate = "borsh")] /// pub struct CreateAccountInstruction { /// /// The PDA seed used to distinguish the new account from other PDAs /// pub new_account_seed: [u8; 16], @@ -1023,6 +1026,7 @@ pub fn transfer_with_seed( /// }; /// /// #[derive(BorshSerialize, BorshDeserialize, Debug)] +/// # #[borsh(crate = "borsh")] /// pub struct CreateAccountInstruction { /// /// The PDA seed used to distinguish the new account from other PDAs /// pub new_account_seed: [u8; 16], @@ -1220,6 +1224,7 @@ pub fn allocate_with_seed( /// /// - 1: system_program - executable /// /// - *: to - writable /// #[derive(BorshSerialize, BorshDeserialize, Debug)] +/// # #[borsh(crate = "borsh")] /// pub struct TransferLamportsToManyInstruction { /// pub bank_pda_bump_seed: u8, /// pub amount_list: Vec, diff --git a/sdk/src/compute_budget.rs b/sdk/src/compute_budget.rs index 84d0c3766..cf9ad7d43 100644 --- a/sdk/src/compute_budget.rs +++ b/sdk/src/compute_budget.rs @@ -63,9 +63,9 @@ impl ComputeBudgetInstruction { /// Serialize Instruction using borsh, this is only used in runtime::cost_model::tests but compilation /// can't be restricted as it's used across packages - // #[cfg(test)] - pub fn pack(self) -> Result, std::io::Error> { - self.try_to_vec() + #[cfg(feature = "dev-context-only-utils")] + pub fn pack(self) -> Result, borsh::io::Error> { + borsh::to_vec(&self) } /// Create a `ComputeBudgetInstruction::SetLoadedAccountsDataSizeLimit` `Instruction` diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index eaaea2d48..1b6763f8e 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -46,15 +46,16 @@ pub use solana_program::address_lookup_table_account; pub use solana_program::program_stubs; pub use solana_program::{ account_info, address_lookup_table, 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, poseidon, 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, + borsh1, 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, poseidon, 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; diff --git a/transaction-status/Cargo.toml b/transaction-status/Cargo.toml index 3c830f591..a4837acb3 100644 --- a/transaction-status/Cargo.toml +++ b/transaction-status/Cargo.toml @@ -13,7 +13,9 @@ edition = { workspace = true } Inflector = { workspace = true } base64 = { workspace = true } bincode = { workspace = true } -borsh = { workspace = true } +# Update this borsh dependency to the workspace version once +# spl-associated-token-account is upgraded and used in the monorepo. +borsh = { version = "0.10.3" } bs58 = { workspace = true } lazy_static = { workspace = true } log = { workspace = true }