diff --git a/Cargo.lock b/Cargo.lock index 413057eee8d4f4..e317b6cc79ed6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7524,6 +7524,41 @@ dependencies = [ "solana-sha256-hasher", ] +[[package]] +name = "solana-message" +version = "2.2.0" +dependencies = [ + "anyhow", + "bincode", + "bitflags 2.6.0", + "blake3", + "borsh 1.5.3", + "itertools 0.12.1", + "lazy_static", + "serde", + "serde_derive", + "serde_json", + "solana-bincode", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-hash", + "solana-instruction", + "solana-logger", + "solana-message", + "solana-nonce", + "solana-program", + "solana-pubkey", + "solana-sanitize", + "solana-sdk-ids", + "solana-sha256-hasher", + "solana-short-vec", + "solana-system-interface", + "solana-sysvar", + "solana-transaction-error", + "static_assertions", + "wasm-bindgen", +] + [[package]] name = "solana-metrics" version = "2.2.0" @@ -7829,6 +7864,7 @@ dependencies = [ "solana-keccak-hasher", "solana-last-restart-slot", "solana-logger", + "solana-message", "solana-msg", "solana-native-token", "solana-nonce", diff --git a/Cargo.toml b/Cargo.toml index ddfb2f172e3ef7..c4fc06edf5d9c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -131,6 +131,7 @@ members = [ "sdk/keypair", "sdk/logger", "sdk/macro", + "sdk/message", "sdk/msg", "sdk/native-token", "sdk/nonce", @@ -488,6 +489,7 @@ solana-log-collector = { path = "log-collector", version = "=2.2.0" } solana-logger = { path = "sdk/logger", version = "=2.2.0" } solana-measure = { path = "measure", version = "=2.2.0" } solana-merkle-tree = { path = "merkle-tree", version = "=2.2.0" } +solana-message = { path = "sdk/message", version = "=2.2.0" } solana-metrics = { path = "metrics", version = "=2.2.0" } solana-msg = { path = "sdk/msg", version = "=2.2.0" } solana-native-token = { path = "sdk/native-token", version = "=2.2.0" } diff --git a/gossip/src/protocol.rs b/gossip/src/protocol.rs index 6d5559dd80b02f..5467e758e4f15b 100644 --- a/gossip/src/protocol.rs +++ b/gossip/src/protocol.rs @@ -46,7 +46,7 @@ pub(crate) const PULL_RESPONSE_MIN_SERIALIZED_SIZE: usize = 161; #[cfg_attr( feature = "frozen-abi", derive(AbiExample, AbiEnumVisitor), - frozen_abi(digest = "D8HvpYCkdo6JweUW61WQ9ZQH2AFvzh3G1qthicnvz4E8") + frozen_abi(digest = "ESDND6D3FcRyA6UTUpDVDcS4AkESc5E6UtZWSbT7G8e8") )] #[derive(Serialize, Deserialize, Debug)] #[allow(clippy::large_enum_variant)] diff --git a/programs/sbf/Cargo.lock b/programs/sbf/Cargo.lock index d3e4945d240c68..c23f52f0a6ef3d 100644 --- a/programs/sbf/Cargo.lock +++ b/programs/sbf/Cargo.lock @@ -5947,6 +5947,27 @@ dependencies = [ "solana-sha256-hasher", ] +[[package]] +name = "solana-message" +version = "2.2.0" +dependencies = [ + "bincode", + "blake3", + "lazy_static", + "serde", + "serde_derive", + "solana-bincode", + "solana-hash", + "solana-instruction", + "solana-pubkey", + "solana-sanitize", + "solana-sdk-ids", + "solana-short-vec", + "solana-system-interface", + "solana-transaction-error", + "wasm-bindgen", +] + [[package]] name = "solana-metrics" version = "2.2.0" @@ -6156,6 +6177,7 @@ dependencies = [ "solana-instruction", "solana-keccak-hasher", "solana-last-restart-slot", + "solana-message", "solana-msg", "solana-native-token", "solana-nonce", diff --git a/sdk/message/Cargo.toml b/sdk/message/Cargo.toml new file mode 100644 index 00000000000000..20d8ab43dcef3a --- /dev/null +++ b/sdk/message/Cargo.toml @@ -0,0 +1,79 @@ +[package] +name = "solana-message" +description = "Solana transaction message types." +documentation = "https://docs.rs/solana-message" +version = { workspace = true } +authors = { workspace = true } +repository = { workspace = true } +homepage = { workspace = true } +license = { workspace = true } +edition = { workspace = true } + +[dependencies] +bincode = { workspace = true, optional = true } +blake3 = { workspace = true, features = ["traits-preview"], optional = true } +lazy_static = { workspace = true } +serde = { workspace = true, optional = true } +serde_derive = { workspace = true, optional = true } +solana-bincode = { workspace = true, optional = true } +solana-frozen-abi = { workspace = true, optional = true } +solana-frozen-abi-macro = { workspace = true, optional = true } +solana-hash = { workspace = true } +solana-instruction = { workspace = true, features = ["std"] } +solana-logger = { workspace = true, optional = true } +solana-pubkey = { workspace = true } +solana-sanitize = { workspace = true } +solana-sdk-ids = { workspace = true } +solana-short-vec = { workspace = true, optional = true } +solana-system-interface = { workspace = true, optional = true, features = [ + "bincode", +] } +solana-transaction-error = { workspace = true } + +[target.'cfg(target_arch = "wasm32")'.dependencies] +wasm-bindgen = { workspace = true } + +[dev-dependencies] +anyhow = { workspace = true } +bitflags = { workspace = true } +borsh = { workspace = true } +itertools = { workspace = true } +serde_json = { workspace = true } +solana-message = { path = ".", features = ["dev-context-only-utils"] } +solana-nonce = { workspace = true } +solana-program = { path = "../program" } +solana-sha256-hasher = { workspace = true } +solana-sysvar = { workspace = true } +static_assertions = { workspace = true } + +[features] +bincode = [ + "dep:bincode", + "dep:solana-bincode", + "dep:solana-system-interface", + "serde", +] +blake3 = ["dep:blake3"] +dev-context-only-utils = ["bincode", "blake3"] +frozen-abi = [ + "dep:solana-frozen-abi", + "dep:solana-frozen-abi-macro", + "dep:solana-logger", + "solana-hash/frozen-abi", + "solana-pubkey/frozen-abi", +] +serde = [ + "dep:serde", + "dep:serde_derive", + "dep:solana-short-vec", + "solana-hash/serde", + "solana-pubkey/serde", +] + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] +all-features = true +rustdoc-args = ["--cfg=docsrs"] + +[lints] +workspace = true diff --git a/sdk/program/src/message/account_keys.rs b/sdk/message/src/account_keys.rs similarity index 98% rename from sdk/program/src/message/account_keys.rs rename to sdk/message/src/account_keys.rs index e7dbd061cede76..e36349b76418b2 100644 --- a/sdk/program/src/message/account_keys.rs +++ b/sdk/message/src/account_keys.rs @@ -1,9 +1,7 @@ use { - crate::{ - instruction::{CompiledInstruction, Instruction}, - message::{v0::LoadedAddresses, CompileError}, - pubkey::Pubkey, - }, + crate::{compiled_instruction::CompiledInstruction, v0::LoadedAddresses, CompileError}, + solana_instruction::Instruction, + solana_pubkey::Pubkey, std::{collections::BTreeMap, iter::zip, ops::Index}, }; @@ -152,7 +150,7 @@ impl PartialEq for AccountKeys<'_> { #[cfg(test)] mod tests { - use {super::*, crate::instruction::AccountMeta}; + use {super::*, solana_instruction::AccountMeta}; fn test_account_keys() -> [Pubkey; 6] { let key0 = Pubkey::new_unique(); diff --git a/sdk/program/src/message/address_loader.rs b/sdk/message/src/address_loader.rs similarity index 92% rename from sdk/program/src/message/address_loader.rs rename to sdk/message/src/address_loader.rs index 632117718660bc..82ac882a7cd2af 100644 --- a/sdk/program/src/message/address_loader.rs +++ b/sdk/message/src/address_loader.rs @@ -1,4 +1,4 @@ -use super::v0::{LoadedAddresses, MessageAddressTableLookup}; +use crate::v0::{LoadedAddresses, MessageAddressTableLookup}; #[deprecated( since = "2.1.0", note = "Use solana_transaction_error::AddressLoaderError instead" diff --git a/sdk/message/src/compiled_instruction.rs b/sdk/message/src/compiled_instruction.rs new file mode 100644 index 00000000000000..dc972854f6a06c --- /dev/null +++ b/sdk/message/src/compiled_instruction.rs @@ -0,0 +1,56 @@ +#[cfg(feature = "serde")] +use serde_derive::{Deserialize, Serialize}; +#[cfg(feature = "frozen-abi")] +use solana_frozen_abi_macro::AbiExample; +use {solana_pubkey::Pubkey, solana_sanitize::Sanitize}; + +/// A compact encoding of an instruction. +/// +/// A `CompiledInstruction` is a component of a multi-instruction [`Message`], +/// which is the core of a Solana transaction. It is created during the +/// construction of `Message`. Most users will not interact with it directly. +/// +/// [`Message`]: crate::Message +#[cfg_attr(feature = "frozen-abi", derive(AbiExample))] +#[cfg_attr( + feature = "serde", + derive(Deserialize, Serialize), + serde(rename_all = "camelCase") +)] +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct CompiledInstruction { + /// Index into the transaction keys array indicating the program account that executes this instruction. + pub program_id_index: u8, + /// Ordered indices into the transaction keys array indicating which accounts to pass to the program. + #[cfg_attr(feature = "serde", serde(with = "solana_short_vec"))] + pub accounts: Vec, + /// The program input data. + #[cfg_attr(feature = "serde", serde(with = "solana_short_vec"))] + pub data: Vec, +} + +impl Sanitize for CompiledInstruction {} + +impl CompiledInstruction { + #[cfg(feature = "bincode")] + pub fn new(program_ids_index: u8, data: &T, accounts: Vec) -> Self { + let data = bincode::serialize(data).unwrap(); + Self { + program_id_index: program_ids_index, + accounts, + data, + } + } + + pub fn new_from_raw_parts(program_id_index: u8, data: Vec, accounts: Vec) -> Self { + Self { + program_id_index, + accounts, + data, + } + } + + pub fn program_id<'a>(&self, program_ids: &'a [Pubkey]) -> &'a Pubkey { + &program_ids[self.program_id_index as usize] + } +} diff --git a/sdk/program/src/message/compiled_keys.rs b/sdk/message/src/compiled_keys.rs similarity index 95% rename from sdk/program/src/message/compiled_keys.rs rename to sdk/message/src/compiled_keys.rs index a9964c33448be2..c973374791263e 100644 --- a/sdk/program/src/message/compiled_keys.rs +++ b/sdk/message/src/compiled_keys.rs @@ -1,12 +1,11 @@ #[cfg(not(target_os = "solana"))] use crate::{ - address_lookup_table::AddressLookupTableAccount, - message::v0::{LoadedAddresses, MessageAddressTableLookup}, + v0::{LoadedAddresses, MessageAddressTableLookup}, + AddressLookupTableAccount, }; use { - crate::{instruction::Instruction, message::MessageHeader, pubkey::Pubkey}, + crate::MessageHeader, core::fmt, solana_instruction::Instruction, solana_pubkey::Pubkey, std::collections::BTreeMap, - thiserror::Error, }; /// A helper struct to collect pubkeys compiled for a set of instructions @@ -17,16 +16,32 @@ pub(crate) struct CompiledKeys { } #[cfg_attr(target_os = "solana", allow(dead_code))] -#[derive(PartialEq, Debug, Error, Eq, Clone)] +#[derive(PartialEq, Debug, Eq, Clone)] pub enum CompileError { - #[error("account index overflowed during compilation")] AccountIndexOverflow, - #[error("address lookup table index overflowed during compilation")] AddressTableLookupIndexOverflow, - #[error("encountered unknown account key `{0}` during instruction compilation")] UnknownInstructionKey(Pubkey), } +impl std::error::Error for CompileError {} + +impl fmt::Display for CompileError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + CompileError::AccountIndexOverflow => { + f.write_str("account index overflowed during compilation") + } + CompileError::AddressTableLookupIndexOverflow => { + f.write_str("address lookup table index overflowed during compilation") + } + CompileError::UnknownInstructionKey(key) => f.write_fmt(format_args!( + "encountered unknown account key `{0}` during instruction compilation", + key, + )), + } + } +} + #[derive(Default, Debug, Clone, PartialEq, Eq)] struct CompiledKeyMeta { is_signer: bool, @@ -184,7 +199,7 @@ impl CompiledKeys { #[cfg(test)] mod tests { - use {super::*, crate::instruction::AccountMeta, bitflags::bitflags}; + use {super::*, bitflags::bitflags, solana_instruction::AccountMeta}; bitflags! { #[derive(Clone, Copy)] diff --git a/sdk/program/src/message/legacy.rs b/sdk/message/src/legacy.rs similarity index 90% rename from sdk/program/src/message/legacy.rs rename to sdk/message/src/legacy.rs index f225e5a646b654..1c467e9b7df24b 100644 --- a/sdk/program/src/message/legacy.rs +++ b/sdk/message/src/legacy.rs @@ -5,30 +5,58 @@ //! `v0` is a [future message format] that encodes more account keys into a //! transaction than the legacy format. //! -//! [`legacy`]: crate::message::legacy -//! [`v0`]: crate::message::v0 +//! [`legacy`]: crate::legacy +//! [`v0`]: crate::v0 //! [future message format]: https://docs.solanalabs.com/proposals/versioned-transactions #![allow(clippy::arithmetic_side_effects)] -#[cfg(target_arch = "wasm32")] -use crate::wasm_bindgen; #[allow(deprecated)] pub use builtins::{BUILTIN_PROGRAMS_KEYS, MAYBE_BUILTIN_KEY_OR_SYSVAR}; +#[cfg(feature = "serde")] +use serde_derive::{Deserialize, Serialize}; +#[cfg(feature = "frozen-abi")] +use solana_frozen_abi_macro::{frozen_abi, AbiExample}; +#[cfg(target_arch = "wasm32")] +use wasm_bindgen::prelude::wasm_bindgen; use { crate::{ - bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, - hash::Hash, - instruction::{CompiledInstruction, Instruction}, - message::{compiled_keys::CompiledKeys, MessageHeader}, - pubkey::Pubkey, - system_instruction, system_program, sysvar, + compiled_instruction::CompiledInstruction, compiled_keys::CompiledKeys, MessageHeader, }, + solana_hash::Hash, + solana_instruction::Instruction, + solana_pubkey::Pubkey, solana_sanitize::{Sanitize, SanitizeError}, - solana_short_vec as short_vec, + solana_sdk_ids::{ + bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, system_program, sysvar, + }, std::{collections::HashSet, convert::TryFrom, str::FromStr}, }; +// copied from deprecated code in solana_program::sysvar to avoid a dependency. +// This should be removed when the items that depend on it are removed. +lazy_static::lazy_static! { + // This will be deprecated and so this list shouldn't be modified + static ref ALL_IDS: Vec = vec![ + sysvar::clock::id(), + sysvar::epoch_schedule::id(), + sysvar::fees::id(), + sysvar::recent_blockhashes::id(), + sysvar::rent::id(), + sysvar::rewards::id(), + sysvar::slot_hashes::id(), + sysvar::slot_history::id(), + sysvar::stake_history::id(), + sysvar::instructions::id(), + ]; +} + +// copied from deprecated code in solana_program::sysvar to avoid a dependency. +// This should be removed when the items that depend on it are removed. +fn is_sysvar_id(id: &Pubkey) -> bool { + ALL_IDS.iter().any(|key| key == id) +} + #[deprecated( since = "2.0.0", note = "please use `solana_sdk::reserved_account_keys::ReservedAccountKeys` instead" @@ -64,7 +92,7 @@ mod builtins { pub static ref MAYBE_BUILTIN_KEY_OR_SYSVAR: [bool; 256] = { let mut temp_table: [bool; 256] = [false; 256]; BUILTIN_PROGRAMS_KEYS.iter().for_each(|key| temp_table[key.as_ref()[0] as usize] = true); - sysvar::ALL_IDS.iter().for_each(|key| temp_table[key.as_ref()[0] as usize] = true); + ALL_IDS.iter().for_each(|key| temp_table[key.as_ref()[0] as usize] = true); temp_table }; } @@ -77,7 +105,7 @@ mod builtins { #[allow(deprecated)] pub fn is_builtin_key_or_sysvar(key: &Pubkey) -> bool { if MAYBE_BUILTIN_KEY_OR_SYSVAR[key.as_ref()[0] as usize] { - return sysvar::is_sysvar_id(key) || BUILTIN_PROGRAMS_KEYS.contains(key); + return is_sysvar_id(key) || BUILTIN_PROGRAMS_KEYS.contains(key); } false } @@ -106,9 +134,7 @@ fn compile_instructions(ixs: &[Instruction], keys: &[Pubkey]) -> Vec Vec, /// The id of a recent ledger entry. @@ -142,7 +172,7 @@ pub struct Message { /// Programs that will be executed in sequence and committed in one atomic transaction if all /// succeed. - #[serde(with = "short_vec")] + #[cfg_attr(feature = "serde", serde(with = "solana_short_vec"))] pub instructions: Vec, } @@ -153,24 +183,28 @@ pub struct Message { #[wasm_bindgen] #[cfg_attr( feature = "frozen-abi", - frozen_abi(digest = "4kL6EbLGU25m5eMk4H1cW9YGhA5LejHSgj2w2fhY1NGp"), + frozen_abi(digest = "2THeaWnXSGDTsiadKytJTcbjrk4KjfMww9arRLZcwGnw"), derive(AbiExample) )] -#[derive(Serialize, Deserialize, Default, Debug, PartialEq, Eq, Clone)] -#[serde(rename_all = "camelCase")] +#[cfg_attr( + feature = "serde", + derive(Deserialize, Serialize), + serde(rename_all = "camelCase") +)] +#[derive(Default, Debug, PartialEq, Eq, Clone)] pub struct Message { #[wasm_bindgen(skip)] pub header: MessageHeader, #[wasm_bindgen(skip)] - #[serde(with = "short_vec")] + #[cfg_attr(feature = "serde", serde(with = "solana_short_vec"))] pub account_keys: Vec, /// The id of a recent ledger entry. pub recent_blockhash: Hash, #[wasm_bindgen(skip)] - #[serde(with = "short_vec")] + #[cfg_attr(feature = "serde", serde(with = "solana_short_vec"))] pub instructions: Vec, } @@ -226,11 +260,11 @@ impl Message { /// # use solana_program::example_mocks::solana_rpc_client; /// use anyhow::Result; /// use borsh::{BorshSerialize, BorshDeserialize}; + /// use solana_instruction::Instruction; + /// use solana_message::Message; + /// use solana_pubkey::Pubkey; /// use solana_rpc_client::rpc_client::RpcClient; /// use solana_sdk::{ - /// instruction::Instruction, - /// message::Message, - /// pubkey::Pubkey, /// signature::{Keypair, Signer}, /// transaction::Transaction, /// }; @@ -298,11 +332,11 @@ impl Message { /// # use solana_program::example_mocks::solana_rpc_client; /// use anyhow::Result; /// use borsh::{BorshSerialize, BorshDeserialize}; + /// use solana_instruction::Instruction; + /// use solana_message::Message; + /// use solana_pubkey::Pubkey; /// use solana_rpc_client::rpc_client::RpcClient; /// use solana_sdk::{ - /// instruction::Instruction, - /// message::Message, - /// pubkey::Pubkey, /// signature::{Keypair, Signer}, /// transaction::Transaction, /// }; @@ -395,17 +429,16 @@ impl Message { /// # use solana_program::example_mocks::solana_rpc_client; /// use anyhow::Result; /// use borsh::{BorshSerialize, BorshDeserialize}; + /// use solana_hash::Hash; + /// use solana_instruction::Instruction; + /// use solana_message::Message; + /// use solana_pubkey::Pubkey; /// use solana_rpc_client::rpc_client::RpcClient; /// use solana_sdk::{ - /// hash::Hash, - /// instruction::Instruction, - /// message::Message, - /// nonce, - /// pubkey::Pubkey, /// signature::{Keypair, Signer}, - /// system_instruction, /// transaction::Transaction, /// }; + /// use solana_system_interface::instruction::create_nonce_account; /// /// // A custom program instruction. This would typically be defined in /// // another crate so it can be shared between the on-chain program and @@ -455,12 +488,12 @@ impl Message { /// -> Result /// { /// let nonce_account_address = Keypair::new(); - /// let nonce_account_size = nonce::State::size(); + /// let nonce_account_size = solana_nonce::state::State::size(); /// let nonce_rent = client.get_minimum_balance_for_rent_exemption(nonce_account_size)?; /// /// // Assigning the nonce authority to the payer so they can sign for the withdrawal, /// // and we can throw away the nonce address secret key. - /// let create_nonce_instr = system_instruction::create_nonce_account( + /// let create_nonce_instr = create_nonce_account( /// &payer.pubkey(), /// &nonce_account_address.pubkey(), /// &payer.pubkey(), @@ -481,14 +514,17 @@ impl Message { /// # create_offline_initialize_tx(&client, program_id, &payer)?; /// # Ok::<(), anyhow::Error>(()) /// ``` + #[cfg(feature = "bincode")] pub fn new_with_nonce( mut instructions: Vec, payer: Option<&Pubkey>, nonce_account_pubkey: &Pubkey, nonce_authority_pubkey: &Pubkey, ) -> Self { - let nonce_ix = - system_instruction::advance_nonce_account(nonce_account_pubkey, nonce_authority_pubkey); + let nonce_ix = solana_system_interface::instruction::advance_nonce_account( + nonce_account_pubkey, + nonce_authority_pubkey, + ); instructions.insert(0, nonce_ix); Self::new(&instructions, payer) } @@ -514,14 +550,14 @@ impl Message { } /// Compute the blake3 hash of this transaction's message. - #[cfg(not(target_os = "solana"))] + #[cfg(all(not(target_os = "solana"), feature = "bincode", feature = "blake3"))] pub fn hash(&self) -> Hash { let message_bytes = self.serialize(); Self::hash_raw_message(&message_bytes) } /// Compute the blake3 hash of a raw transaction message. - #[cfg(not(target_os = "solana"))] + #[cfg(all(not(target_os = "solana"), feature = "blake3"))] pub fn hash_raw_message(message_bytes: &[u8]) -> Hash { use {blake3::traits::digest::Digest, solana_hash::HASH_BYTES}; let mut hasher = blake3::Hasher::new(); @@ -535,6 +571,7 @@ impl Message { compile_instruction(ix, &self.account_keys) } + #[cfg(feature = "bincode")] pub fn serialize(&self) -> Vec { bincode::serialize(self).unwrap() } @@ -699,9 +736,8 @@ impl Message { mod tests { #![allow(deprecated)] use { - super::*, - crate::{hash, instruction::AccountMeta, message::MESSAGE_HEADER_LENGTH}, - std::collections::HashSet, + super::*, crate::MESSAGE_HEADER_LENGTH, solana_instruction::AccountMeta, + solana_sha256_hasher::hash, std::collections::HashSet, }; #[test] @@ -720,7 +756,7 @@ mod tests { // BUILTIN_PROGRAMS_KEYS without the risk of breaking consensus. let builtins = format!("{:?}", *BUILTIN_PROGRAMS_KEYS); assert_eq!( - format!("{}", hash::hash(builtins.as_bytes())), + format!("{}", hash(builtins.as_bytes())), "ACqmMkYbo9eqK6QrRSrB3HLyR6uHhLf31SCfGUAJjiWj" ); } @@ -982,4 +1018,9 @@ mod tests { Hash::from_str("7VWCF4quo2CcWQFNUayZiorxpiR5ix8YzLebrXKf3fMF").unwrap() ) } + + #[test] + fn test_inline_all_ids() { + assert_eq!(solana_sysvar::ALL_IDS.to_vec(), ALL_IDS.to_vec()); + } } diff --git a/sdk/program/src/message/mod.rs b/sdk/message/src/lib.rs similarity index 82% rename from sdk/program/src/message/mod.rs rename to sdk/message/src/lib.rs index cc7904117e9475..1233fc73564550 100644 --- a/sdk/program/src/message/mod.rs +++ b/sdk/message/src/lib.rs @@ -1,6 +1,8 @@ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![cfg_attr(feature = "frozen-abi", feature(min_specialization))] //! Sequences of [`Instruction`]s executed within a single transaction. //! -//! [`Instruction`]: crate::instruction::Instruction +//! [`Instruction`]: https://docs.rs/solana-instruction/latest/solana_instruction/struct.Instruction.html //! //! In Solana, programs execute instructions, and clients submit sequences //! of instructions to the network to be atomically executed as [`Transaction`]s. @@ -37,8 +39,13 @@ //! types continue to be exposed to Solana programs, for backwards compatibility //! reasons. +pub mod compiled_instruction; mod compiled_keys; pub mod legacy; +#[cfg(feature = "serde")] +use serde_derive::{Deserialize, Serialize}; +#[cfg(feature = "frozen-abi")] +use solana_frozen_abi_macro::AbiExample; #[cfg(not(target_os = "solana"))] #[path = ""] @@ -73,8 +80,8 @@ pub const MESSAGE_HEADER_LENGTH: usize = 3; /// `CompiledInstruction`s then reference by index the accounts they require in /// the single shared account list. /// -/// [`Instruction`]: crate::instruction::Instruction -/// [`CompiledInstruction`]: crate::instruction::CompiledInstruction +/// [`Instruction`]: https://docs.rs/solana-instruction/latest/solana_instruction/struct.Instruction.html +/// [`CompiledInstruction`]: crate::compiled_instruction::CompiledInstruction /// /// The shared account list is ordered by the permissions required of the accounts: /// @@ -92,8 +99,12 @@ pub const MESSAGE_HEADER_LENGTH: usize = 3; /// /// [PoH]: https://docs.solanalabs.com/consensus/synchronization #[cfg_attr(feature = "frozen-abi", derive(AbiExample))] -#[derive(Serialize, Deserialize, Default, Debug, PartialEq, Eq, Clone, Copy)] -#[serde(rename_all = "camelCase")] +#[cfg_attr( + feature = "serde", + derive(Deserialize, Serialize), + serde(rename_all = "camelCase") +)] +#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)] pub struct MessageHeader { /// The number of signatures required for this message to be considered /// valid. The signers of those signatures must match the first @@ -109,3 +120,12 @@ pub struct MessageHeader { /// read-only accounts. pub num_readonly_unsigned_accounts: u8, } + +/// The definition of address lookup table accounts. +/// +/// As used by the `crate::v0` message format. +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct AddressLookupTableAccount { + pub key: solana_pubkey::Pubkey, + pub addresses: Vec, +} diff --git a/sdk/program/src/message/sanitized.rs b/sdk/message/src/sanitized.rs similarity index 96% rename from sdk/program/src/message/sanitized.rs rename to sdk/message/src/sanitized.rs index d2bfdd5ddd8ba5..ac7f61b05010a6 100644 --- a/sdk/program/src/message/sanitized.rs +++ b/sdk/message/src/sanitized.rs @@ -5,25 +5,28 @@ pub use solana_transaction_error::SanitizeMessageError; use { crate::{ - ed25519_program, - hash::Hash, - instruction::CompiledInstruction, - message::{ - legacy, - v0::{self, LoadedAddresses}, - AccountKeys, AddressLoader, MessageHeader, SanitizedVersionedMessage, VersionedMessage, - }, - nonce::NONCED_TX_MARKER_IX_INDEX, - program_utils::limited_deserialize, - pubkey::Pubkey, - secp256k1_program, - solana_program::{system_instruction::SystemInstruction, system_program}, + compiled_instruction::CompiledInstruction, + legacy, + v0::{self, LoadedAddresses}, + AccountKeys, AddressLoader, MessageHeader, SanitizedVersionedMessage, VersionedMessage, }, + solana_hash::Hash, + solana_instruction::{BorrowedAccountMeta, BorrowedInstruction}, + solana_pubkey::Pubkey, solana_sanitize::Sanitize, - solana_sysvar::instructions::{BorrowedAccountMeta, BorrowedInstruction}, + solana_sdk_ids::{ed25519_program, secp256k1_program}, std::{borrow::Cow, collections::HashSet, convert::TryFrom}, }; +// inlined to avoid solana_nonce dep +#[cfg(feature = "bincode")] +const NONCED_TX_MARKER_IX_INDEX: u8 = 0; +#[cfg(test)] +static_assertions::const_assert_eq!( + NONCED_TX_MARKER_IX_INDEX, + solana_nonce::NONCED_TX_MARKER_IX_INDEX +); + #[derive(Debug, Clone, Eq, PartialEq)] pub struct LegacyMessage<'a> { /// Legacy message @@ -331,20 +334,23 @@ impl SanitizedMessage { }) } + #[cfg(feature = "bincode")] /// If the message uses a durable nonce, return the pubkey of the nonce account pub fn get_durable_nonce(&self) -> Option<&Pubkey> { self.instructions() .get(NONCED_TX_MARKER_IX_INDEX as usize) .filter( |ix| match self.account_keys().get(ix.program_id_index as usize) { - Some(program_id) => system_program::check_id(program_id), + Some(program_id) => solana_sdk_ids::system_program::check_id(program_id), _ => false, }, ) .filter(|ix| { matches!( - limited_deserialize(&ix.data, 4 /* serialized size of AdvanceNonceAccount */), - Ok(SystemInstruction::AdvanceNonceAccount) + solana_bincode::limited_deserialize( + &ix.data, 4 /* serialized size of AdvanceNonceAccount */ + ), + Ok(solana_system_interface::instruction::SystemInstruction::AdvanceNonceAccount) ) }) .and_then(|ix| { @@ -459,7 +465,7 @@ impl TransactionSignatureDetails { #[cfg(test)] mod tests { - use {super::*, crate::message::v0, std::collections::HashSet}; + use {super::*, crate::v0, std::collections::HashSet}; #[test] fn test_try_from_legacy_message() { diff --git a/sdk/program/src/message/versions/mod.rs b/sdk/message/src/versions/mod.rs similarity index 93% rename from sdk/program/src/message/versions/mod.rs rename to sdk/message/src/versions/mod.rs index 414af8de0b6e83..2eb56be2bf7bf9 100644 --- a/sdk/program/src/message/versions/mod.rs +++ b/sdk/message/src/versions/mod.rs @@ -1,19 +1,23 @@ +#[cfg(feature = "frozen-abi")] +use solana_frozen_abi_macro::{frozen_abi, AbiEnumVisitor, AbiExample}; use { crate::{ - hash::Hash, - instruction::CompiledInstruction, - message::{legacy::Message as LegacyMessage, v0::MessageAddressTableLookup, MessageHeader}, - pubkey::Pubkey, + compiled_instruction::CompiledInstruction, legacy::Message as LegacyMessage, + v0::MessageAddressTableLookup, MessageHeader, }, + solana_hash::Hash, + solana_pubkey::Pubkey, + solana_sanitize::{Sanitize, SanitizeError}, + std::collections::HashSet, +}; +#[cfg(feature = "serde")] +use { serde::{ de::{self, Deserializer, SeqAccess, Unexpected, Visitor}, ser::{SerializeTuple, Serializer}, }, serde_derive::{Deserialize, Serialize}, - solana_hash::HASH_BYTES, - solana_sanitize::{Sanitize, SanitizeError}, - solana_short_vec as short_vec, - std::{collections::HashSet, fmt}, + std::fmt, }; mod sanitized; @@ -34,7 +38,7 @@ pub const MESSAGE_VERSION_PREFIX: u8 = 0x80; /// format. #[cfg_attr( feature = "frozen-abi", - frozen_abi(digest = "EjjHMjAnRrd86DuTgysFXRicMiAQv3vTvzRzcMJCjYfC"), + frozen_abi(digest = "2RTtea34NPrb8p9mWHCWjFh76cwP3MbjSmeoj5CXEBwN"), derive(AbiEnumVisitor, AbiExample) )] #[derive(Debug, PartialEq, Eq, Clone)] @@ -146,23 +150,26 @@ impl VersionedMessage { } } + #[cfg(feature = "bincode")] pub fn serialize(&self) -> Vec { bincode::serialize(self).unwrap() } + #[cfg(all(feature = "bincode", feature = "blake3"))] /// Compute the blake3 hash of this transaction's message pub fn hash(&self) -> Hash { let message_bytes = self.serialize(); Self::hash_raw_message(&message_bytes) } + #[cfg(feature = "blake3")] /// Compute the blake3 hash of a raw transaction message pub fn hash_raw_message(message_bytes: &[u8]) -> Hash { use blake3::traits::digest::Digest; let mut hasher = blake3::Hasher::new(); hasher.update(b"solana-tx-message-v1"); hasher.update(message_bytes); - let hash_bytes: [u8; HASH_BYTES] = hasher.finalize().into(); + let hash_bytes: [u8; solana_hash::HASH_BYTES] = hasher.finalize().into(); hash_bytes.into() } } @@ -173,6 +180,7 @@ impl Default for VersionedMessage { } } +#[cfg(feature = "serde")] impl serde::Serialize for VersionedMessage { fn serialize(&self, serializer: S) -> Result where @@ -194,11 +202,13 @@ impl serde::Serialize for VersionedMessage { } } +#[cfg(feature = "serde")] enum MessagePrefix { Legacy(u8), Versioned(u8), } +#[cfg(feature = "serde")] impl<'de> serde::Deserialize<'de> for MessagePrefix { fn deserialize(deserializer: D) -> Result where @@ -235,6 +245,7 @@ impl<'de> serde::Deserialize<'de> for MessagePrefix { } } +#[cfg(feature = "serde")] impl<'de> serde::Deserialize<'de> for VersionedMessage { fn deserialize(deserializer: D) -> Result where @@ -264,10 +275,10 @@ impl<'de> serde::Deserialize<'de> for VersionedMessage { struct RemainingLegacyMessage { pub num_readonly_signed_accounts: u8, pub num_readonly_unsigned_accounts: u8, - #[serde(with = "short_vec")] + #[cfg_attr(feature = "serde", serde(with = "solana_short_vec"))] pub account_keys: Vec, pub recent_blockhash: Hash, - #[serde(with = "short_vec")] + #[cfg_attr(feature = "serde", serde(with = "solana_short_vec"))] pub instructions: Vec, } @@ -324,10 +335,8 @@ impl<'de> serde::Deserialize<'de> for VersionedMessage { mod tests { use { super::*, - crate::{ - instruction::{AccountMeta, Instruction}, - message::v0::MessageAddressTableLookup, - }, + crate::v0::MessageAddressTableLookup, + solana_instruction::{AccountMeta, Instruction}, }; #[test] diff --git a/sdk/program/src/message/versions/sanitized.rs b/sdk/message/src/versions/sanitized.rs similarity index 90% rename from sdk/program/src/message/versions/sanitized.rs rename to sdk/message/src/versions/sanitized.rs index b2d43da131dcd8..bd95964716c7e9 100644 --- a/sdk/program/src/message/versions/sanitized.rs +++ b/sdk/message/src/versions/sanitized.rs @@ -1,7 +1,6 @@ use { - super::VersionedMessage, - crate::{instruction::CompiledInstruction, pubkey::Pubkey}, - solana_sanitize::SanitizeError, + super::VersionedMessage, crate::compiled_instruction::CompiledInstruction, + solana_pubkey::Pubkey, solana_sanitize::SanitizeError, }; /// Wraps a sanitized `VersionedMessage` to provide a safe API diff --git a/sdk/program/src/message/versions/v0/loaded.rs b/sdk/message/src/versions/v0/loaded.rs similarity index 96% rename from sdk/program/src/message/versions/v0/loaded.rs rename to sdk/message/src/versions/v0/loaded.rs index 1825c5e748e3f4..94325007e01be8 100644 --- a/sdk/program/src/message/versions/v0/loaded.rs +++ b/sdk/message/src/versions/v0/loaded.rs @@ -1,9 +1,9 @@ +#[cfg(feature = "serde")] +use serde_derive::{Deserialize, Serialize}; use { - crate::{ - bpf_loader_upgradeable, - message::{v0, AccountKeys}, - pubkey::Pubkey, - }, + crate::{v0, AccountKeys}, + solana_pubkey::Pubkey, + solana_sdk_ids::bpf_loader_upgradeable, std::{borrow::Cow, collections::HashSet}, }; @@ -21,7 +21,8 @@ pub struct LoadedMessage<'a> { /// Collection of addresses loaded from on-chain lookup tables, split /// by readonly and writable. -#[derive(Clone, Default, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Default, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct LoadedAddresses { /// List of addresses for writable loaded accounts pub writable: Vec, @@ -187,8 +188,9 @@ impl<'a> LoadedMessage<'a> { mod tests { use { super::*, - crate::{instruction::CompiledInstruction, message::MessageHeader, system_program, sysvar}, + crate::{compiled_instruction::CompiledInstruction, MessageHeader}, itertools::Itertools, + solana_sdk_ids::{system_program, sysvar}, }; fn check_test_loaded_message() -> (LoadedMessage<'static>, [Pubkey; 6]) { @@ -270,8 +272,6 @@ mod tests { #[test] fn test_is_writable() { - solana_logger::setup(); - let reserved_account_keys = HashSet::from_iter([sysvar::clock::id(), system_program::id()]); let create_message_with_keys = |keys: Vec| { LoadedMessage::new( diff --git a/sdk/program/src/message/versions/v0/mod.rs b/sdk/message/src/versions/v0/mod.rs similarity index 94% rename from sdk/program/src/message/versions/v0/mod.rs rename to sdk/message/src/versions/v0/mod.rs index 9eaad5a9b39944..893a0664b8ff78 100644 --- a/sdk/program/src/message/versions/v0/mod.rs +++ b/sdk/message/src/versions/v0/mod.rs @@ -5,25 +5,26 @@ //! `v0` is a [future message format] that encodes more account keys into a //! transaction than the legacy format. //! -//! [`legacy`]: crate::message::legacy -//! [`v0`]: crate::message::v0 +//! [`legacy`]: crate::legacy +//! [`v0`]: crate::v0 //! [future message format]: https://docs.solanalabs.com/proposals/versioned-transactions pub use loaded::*; +#[cfg(feature = "serde")] +use serde_derive::{Deserialize, Serialize}; +#[cfg(feature = "frozen-abi")] +use solana_frozen_abi_macro::AbiExample; use { crate::{ - address_lookup_table::AddressLookupTableAccount, - bpf_loader_upgradeable, - hash::Hash, - instruction::{CompiledInstruction, Instruction}, - message::{ - compiled_keys::{CompileError, CompiledKeys}, - AccountKeys, MessageHeader, MESSAGE_VERSION_PREFIX, - }, - pubkey::Pubkey, + compiled_instruction::CompiledInstruction, + compiled_keys::{CompileError, CompiledKeys}, + AccountKeys, AddressLookupTableAccount, MessageHeader, }, + solana_hash::Hash, + solana_instruction::Instruction, + solana_pubkey::Pubkey, solana_sanitize::SanitizeError, - solana_short_vec as short_vec, + solana_sdk_ids::bpf_loader_upgradeable, std::collections::HashSet, }; @@ -32,16 +33,20 @@ mod loaded; /// Address table lookups describe an on-chain address lookup table to use /// for loading more readonly and writable accounts in a single tx. #[cfg_attr(feature = "frozen-abi", derive(AbiExample))] -#[derive(Serialize, Deserialize, Default, Debug, PartialEq, Eq, Clone)] -#[serde(rename_all = "camelCase")] +#[cfg_attr( + feature = "serde", + derive(Deserialize, Serialize), + serde(rename_all = "camelCase") +)] +#[derive(Default, Debug, PartialEq, Eq, Clone)] pub struct MessageAddressTableLookup { /// Address lookup table account key pub account_key: Pubkey, /// List of indexes used to load writable account addresses - #[serde(with = "short_vec")] + #[cfg_attr(feature = "serde", serde(with = "solana_short_vec"))] pub writable_indexes: Vec, /// List of indexes used to load readonly account addresses - #[serde(with = "short_vec")] + #[cfg_attr(feature = "serde", serde(with = "solana_short_vec"))] pub readonly_indexes: Vec, } @@ -50,12 +55,15 @@ pub struct MessageAddressTableLookup { /// This message format supports succinct account loading with /// on-chain address lookup tables. /// -/// See the [`message`] module documentation for further description. +/// See the crate documentation for further description. /// -/// [`message`]: crate::message #[cfg_attr(feature = "frozen-abi", derive(AbiExample))] -#[derive(Serialize, Deserialize, Default, Debug, PartialEq, Eq, Clone)] -#[serde(rename_all = "camelCase")] +#[cfg_attr( + feature = "serde", + derive(Deserialize, Serialize), + serde(rename_all = "camelCase") +)] +#[derive(Default, Debug, PartialEq, Eq, Clone)] pub struct Message { /// The message header, identifying signed and read-only `account_keys`. /// Header values only describe static `account_keys`, they do not describe @@ -63,7 +71,7 @@ pub struct Message { pub header: MessageHeader, /// List of accounts loaded by this transaction. - #[serde(with = "short_vec")] + #[cfg_attr(feature = "serde", serde(with = "solana_short_vec"))] pub account_keys: Vec, /// The blockhash of a recent block. @@ -82,12 +90,12 @@ pub struct Message { /// 1) message `account_keys` /// 2) ordered list of keys loaded from `writable` lookup table indexes /// 3) ordered list of keys loaded from `readable` lookup table indexes - #[serde(with = "short_vec")] + #[cfg_attr(feature = "serde", serde(with = "solana_short_vec"))] pub instructions: Vec, /// List of address table lookups used to load additional accounts /// for this transaction. - #[serde(with = "short_vec")] + #[cfg_attr(feature = "serde", serde(with = "solana_short_vec"))] pub address_table_lookups: Vec, } @@ -197,13 +205,12 @@ impl Message { /// # use std::borrow::Cow; /// # use solana_sdk::account::Account; /// use anyhow::Result; + /// use solana_instruction::{AccountMeta, Instruction}; + /// use solana_message::{AddressLookupTableAccount, VersionedMessage, v0}; + /// use solana_pubkey::Pubkey; /// use solana_rpc_client::rpc_client::RpcClient; /// use solana_program::address_lookup_table::{self, state::{AddressLookupTable, LookupTableMeta}}; /// use solana_sdk::{ - /// address_lookup_table::AddressLookupTableAccount, - /// instruction::{AccountMeta, Instruction}, - /// message::{VersionedMessage, v0}, - /// pubkey::Pubkey, /// signature::{Keypair, Signer}, /// transaction::VersionedTransaction, /// }; @@ -288,9 +295,10 @@ impl Message { }) } + #[cfg(feature = "bincode")] /// Serialize this message with a version #0 prefix using bincode encoding. pub fn serialize(&self) -> Vec { - bincode::serialize(&(MESSAGE_VERSION_PREFIX, self)).unwrap() + bincode::serialize(&(crate::MESSAGE_VERSION_PREFIX, self)).unwrap() } /// Returns true if the account at the specified index is called as a program by an instruction @@ -377,10 +385,7 @@ impl Message { #[cfg(test)] mod tests { - use { - super::*, - crate::{instruction::AccountMeta, message::VersionedMessage}, - }; + use {super::*, crate::VersionedMessage, solana_instruction::AccountMeta}; #[test] fn test_sanitize() { diff --git a/sdk/program/Cargo.toml b/sdk/program/Cargo.toml index dc5ffb8d4304c1..0478e559597754 100644 --- a/sdk/program/Cargo.toml +++ b/sdk/program/Cargo.toml @@ -56,6 +56,7 @@ solana-instruction = { workspace = true, default-features = false, features = [ ] } solana-keccak-hasher = { workspace = true, features = ["sha3"] } solana-last-restart-slot = { workspace = true, features = ["serde", "sysvar"] } +solana-message = { workspace = true, features = ["bincode", "blake3"] } solana-msg = { workspace = true } solana-native-token = { workspace = true } solana-nonce = { workspace = true, features = ["serde"] } @@ -153,6 +154,7 @@ frozen-abi = [ "solana-fee-calculator/frozen-abi", "solana-hash/frozen-abi", "solana-instruction/frozen-abi", + "solana-message/frozen-abi", "solana-pubkey/frozen-abi", "solana-rent/frozen-abi", "solana-short-vec/frozen-abi", diff --git a/sdk/program/src/address_lookup_table/mod.rs b/sdk/program/src/address_lookup_table/mod.rs index b1d29aac360a6b..036bd7cebefb31 100644 --- a/sdk/program/src/address_lookup_table/mod.rs +++ b/sdk/program/src/address_lookup_table/mod.rs @@ -9,12 +9,4 @@ pub mod state; pub mod program { pub use solana_sdk_ids::address_lookup_table::{check_id, id, ID}; } - -/// The definition of address lookup table accounts. -/// -/// As used by the `crate::message::v0` message format. -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct AddressLookupTableAccount { - pub key: crate::pubkey::Pubkey, - pub addresses: Vec, -} +pub use crate::message::AddressLookupTableAccount; diff --git a/sdk/program/src/instruction.rs b/sdk/program/src/instruction.rs index c380ecdbcde9c3..971bbc0e04e5fc 100644 --- a/sdk/program/src/instruction.rs +++ b/sdk/program/src/instruction.rs @@ -1,59 +1,10 @@ -#[cfg(feature = "frozen-abi")] -use solana_frozen_abi_macro::AbiExample; -pub use solana_instruction::{ - error::InstructionError, AccountMeta, Instruction, ProcessedSiblingInstruction, - TRANSACTION_LEVEL_STACK_HEIGHT, +pub use { + crate::message::compiled_instruction::CompiledInstruction, + solana_instruction::{ + error::InstructionError, AccountMeta, Instruction, ProcessedSiblingInstruction, + TRANSACTION_LEVEL_STACK_HEIGHT, + }, }; -use { - bincode::serialize, serde::Serialize, solana_pubkey::Pubkey, solana_sanitize::Sanitize, - solana_short_vec as short_vec, -}; - -/// A compact encoding of an instruction. -/// -/// A `CompiledInstruction` is a component of a multi-instruction [`Message`], -/// which is the core of a Solana transaction. It is created during the -/// construction of `Message`. Most users will not interact with it directly. -/// -/// [`Message`]: crate::message::Message -#[cfg_attr(feature = "frozen-abi", derive(AbiExample))] -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] -#[serde(rename_all = "camelCase")] -pub struct CompiledInstruction { - /// Index into the transaction keys array indicating the program account that executes this instruction. - pub program_id_index: u8, - /// Ordered indices into the transaction keys array indicating which accounts to pass to the program. - #[serde(with = "short_vec")] - pub accounts: Vec, - /// The program input data. - #[serde(with = "short_vec")] - pub data: Vec, -} - -impl Sanitize for CompiledInstruction {} - -impl CompiledInstruction { - pub fn new(program_ids_index: u8, data: &T, accounts: Vec) -> Self { - let data = serialize(data).unwrap(); - Self { - program_id_index: program_ids_index, - accounts, - data, - } - } - - pub fn new_from_raw_parts(program_id_index: u8, data: Vec, accounts: Vec) -> Self { - Self { - program_id_index, - accounts, - data, - } - } - - pub fn program_id<'a>(&self, program_ids: &'a [Pubkey]) -> &'a Pubkey { - &program_ids[self.program_id_index as usize] - } -} /// Returns a sibling instruction from the processed sibling instruction list. /// diff --git a/sdk/program/src/lib.rs b/sdk/program/src/lib.rs index 478e55db3eb213..e36ff37750604c 100644 --- a/sdk/program/src/lib.rs +++ b/sdk/program/src/lib.rs @@ -490,7 +490,6 @@ pub mod loader_upgradeable_instruction; pub mod loader_v4; pub mod loader_v4_instruction; pub mod log; -pub mod message; pub mod nonce; pub mod program; pub mod program_error; @@ -524,6 +523,8 @@ pub use solana_fee_calculator as fee_calculator; pub use solana_keccak_hasher as keccak; #[deprecated(since = "2.1.0", note = "Use `solana-last-restart-slot` crate instead")] pub use solana_last_restart_slot as last_restart_slot; +#[deprecated(since = "2.2.0", note = "Use `solana-message` crate instead")] +pub use solana_message as message; #[deprecated(since = "2.1.0", note = "Use `solana-program-memory` crate instead")] pub use solana_program_memory as program_memory; #[deprecated(since = "2.1.0", note = "Use `solana-program-pack` crate instead")] diff --git a/sdk/src/transaction/mod.rs b/sdk/src/transaction/mod.rs index b597b9d840be67..7e898bf2477e00 100644 --- a/sdk/src/transaction/mod.rs +++ b/sdk/src/transaction/mod.rs @@ -178,7 +178,7 @@ pub enum TransactionVerificationMode { #[cfg_attr( feature = "frozen-abi", derive(AbiExample), - frozen_abi(digest = "GESn6AYYNhpNfzJXdQ6kGjqz4VjpMw3ye9rghqaEqks7") + frozen_abi(digest = "76BDTr3Xm3VP7h4eSiw6pZHKc5yYewDufyia3Yedh6GG") )] #[derive(Debug, PartialEq, Default, Eq, Clone, Serialize, Deserialize)] pub struct Transaction { diff --git a/svm/examples/Cargo.lock b/svm/examples/Cargo.lock index e8596a5945304a..58cd78515ad41d 100644 --- a/svm/examples/Cargo.lock +++ b/svm/examples/Cargo.lock @@ -5767,6 +5767,27 @@ dependencies = [ "solana-sha256-hasher", ] +[[package]] +name = "solana-message" +version = "2.2.0" +dependencies = [ + "bincode", + "blake3", + "lazy_static", + "serde", + "serde_derive", + "solana-bincode", + "solana-hash", + "solana-instruction", + "solana-pubkey", + "solana-sanitize", + "solana-sdk-ids", + "solana-short-vec", + "solana-system-interface", + "solana-transaction-error", + "wasm-bindgen", +] + [[package]] name = "solana-metrics" version = "2.2.0" @@ -5976,6 +5997,7 @@ dependencies = [ "solana-instruction", "solana-keccak-hasher", "solana-last-restart-slot", + "solana-message", "solana-msg", "solana-native-token", "solana-nonce",