diff --git a/Cargo.lock b/Cargo.lock index 2272c19754ba95..3b30fda64444ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6496,18 +6496,32 @@ dependencies = [ "log", "quinn", "rayon", + "solana-account", + "solana-client-traits", + "solana-commitment-config", "solana-connection-cache", + "solana-epoch-info", + "solana-hash", + "solana-instruction", + "solana-keypair", "solana-measure", "solana-net-utils", + "solana-program", + "solana-pubkey", "solana-pubsub-client", "solana-quic-client", + "solana-quic-definitions", "solana-rpc-client", "solana-rpc-client-api", "solana-rpc-client-nonce-utils", - "solana-sdk", + "solana-signature", + "solana-signer", "solana-streamer", "solana-thin-client", + "solana-time-utils", "solana-tpu-client", + "solana-transaction", + "solana-transaction-error", "solana-udp-client", "thiserror 2.0.3", "tokio", @@ -6542,6 +6556,24 @@ dependencies = [ "tungstenite", ] +[[package]] +name = "solana-client-traits" +version = "2.2.0" +dependencies = [ + "solana-account", + "solana-commitment-config", + "solana-epoch-info", + "solana-hash", + "solana-instruction", + "solana-keypair", + "solana-program", + "solana-pubkey", + "solana-signature", + "solana-signer", + "solana-transaction", + "solana-transaction-error", +] + [[package]] name = "solana-clock" version = "2.2.0" @@ -8474,6 +8506,7 @@ dependencies = [ "siphasher", "solana-account", "solana-bn254", + "solana-client-traits", "solana-cluster-type", "solana-commitment-config", "solana-compute-budget-interface", @@ -8517,6 +8550,7 @@ dependencies = [ "solana-signer", "solana-sysvar", "solana-time-utils", + "solana-transaction", "solana-transaction-context", "solana-transaction-error", "static_assertions", @@ -9199,6 +9233,43 @@ dependencies = [ "tokio-util 0.7.12", ] +[[package]] +name = "solana-transaction" +version = "2.2.0" +dependencies = [ + "anyhow", + "bincode", + "borsh 1.5.3", + "serde", + "serde_derive", + "solana-bincode", + "solana-feature-set", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-hash", + "solana-instruction", + "solana-keypair", + "solana-logger", + "solana-nonce", + "solana-packet", + "solana-precompiles", + "solana-presigner", + "solana-program", + "solana-pubkey", + "solana-reserved-account-keys", + "solana-sanitize", + "solana-sdk", + "solana-sdk-ids", + "solana-sha256-hasher", + "solana-short-vec", + "solana-signature", + "solana-signer", + "solana-transaction", + "solana-transaction-error", + "static_assertions", + "wasm-bindgen", +] + [[package]] name = "solana-transaction-context" version = "2.2.0" diff --git a/Cargo.toml b/Cargo.toml index 55ce023631449f..7e64899c08180c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -105,6 +105,7 @@ members = [ "sdk/borsh", "sdk/cargo-build-sbf", "sdk/cargo-test-sbf", + "sdk/client-traits", "sdk/clock", "sdk/cluster-type", "sdk/commitment-config", @@ -171,6 +172,7 @@ members = [ "sdk/sysvar", "sdk/sysvar-id", "sdk/time-utils", + "sdk/transaction", "sdk/transaction-context", "sdk/transaction-error", "send-transaction-service", @@ -437,6 +439,7 @@ solana-cli = { path = "cli", version = "=2.2.0" } solana-cli-config = { path = "cli-config", version = "=2.2.0" } solana-cli-output = { path = "cli-output", version = "=2.2.0" } solana-client = { path = "client", version = "=2.2.0" } +solana-client-traits = { path = "sdk/client-traits", version = "=2.2.0" } solana-clock = { path = "sdk/clock", version = "=2.2.0" } solana-cluster-type = { path = "sdk/cluster-type", version = "=2.2.0" } solana-commitment-config = { path = "sdk/commitment-config", version = "=2.2.0" } @@ -564,6 +567,7 @@ solana-sysvar = { path = "sdk/sysvar", version = "=2.2.0" } solana-sysvar-id = { path = "sdk/sysvar-id", version = "=2.2.0" } solana-test-validator = { path = "test-validator", version = "=2.2.0" } solana-thin-client = { path = "thin-client", version = "=2.2.0" } +solana-transaction = { path = "sdk/transaction", version = "=2.2.0" } solana-transaction-error = { path = "sdk/transaction-error", version = "=2.2.0" } solana-tpu-client = { path = "tpu-client", version = "=2.2.0", default-features = false } solana-tpu-client-next = { path = "tpu-client-next", version = "=2.2.0" } diff --git a/client/Cargo.toml b/client/Cargo.toml index 36cab356c05104..cf2a724bf847eb 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -20,17 +20,31 @@ indicatif = { workspace = true } log = { workspace = true } quinn = { workspace = true } rayon = { workspace = true } +solana-account = { workspace = true } +solana-client-traits = { workspace = true } +solana-commitment-config = { workspace = true } solana-connection-cache = { workspace = true } +solana-epoch-info = { workspace = true } +solana-hash = { workspace = true } +solana-instruction = { workspace = true } +solana-keypair = { workspace = true } solana-measure = { workspace = true } +solana-program = { workspace = true, default-features = false } +solana-pubkey = { workspace = true } solana-pubsub-client = { workspace = true } solana-quic-client = { workspace = true } +solana-quic-definitions = { workspace = true } solana-rpc-client = { workspace = true, features = ["default"] } solana-rpc-client-api = { workspace = true } solana-rpc-client-nonce-utils = { workspace = true } -solana-sdk = { workspace = true, features = ["openssl-vendored"] } +solana-signature = { workspace = true } +solana-signer = { workspace = true } solana-streamer = { workspace = true } solana-thin-client = { workspace = true } +solana-time-utils = { workspace = true } solana-tpu-client = { workspace = true, features = ["default"] } +solana-transaction = { workspace = true } +solana-transaction-error = { workspace = true } solana-udp-client = { workspace = true } thiserror = { workspace = true } tokio = { workspace = true, features = ["full"] } diff --git a/client/src/connection_cache.rs b/client/src/connection_cache.rs index 28cc60a18075b3..10b3bbb9ecd609 100644 --- a/client/src/connection_cache.rs +++ b/client/src/connection_cache.rs @@ -8,12 +8,12 @@ use { NewConnectionConfig, }, }, + solana_keypair::Keypair, + solana_pubkey::Pubkey, solana_quic_client::{QuicConfig, QuicConnectionManager, QuicPool}, - solana_sdk::{ - pubkey::Pubkey, quic::NotifyKeyUpdate, signature::Keypair, - transport::Result as TransportResult, - }, + solana_quic_definitions::NotifyKeyUpdate, solana_streamer::streamer::StakedNodes, + solana_transaction_error::TransportResult, solana_udp_client::{UdpConfig, UdpConnectionManager, UdpPool}, std::{ net::{IpAddr, Ipv4Addr, SocketAddr}, @@ -201,8 +201,8 @@ mod tests { super::*, crate::connection_cache::ConnectionCache, crossbeam_channel::unbounded, + solana_keypair::Keypair, solana_net_utils::bind_to_localhost, - solana_sdk::signature::Keypair, solana_streamer::{ quic::{QuicServerParams, SpawnServerResult}, streamer::StakedNodes, diff --git a/client/src/nonblocking/tpu_client.rs b/client/src/nonblocking/tpu_client.rs index 5e71eae36bd6e4..e59a169416e4fa 100644 --- a/client/src/nonblocking/tpu_client.rs +++ b/client/src/nonblocking/tpu_client.rs @@ -5,15 +5,13 @@ use { ConnectionCache as BackendConnectionCache, ConnectionManager, ConnectionPool, NewConnectionConfig, }, + solana_program::message::Message, solana_quic_client::{QuicConfig, QuicConnectionManager, QuicPool}, solana_rpc_client::nonblocking::rpc_client::RpcClient, - solana_sdk::{ - message::Message, - signers::Signers, - transaction::{Transaction, TransactionError}, - transport::Result as TransportResult, - }, + solana_signer::signers::Signers, solana_tpu_client::nonblocking::tpu_client::{Result, TpuClient as BackendTpuClient}, + solana_transaction::Transaction, + solana_transaction_error::{TransactionError, TransportResult}, std::sync::Arc, }; diff --git a/client/src/send_and_confirm_transactions_in_parallel.rs b/client/src/send_and_confirm_transactions_in_parallel.rs index eb7153316702cf..adf3cee9c041d3 100644 --- a/client/src/send_and_confirm_transactions_in_parallel.rs +++ b/client/src/send_and_confirm_transactions_in_parallel.rs @@ -6,6 +6,8 @@ use { bincode::serialize, dashmap::DashMap, futures_util::future::join_all, + solana_hash::Hash, + solana_program::message::Message, solana_quic_client::{QuicConfig, QuicConnectionManager, QuicPool}, solana_rpc_client::spinner::{self, SendTransactionProgress}, solana_rpc_client_api::{ @@ -14,14 +16,11 @@ use { request::{RpcError, RpcResponseErrorData, MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS}, response::RpcSimulateTransactionResult, }, - solana_sdk::{ - hash::Hash, - message::Message, - signature::{Signature, SignerError}, - signers::Signers, - transaction::{Transaction, TransactionError}, - }, + solana_signature::Signature, + solana_signer::{signers::Signers, SignerError}, solana_tpu_client::tpu_client::{Result, TpuSenderError}, + solana_transaction::Transaction, + solana_transaction_error::TransactionError, std::{ sync::{ atomic::{AtomicU64, AtomicUsize, Ordering}, diff --git a/client/src/thin_client.rs b/client/src/thin_client.rs index 596c9a13a6dbd3..c769d5bf623c16 100644 --- a/client/src/thin_client.rs +++ b/client/src/thin_client.rs @@ -5,24 +5,23 @@ #[allow(deprecated)] use { crate::connection_cache::{dispatch, ConnectionCache}, + solana_account::Account, + solana_client_traits::{AsyncClient, Client, SyncClient}, + solana_commitment_config::CommitmentConfig, + solana_epoch_info::EpochInfo, + solana_hash::Hash, + solana_instruction::Instruction, + solana_keypair::Keypair, + solana_program::message::Message, + solana_pubkey::Pubkey, solana_quic_client::{QuicConfig, QuicConnectionManager, QuicPool}, solana_rpc_client::rpc_client::RpcClient, solana_rpc_client_api::config::RpcProgramAccountsConfig, - solana_sdk::{ - account::Account, - client::{AsyncClient, Client, SyncClient}, - commitment_config::CommitmentConfig, - epoch_info::EpochInfo, - hash::Hash, - instruction::Instruction, - message::Message, - pubkey::Pubkey, - signature::{Keypair, Signature}, - signers::Signers, - transaction::{self, Transaction, VersionedTransaction}, - transport::Result as TransportResult, - }, + solana_signature::Signature, + solana_signer::signers::Signers, solana_thin_client::thin_client::ThinClient as BackendThinClient, + solana_transaction::{versioned::VersionedTransaction, Transaction}, + solana_transaction_error::{TransactionResult, TransportResult}, solana_udp_client::{UdpConfig, UdpConnectionManager, UdpPool}, std::{net::SocketAddr, sync::Arc, time::Duration}, }; @@ -214,13 +213,13 @@ impl SyncClient for ThinClient { dispatch!(fn get_signature_status( &self, signature: &Signature - ) -> TransportResult>>); + ) -> TransportResult>>); dispatch!(fn get_signature_status_with_commitment( &self, signature: &Signature, commitment_config: CommitmentConfig - ) -> TransportResult>>); + ) -> TransportResult>>); dispatch!(fn get_slot(&self) -> TransportResult); diff --git a/client/src/tpu_client.rs b/client/src/tpu_client.rs index 893761637ce64d..cc24e659bc93f7 100644 --- a/client/src/tpu_client.rs +++ b/client/src/tpu_client.rs @@ -4,15 +4,13 @@ use { ConnectionCache as BackendConnectionCache, ConnectionManager, ConnectionPool, NewConnectionConfig, }, + solana_program::message::Message, solana_quic_client::{QuicConfig, QuicConnectionManager, QuicPool}, solana_rpc_client::rpc_client::RpcClient, - solana_sdk::{ - message::Message, - signers::Signers, - transaction::{Transaction, TransactionError}, - transport::Result as TransportResult, - }, + solana_signer::signers::Signers, solana_tpu_client::tpu_client::{Result, TpuClient as BackendTpuClient}, + solana_transaction::Transaction, + solana_transaction_error::{TransactionError, TransportResult}, solana_udp_client::{UdpConfig, UdpConnectionManager, UdpPool}, std::sync::Arc, }; diff --git a/client/src/transaction_executor.rs b/client/src/transaction_executor.rs index c85aa21f8bb555..23354818777788 100644 --- a/client/src/transaction_executor.rs +++ b/client/src/transaction_executor.rs @@ -1,12 +1,12 @@ #![allow(clippy::arithmetic_side_effects)] use { log::*, + solana_commitment_config::CommitmentConfig, solana_measure::measure::Measure, solana_rpc_client::rpc_client::RpcClient, - solana_sdk::{ - commitment_config::CommitmentConfig, signature::Signature, timing::timestamp, - transaction::Transaction, - }, + solana_signature::Signature, + solana_time_utils::timestamp, + solana_transaction::Transaction, std::{ net::SocketAddr, sync::{ diff --git a/gossip/src/protocol.rs b/gossip/src/protocol.rs index 6d5559dd80b02f..2685974df700a4 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 = "CFvnYRePV1TT51ArsF5Js69ntt1CJpWxJGq4kMJVnNjk") )] #[derive(Serialize, Deserialize, Debug)] #[allow(clippy::large_enum_variant)] diff --git a/programs/sbf/Cargo.lock b/programs/sbf/Cargo.lock index 56d19a39df423c..c61bc925ac4e16 100644 --- a/programs/sbf/Cargo.lock +++ b/programs/sbf/Cargo.lock @@ -5253,22 +5253,54 @@ dependencies = [ "log", "quinn", "rayon", + "solana-account", + "solana-client-traits", + "solana-commitment-config", "solana-connection-cache", + "solana-epoch-info", + "solana-hash", + "solana-instruction", + "solana-keypair", "solana-measure", + "solana-program", + "solana-pubkey", "solana-pubsub-client", "solana-quic-client", + "solana-quic-definitions", "solana-rpc-client", "solana-rpc-client-api", "solana-rpc-client-nonce-utils", - "solana-sdk", + "solana-signature", + "solana-signer", "solana-streamer", "solana-thin-client", + "solana-time-utils", "solana-tpu-client", + "solana-transaction", + "solana-transaction-error", "solana-udp-client", "thiserror 2.0.3", "tokio", ] +[[package]] +name = "solana-client-traits" +version = "2.2.0" +dependencies = [ + "solana-account", + "solana-commitment-config", + "solana-epoch-info", + "solana-hash", + "solana-instruction", + "solana-keypair", + "solana-program", + "solana-pubkey", + "solana-signature", + "solana-signer", + "solana-transaction", + "solana-transaction-error", +] + [[package]] name = "solana-clock" version = "2.2.0" @@ -7184,6 +7216,7 @@ dependencies = [ "siphasher", "solana-account", "solana-bn254", + "solana-client-traits", "solana-cluster-type", "solana-commitment-config", "solana-compute-budget-interface", @@ -7222,6 +7255,7 @@ dependencies = [ "solana-signature", "solana-signer", "solana-time-utils", + "solana-transaction", "solana-transaction-context", "solana-transaction-error", "thiserror 2.0.3", @@ -7697,6 +7731,31 @@ dependencies = [ "tokio", ] +[[package]] +name = "solana-transaction" +version = "2.2.0" +dependencies = [ + "bincode", + "serde", + "serde_derive", + "solana-bincode", + "solana-feature-set", + "solana-hash", + "solana-instruction", + "solana-keypair", + "solana-precompiles", + "solana-program", + "solana-pubkey", + "solana-reserved-account-keys", + "solana-sanitize", + "solana-sdk-ids", + "solana-short-vec", + "solana-signature", + "solana-signer", + "solana-transaction-error", + "wasm-bindgen", +] + [[package]] name = "solana-transaction-context" version = "2.2.0" diff --git a/rpc/src/rpc.rs b/rpc/src/rpc.rs index 29cce7b1a74680..7e07d0262728df 100644 --- a/rpc/src/rpc.rs +++ b/rpc/src/rpc.rs @@ -8533,7 +8533,7 @@ pub mod tests { decode_and_deserialize::(tx58, TransactionBinaryEncoding::Base58) .unwrap_err(), Error::invalid_params(format!( - "base58 encoded solana_sdk::transaction::Transaction too large: {tx58_len} bytes (max: encoded/raw {MAX_BASE58_SIZE}/{PACKET_DATA_SIZE})", + "base58 encoded solana_transaction::Transaction too large: {tx58_len} bytes (max: encoded/raw {MAX_BASE58_SIZE}/{PACKET_DATA_SIZE})", ) )); @@ -8543,7 +8543,7 @@ pub mod tests { decode_and_deserialize::(tx64, TransactionBinaryEncoding::Base64) .unwrap_err(), Error::invalid_params(format!( - "base64 encoded solana_sdk::transaction::Transaction too large: {tx64_len} bytes (max: encoded/raw {MAX_BASE64_SIZE}/{PACKET_DATA_SIZE})", + "base64 encoded solana_transaction::Transaction too large: {tx64_len} bytes (max: encoded/raw {MAX_BASE64_SIZE}/{PACKET_DATA_SIZE})", ) )); @@ -8554,7 +8554,7 @@ pub mod tests { decode_and_deserialize::(tx58, TransactionBinaryEncoding::Base58) .unwrap_err(), Error::invalid_params(format!( - "decoded solana_sdk::transaction::Transaction too large: {too_big} bytes (max: {PACKET_DATA_SIZE} bytes)" + "decoded solana_transaction::Transaction too large: {too_big} bytes (max: {PACKET_DATA_SIZE} bytes)" )) ); @@ -8563,7 +8563,7 @@ pub mod tests { decode_and_deserialize::(tx64, TransactionBinaryEncoding::Base64) .unwrap_err(), Error::invalid_params(format!( - "decoded solana_sdk::transaction::Transaction too large: {too_big} bytes (max: {PACKET_DATA_SIZE} bytes)" + "decoded solana_transaction::Transaction too large: {too_big} bytes (max: {PACKET_DATA_SIZE} bytes)" )) ); @@ -8573,7 +8573,7 @@ pub mod tests { decode_and_deserialize::(tx64.clone(), TransactionBinaryEncoding::Base64) .unwrap_err(), Error::invalid_params( - "failed to deserialize solana_sdk::transaction::Transaction: invalid value: \ + "failed to deserialize solana_transaction::Transaction: invalid value: \ continue signal on byte-three, expected a terminal signal on or before byte-three" .to_string() ) @@ -8591,7 +8591,7 @@ pub mod tests { decode_and_deserialize::(tx58.clone(), TransactionBinaryEncoding::Base58) .unwrap_err(), Error::invalid_params( - "failed to deserialize solana_sdk::transaction::Transaction: invalid value: \ + "failed to deserialize solana_transaction::Transaction: invalid value: \ continue signal on byte-three, expected a terminal signal on or before byte-three" .to_string() ) diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml index 63c3632d26e1e5..e311dd9b63a76c 100644 --- a/sdk/Cargo.toml +++ b/sdk/Cargo.toml @@ -35,6 +35,7 @@ full = [ "solana-commitment-config", "digest", "solana-pubkey/rand", + "dep:solana-client-traits", "dep:solana-cluster-type", "dep:solana-ed25519-program", "dep:solana-compute-budget-interface", @@ -47,6 +48,7 @@ full = [ "dep:solana-seed-derivable", "dep:solana-seed-phrase", "dep:solana-signer", + "dep:solana-transaction", "dep:solana-transaction-error", ] borsh = [ @@ -60,6 +62,7 @@ dev-context-only-utils = [ "solana-account/dev-context-only-utils", "solana-compute-budget-interface/dev-context-only-utils", "solana-rent-debits/dev-context-only-utils", + "solana-transaction/dev-context-only-utils", "solana-transaction-context/dev-context-only-utils", ] frozen-abi = [ @@ -74,7 +77,8 @@ frozen-abi = [ "solana-reward-info/frozen-abi", "solana-short-vec/frozen-abi", "solana-signature/frozen-abi", - "solana-transaction-error/frozen-abi", + "solana-transaction/frozen-abi", + "solana-transaction-error/frozen-abi" ] # Enables the "vendored" feature of openssl inside of secp256r1-program openssl-vendored = ["solana-precompiles/openssl-vendored"] @@ -112,6 +116,7 @@ sha3 = { workspace = true, optional = true } siphasher = { workspace = true } solana-account = { workspace = true, features = ["bincode"] } solana-bn254 = { workspace = true } +solana-client-traits = { workspace = true, optional = true } solana-cluster-type = { workspace = true, features = [ "serde", ], optional = true } @@ -173,6 +178,12 @@ solana-signature = { workspace = true, features = [ ], optional = true } solana-signer = { workspace = true, optional = true } solana-time-utils = { workspace = true } +solana-transaction = { workspace = true, features = [ + "bincode", + "precompiles", + "serde", + "verify" +], optional = true } solana-transaction-context = { workspace = true, features = ["bincode"] } solana-transaction-error = { workspace = true, features = [ "serde", diff --git a/sdk/client-traits/Cargo.toml b/sdk/client-traits/Cargo.toml new file mode 100644 index 00000000000000..c838b5870889ed --- /dev/null +++ b/sdk/client-traits/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "solana-client-traits" +description = "Traits for Solana clients" +documentation = "https://docs.rs/solana-client-traits" +version = { workspace = true } +authors = { workspace = true } +repository = { workspace = true } +homepage = { workspace = true } +license = { workspace = true } +edition = { workspace = true } + +[dependencies] +solana-account = { workspace = true } +solana-commitment-config = { workspace = true } +solana-epoch-info = { workspace = true } +solana-hash = { workspace = true } +solana-instruction = { workspace = true } +solana-keypair = { workspace = true } +solana-program = { workspace = true } +solana-pubkey = { workspace = true } +solana-signature = { workspace = true } +solana-signer = { workspace = true } +solana-transaction = { workspace = true } +solana-transaction-error = { workspace = true } + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] diff --git a/sdk/src/client.rs b/sdk/client-traits/src/lib.rs similarity index 89% rename from sdk/src/client.rs rename to sdk/client-traits/src/lib.rs index 6b9261a5d1f312..fc3260d3538fec 100644 --- a/sdk/src/client.rs +++ b/sdk/client-traits/src/lib.rs @@ -7,25 +7,19 @@ //! Asynchronous implementations are expected to create transactions, sign them, and send //! them but without waiting to see if the server accepted it. -#![cfg(feature = "full")] - use { - crate::{ - clock::Slot, - commitment_config::CommitmentConfig, - epoch_info::EpochInfo, - hash::Hash, - instruction::Instruction, - message::Message, - pubkey::Pubkey, - signature::{Keypair, Signature}, - signer::Signer, - signers::Signers, - system_instruction, - transaction::{self, Transaction, VersionedTransaction}, - transport::Result, - }, solana_account::Account, + solana_commitment_config::CommitmentConfig, + solana_epoch_info::EpochInfo, + solana_hash::Hash, + solana_instruction::Instruction, + solana_keypair::Keypair, + solana_program::{message::Message, system_instruction::transfer}, + solana_pubkey::Pubkey, + solana_signature::Signature, + solana_signer::{signers::Signers, Signer}, + solana_transaction::{versioned::VersionedTransaction, Transaction}, + solana_transaction_error::{TransactionResult, TransportResult as Result}, }; pub trait Client: SyncClient + AsyncClient { @@ -84,20 +78,17 @@ pub trait SyncClient { fn get_minimum_balance_for_rent_exemption(&self, data_len: usize) -> Result; /// Get signature status. - fn get_signature_status( - &self, - signature: &Signature, - ) -> Result>>; + fn get_signature_status(&self, signature: &Signature) -> Result>>; /// Get signature status. Uses explicit commitment configuration. fn get_signature_status_with_commitment( &self, signature: &Signature, commitment_config: CommitmentConfig, - ) -> Result>>; + ) -> Result>>; /// Get last known slot - fn get_slot(&self) -> Result; + fn get_slot(&self) -> Result; /// Get last known slot. Uses explicit commitment configuration. fn get_slot_with_commitment(&self, commitment_config: CommitmentConfig) -> Result; @@ -200,8 +191,7 @@ pub trait AsyncClient { pubkey: &Pubkey, recent_blockhash: Hash, ) -> Result { - let transfer_instruction = - system_instruction::transfer(&keypair.pubkey(), pubkey, lamports); + let transfer_instruction = transfer(&keypair.pubkey(), pubkey, lamports); self.async_send_instruction(keypair, transfer_instruction, recent_blockhash) } } diff --git a/sdk/instruction/Cargo.toml b/sdk/instruction/Cargo.toml index 5826fca227ff20..6c21e3959784ea 100644 --- a/sdk/instruction/Cargo.toml +++ b/sdk/instruction/Cargo.toml @@ -48,7 +48,7 @@ serde = [ std = [] [package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] +targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown"] all-features = true rustdoc-args = ["--cfg=docsrs"] diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index b51f88e7c6ef56..575fa74855dd73 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -61,7 +61,6 @@ pub use solana_program::{borsh, borsh0_10, borsh1}; #[cfg(feature = "full")] #[deprecated(since = "2.2.0", note = "Use `solana-signer` crate instead")] pub use solana_signer::signers; -pub mod client; pub mod entrypoint; pub mod entrypoint_deprecated; pub mod epoch_rewards_hasher; @@ -94,7 +93,6 @@ pub mod rpc_port; pub mod shred_version; pub mod signature; pub mod signer; -pub mod simple_vote_transaction_checker; pub mod system_transaction; pub mod transaction; pub mod transport; @@ -109,6 +107,9 @@ pub use solana_account as account; pub use solana_account::state_traits as account_utils; #[deprecated(since = "2.1.0", note = "Use `solana-bn254` crate instead")] pub use solana_bn254 as alt_bn128; +#[cfg(feature = "full")] +#[deprecated(since = "2.2.0", note = "Use `solana-client-traits` crate instead")] +pub use solana_client_traits as client; #[deprecated( since = "2.2.0", note = "Use `solana-compute-budget-interface` crate instead" @@ -203,6 +204,12 @@ pub use solana_serde_varint as serde_varint; pub use solana_short_vec as short_vec; #[deprecated(since = "2.2.0", note = "Use `solana-time-utils` crate instead")] pub use solana_time_utils as timing; +#[cfg(feature = "full")] +#[deprecated( + since = "2.2.0", + note = "Use `solana_transaction::simple_vote_transaction_checker` instead" +)] +pub use solana_transaction::simple_vote_transaction_checker; #[deprecated( since = "2.2.0", note = "Use `solana-transaction-context` crate instead" diff --git a/sdk/src/transaction.rs b/sdk/src/transaction.rs new file mode 100644 index 00000000000000..7e4864a3d3f748 --- /dev/null +++ b/sdk/src/transaction.rs @@ -0,0 +1,21 @@ +#![cfg(feature = "full")] +#[deprecated(since = "2.2.0", note = "Use solana_transaction_error crate instead")] +pub use solana_transaction_error::{ + AddressLoaderError, SanitizeMessageError, TransactionError, TransactionResult as Result, + TransportError, TransportResult, +}; +#[deprecated(since = "2.2.0", note = "Use solana_transaction crate instead")] +pub use { + solana_program::message::{AddressLoader, SimpleAddressLoader}, + solana_transaction::{ + sanitized::{ + MessageHash, SanitizedTransaction, TransactionAccountLocks, MAX_TX_ACCOUNT_LOCKS, + }, + uses_durable_nonce, + versioned::{ + sanitized::SanitizedVersionedTransaction, Legacy, TransactionVersion, + VersionedTransaction, + }, + Transaction, TransactionVerificationMode, + }, +}; diff --git a/sdk/src/wasm/transaction.rs b/sdk/src/wasm/transaction.rs index 208a76bfa2d415..5c5da471a7878a 100644 --- a/sdk/src/wasm/transaction.rs +++ b/sdk/src/wasm/transaction.rs @@ -1,54 +1,3 @@ -//! `Transaction` Javascript interface -#![cfg(target_arch = "wasm32")] -#![allow(non_snake_case)] -use { - crate::{hash::Hash, message::Message, signer::keypair::Keypair, transaction::Transaction}, - solana_program::{ - pubkey::Pubkey, - wasm::{display_to_jsvalue, instructions::Instructions}, - }, - wasm_bindgen::prelude::*, -}; - -#[wasm_bindgen] -impl Transaction { - /// Create a new `Transaction` - #[wasm_bindgen(constructor)] - pub fn constructor(instructions: Instructions, payer: Option) -> Transaction { - let instructions: Vec<_> = instructions.into(); - Transaction::new_with_payer(&instructions, payer.as_ref()) - } - - /// Return a message containing all data that should be signed. - #[wasm_bindgen(js_name = message)] - pub fn js_message(&self) -> Message { - self.message.clone() - } - - /// Return the serialized message data to sign. - pub fn messageData(&self) -> Box<[u8]> { - self.message_data().into() - } - - /// Verify the transaction - #[wasm_bindgen(js_name = verify)] - pub fn js_verify(&self) -> Result<(), JsValue> { - self.verify().map_err(display_to_jsvalue) - } - - pub fn partialSign(&mut self, keypair: &Keypair, recent_blockhash: &Hash) { - self.partial_sign(&[keypair], *recent_blockhash); - } - - pub fn isSigned(&self) -> bool { - self.is_signed() - } - - pub fn toBytes(&self) -> Box<[u8]> { - bincode::serialize(self).unwrap().into() - } - - pub fn fromBytes(bytes: &[u8]) -> Result { - bincode::deserialize(bytes).map_err(display_to_jsvalue) - } -} +//! This module is empty but has not yet been removed because that would +//! technically be a breaking change. There was never anything to import +//! from here. diff --git a/sdk/transaction/Cargo.toml b/sdk/transaction/Cargo.toml new file mode 100644 index 00000000000000..1a013ad1ede569 --- /dev/null +++ b/sdk/transaction/Cargo.toml @@ -0,0 +1,75 @@ +[package] +name = "solana-transaction" +description = "Solana transaction-types" +documentation = "https://docs.rs/solana-transaction" +version = { workspace = true } +authors = { workspace = true } +repository = { workspace = true } +homepage = { workspace = true } +license = { workspace = true } +edition = { workspace = true } + +[dependencies] +bincode = { workspace = true, optional = true } +serde = { workspace = true, optional = true } +serde_derive = { workspace = true, optional = true } +solana-bincode = { workspace = true, optional = true } +solana-feature-set = { 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 } +solana-logger = { workspace = true, optional = true } +solana-precompiles = { workspace = true, optional = true } +solana-program = { workspace = true } +solana-pubkey = { workspace = true } +solana-reserved-account-keys = { workspace = true } +solana-sanitize = { workspace = true } +solana-sdk-ids = { workspace = true } +solana-short-vec = { workspace = true, optional = true } +solana-signature = { workspace = true } +solana-signer = { workspace = true } +solana-transaction-error = { workspace = true } + +[target.'cfg(target_arch = "wasm32")'.dependencies] +solana-keypair = { workspace = true } +wasm-bindgen = { workspace = true } + +[dev-dependencies] +anyhow = { workspace = true } +bincode = { workspace = true } +borsh = { workspace = true } +solana-hash = { workspace = true } +solana-instruction = { workspace = true, features = ["borsh"] } +solana-keypair = { workspace = true } +solana-nonce = { workspace = true } +solana-packet = { workspace = true } +solana-presigner = { workspace = true } +solana-program = { workspace = true, default-features = false } +solana-pubkey = { workspace = true, features = ["rand"] } +solana-sdk = { path = ".." } +solana-sha256-hasher = { workspace = true } +solana-transaction = { path = ".", features = ["dev-context-only-utils"] } +static_assertions = { workspace = true } + +[features] +bincode = ["dep:bincode", "dep:solana-bincode", "serde"] +dev-context-only-utils = ["bincode", "precompiles", "serde", "verify"] +frozen-abi = [ + "dep:solana-frozen-abi", + "dep:solana-frozen-abi-macro", + "dep:solana-logger", +] +precompiles = ["dep:solana-feature-set", "dep:solana-precompiles"] +serde = [ + "dep:serde", + "dep:serde_derive", + "dep:solana-short-vec", + "solana-signature/serde", +] +verify = ["solana-signature/verify"] + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] +all-features = true +rustdoc-args = ["--cfg=docsrs"] diff --git a/sdk/src/transaction/mod.rs b/sdk/transaction/src/lib.rs similarity index 91% rename from sdk/src/transaction/mod.rs rename to sdk/transaction/src/lib.rs index 6fc088b964a360..12c42d8b951aee 100644 --- a/sdk/src/transaction/mod.rs +++ b/sdk/transaction/src/lib.rs @@ -1,3 +1,5 @@ +#![cfg_attr(feature = "frozen-abi", feature(min_specialization))] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] //! Atomically-committed sequences of instructions. //! //! While [`Instruction`]s are the basic unit of computation in Solana, they are @@ -20,8 +22,8 @@ //! signers including remote wallets, such as Ledger devices, as represented by //! the [`RemoteKeypair`] type in the [`solana-remote-wallet`] crate. //! -//! [`Signer`]: crate::signer::Signer -//! [`Keypair`]: crate::signer::keypair::Keypair +//! [`Signer`]: https://docs.rs/solana-signer/latest/solana_signer/trait.Signer.html +//! [`Keypair`]: https://docs.rs/solana-keypair/latest/solana_keypair/struct.Keypair.html //! [`solana-remote-wallet`]: https://docs.rs/solana-remote-wallet/latest/ //! [`RemoteKeypair`]: https://docs.rs/solana-remote-wallet/latest/solana_remote_wallet/remote_keypair/struct.RemoteKeypair.html //! @@ -56,14 +58,13 @@ //! # use solana_sdk::example_mocks::solana_rpc_client; //! use anyhow::Result; //! use borsh::{BorshSerialize, BorshDeserialize}; +//! use solana_instruction::Instruction; +//! use solana_keypair::Keypair; +//! use solana_program::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, -//! }; +//! use solana_signer::Signer; +//! use solana_transaction::Transaction; //! //! // A custom program instruction. This would typically be defined in //! // another crate so it can be shared between the on-chain program and @@ -109,43 +110,34 @@ //! # Ok::<(), anyhow::Error>(()) //! ``` -#![cfg(feature = "full")] - #[cfg(target_arch = "wasm32")] -use crate::wasm_bindgen; +use wasm_bindgen::prelude::wasm_bindgen; +#[cfg(feature = "serde")] +use { + serde_derive::{Deserialize, Serialize}, + solana_short_vec as short_vec, +}; +#[cfg(feature = "bincode")] use { - crate::{ - hash::Hash, - instruction::{CompiledInstruction, Instruction}, - message::Message, - nonce::NONCED_TX_MARKER_IX_INDEX, - precompiles::verify_if_precompile, - program_utils::limited_deserialize, - pubkey::Pubkey, - signature::{Signature, SignerError}, - signers::Signers, - }, - serde::Serialize, - solana_feature_set as feature_set, + solana_bincode::limited_deserialize, solana_program::{system_instruction::SystemInstruction, system_program}, +}; +use { + solana_hash::Hash, + solana_instruction::Instruction, + solana_program::{instruction::CompiledInstruction, message::Message}, + solana_pubkey::Pubkey, solana_sanitize::{Sanitize, SanitizeError}, - solana_short_vec as short_vec, + solana_signature::Signature, + solana_signer::{signers::Signers, SignerError}, + solana_transaction_error::{TransactionError, TransactionResult as Result}, std::result, }; -mod sanitized; -mod versioned; - -#[deprecated( - since = "2.2.0", - note = "Use `solana_transaction_error::TransactionResult` instead" -)] -pub use solana_transaction_error::TransactionResult as Result; -#[deprecated(since = "2.1.0", note = "Use solana_transaction_error crate instead")] -pub use solana_transaction_error::{ - AddressLoaderError, SanitizeMessageError, TransactionError, TransportError, TransportResult, -}; -pub use {sanitized::*, versioned::*}; +pub mod sanitized; +pub mod simple_vote_transaction_checker; +pub mod versioned; +mod wasm; #[derive(PartialEq, Eq, Clone, Copy, Debug)] pub enum TransactionVerificationMode { @@ -154,13 +146,27 @@ pub enum TransactionVerificationMode { FullVerification, } +// inlined to avoid solana-nonce dep +#[cfg(test)] +static_assertions::const_assert_eq!( + NONCED_TX_MARKER_IX_INDEX, + solana_nonce::NONCED_TX_MARKER_IX_INDEX +); +#[cfg(feature = "bincode")] +const NONCED_TX_MARKER_IX_INDEX: u8 = 0; +// inlined to avoid solana-packet dep +#[cfg(test)] +static_assertions::const_assert_eq!(PACKET_DATA_SIZE, solana_packet::PACKET_DATA_SIZE); +#[cfg(feature = "bincode")] +const PACKET_DATA_SIZE: usize = 1280 - 40 - 8; + /// An atomically-committed sequence of instructions. /// /// While [`Instruction`]s are the basic unit of computation in Solana, /// they are submitted by clients in [`Transaction`]s containing one or /// more instructions, and signed by one or more [`Signer`]s. /// -/// [`Signer`]: crate::signer::Signer +/// [`Signer`]: https://docs.rs/solana-signer/latest/solana_signer/trait.Signer.html /// /// See the [module documentation] for more details about transactions. /// @@ -177,21 +183,22 @@ pub enum TransactionVerificationMode { #[cfg(not(target_arch = "wasm32"))] #[cfg_attr( feature = "frozen-abi", - derive(AbiExample), - frozen_abi(digest = "GESn6AYYNhpNfzJXdQ6kGjqz4VjpMw3ye9rghqaEqks7") + derive(solana_frozen_abi_macro::AbiExample), + solana_frozen_abi_macro::frozen_abi(digest = "GESn6AYYNhpNfzJXdQ6kGjqz4VjpMw3ye9rghqaEqks7") )] -#[derive(Debug, PartialEq, Default, Eq, Clone, Serialize, Deserialize)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +#[derive(Debug, PartialEq, Default, Eq, Clone)] pub struct Transaction { /// A set of signatures of a serialized [`Message`], signed by the first /// keys of the `Message`'s [`account_keys`], where the number of signatures /// is equal to [`num_required_signatures`] of the `Message`'s /// [`MessageHeader`]. /// - /// [`account_keys`]: Message::account_keys - /// [`MessageHeader`]: crate::message::MessageHeader - /// [`num_required_signatures`]: crate::message::MessageHeader::num_required_signatures + /// [`account_keys`]: https://docs.rs/solana-program/latest/solana_program/message/legacy/struct.Message.html#structfield.account_keys + /// [`MessageHeader`]: https://docs.rs/solana-program/latest/solana_program/message/struct.MessageHeader.html + /// [`num_required_signatures`]: https://docs.rs/solana-program/latest/solana_program/message/struct.MessageHeader.html#structfield.num_required_signatures // NOTE: Serialization-related changes must be paired with the direct read at sigverify. - #[serde(with = "short_vec")] + #[cfg_attr(feature = "serde", serde(with = "short_vec"))] pub signatures: Vec, /// The message to sign. @@ -208,10 +215,11 @@ pub struct Transaction { derive(AbiExample), frozen_abi(digest = "H7xQFcd1MtMv9QKZWGatBAXwhg28tpeX59P3s8ZZLAY4") )] -#[derive(Debug, PartialEq, Default, Eq, Clone, Serialize, Deserialize)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +#[derive(Debug, PartialEq, Default, Eq, Clone)] pub struct Transaction { #[wasm_bindgen(skip)] - #[serde(with = "short_vec")] + #[cfg_attr(feature = "serde", serde(with = "short_vec"))] pub signatures: Vec, #[wasm_bindgen(skip)] @@ -244,14 +252,13 @@ impl Transaction { /// # use solana_sdk::example_mocks::solana_rpc_client; /// use anyhow::Result; /// use borsh::{BorshSerialize, BorshDeserialize}; + /// use solana_instruction::Instruction; + /// use solana_keypair::Keypair; + /// use solana_program::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, - /// }; + /// use solana_signer::Signer; + /// use solana_transaction::Transaction; /// /// // A custom program instruction. This would typically be defined in /// // another crate so it can be shared between the on-chain program and @@ -323,14 +330,13 @@ impl Transaction { /// # use solana_sdk::example_mocks::solana_rpc_client; /// use anyhow::Result; /// use borsh::{BorshSerialize, BorshDeserialize}; + /// use solana_instruction::Instruction; + /// use solana_keypair::Keypair; + /// use solana_program::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, - /// }; + /// use solana_signer::Signer; + /// use solana_transaction::Transaction; /// /// // A custom program instruction. This would typically be defined in /// // another crate so it can be shared between the on-chain program and @@ -402,14 +408,13 @@ impl Transaction { /// # use solana_sdk::example_mocks::solana_rpc_client; /// use anyhow::Result; /// use borsh::{BorshSerialize, BorshDeserialize}; + /// use solana_instruction::Instruction; + /// use solana_keypair::Keypair; + /// use solana_program::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, - /// }; + /// use solana_signer::Signer; + /// use solana_transaction::Transaction; /// /// // A custom program instruction. This would typically be defined in /// // another crate so it can be shared between the on-chain program and @@ -478,14 +483,13 @@ impl Transaction { /// # use solana_sdk::example_mocks::solana_rpc_client; /// use anyhow::Result; /// use borsh::{BorshSerialize, BorshDeserialize}; + /// use solana_instruction::Instruction; + /// use solana_keypair::Keypair; + /// use solana_program::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, - /// }; + /// use solana_signer::Signer; + /// use solana_transaction::Transaction; /// /// // A custom program instruction. This would typically be defined in /// // another crate so it can be shared between the on-chain program and @@ -686,14 +690,13 @@ impl Transaction { /// # use solana_sdk::example_mocks::solana_rpc_client; /// use anyhow::Result; /// use borsh::{BorshSerialize, BorshDeserialize}; + /// use solana_instruction::Instruction; + /// use solana_keypair::Keypair; + /// use solana_program::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, - /// }; + /// use solana_signer::Signer; + /// use solana_transaction::Transaction; /// /// // A custom program instruction. This would typically be defined in /// // another crate so it can be shared between the on-chain program and @@ -824,14 +827,13 @@ impl Transaction { /// # use solana_sdk::example_mocks::solana_rpc_client; /// use anyhow::Result; /// use borsh::{BorshSerialize, BorshDeserialize}; + /// use solana_instruction::Instruction; + /// use solana_keypair::Keypair; + /// use solana_program::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, - /// }; + /// use solana_signer::Signer; + /// use solana_transaction::Transaction; /// /// // A custom program instruction. This would typically be defined in /// // another crate so it can be shared between the on-chain program and @@ -928,11 +930,11 @@ impl Transaction { /// See the documentation for the [`solana-remote-wallet`] crate for details /// on the operation of [`RemoteKeypair`] signers. /// - /// [`num_required_signatures`]: crate::message::MessageHeader::num_required_signatures + /// [`num_required_signatures`]: https://docs.rs/solana-program/latest/solana_program/message/struct.MessageHeader.html#structfield.num_required_signatures /// [`account_keys`]: Message::account_keys - /// [`Presigner`]: crate::signer::presigner::Presigner - /// [`PresignerError`]: crate::signer::presigner::PresignerError - /// [`PresignerError::VerificationFailure`]: crate::signer::presigner::PresignerError::VerificationFailure + /// [`Presigner`]: https://docs.rs/solana-presigner/latest/solana_presigner/struct.Presigner.html + /// [`PresignerError`]: https://docs.rs/solana-signer/latest/solana_signer/enum.PresignerError.html + /// [`PresignerError::VerificationFailure`]: https://docs.rs/solana-signer/latest/solana_signer/enum.PresignerError.html#variant.WrongSize /// [`solana-remote-wallet`]: https://docs.rs/solana-remote-wallet/latest/ /// [`RemoteKeypair`]: https://docs.rs/solana-remote-wallet/latest/solana_remote_wallet/remote_keypair/struct.RemoteKeypair.html pub fn try_partial_sign( @@ -987,6 +989,7 @@ impl Transaction { Signature::default() } + #[cfg(feature = "verify")] /// Verifies that all signers have signed the message. /// /// # Errors @@ -1005,6 +1008,7 @@ impl Transaction { } } + #[cfg(feature = "verify")] /// Verify the transaction and hash its message. /// /// # Errors @@ -1023,6 +1027,7 @@ impl Transaction { } } + #[cfg(feature = "verify")] /// Verifies that all signers have signed the message. /// /// Returns a vector with the length of required signatures, where each @@ -1031,6 +1036,7 @@ impl Transaction { self._verify_with_results(&self.message_data()) } + #[cfg(feature = "verify")] pub(crate) fn _verify_with_results(&self, message_bytes: &[u8]) -> Vec { self.signatures .iter() @@ -1039,8 +1045,9 @@ impl Transaction { .collect() } + #[cfg(feature = "precompiles")] /// Verify the precompiled programs in this transaction. - pub fn verify_precompiles(&self, feature_set: &feature_set::FeatureSet) -> Result<()> { + pub fn verify_precompiles(&self, feature_set: &solana_feature_set::FeatureSet) -> Result<()> { for instruction in &self.message().instructions { // The Transaction may not be sanitized at this point if instruction.program_id_index as usize >= self.message().account_keys.len() { @@ -1048,7 +1055,7 @@ impl Transaction { } let program_id = &self.message().account_keys[instruction.program_id_index as usize]; - verify_if_precompile( + solana_precompiles::verify_if_precompile( program_id, instruction, &self.message().instructions, @@ -1075,6 +1082,7 @@ impl Transaction { .collect()) } + #[cfg(feature = "verify")] /// Replace all the signatures and pubkeys. pub fn replace_signatures(&mut self, signers: &[(Pubkey, Signature)]) -> Result<()> { let num_required_signatures = self.message.header.num_required_signatures as usize; @@ -1111,6 +1119,7 @@ impl Transaction { } } +#[cfg(feature = "bincode")] /// Returns true if transaction begins with an advance nonce instruction. pub fn uses_durable_nonce(tx: &Transaction) -> Option<&CompiledInstruction> { let message = tx.message(); @@ -1125,7 +1134,7 @@ pub fn uses_durable_nonce(tx: &Transaction) -> Option<&CompiledInstruction> { ) // Is a nonce advance instruction && matches!( - limited_deserialize(&instruction.data), + limited_deserialize(&instruction.data, PACKET_DATA_SIZE as u64), Ok(SystemInstruction::AdvanceNonceAccount) ) }) @@ -1137,13 +1146,13 @@ mod tests { use { super::*, - crate::{ - hash::hash, - instruction::AccountMeta, - signature::{Keypair, Presigner, Signer}, - system_instruction, - }, bincode::{deserialize, serialize, serialized_size}, + solana_instruction::AccountMeta, + solana_keypair::Keypair, + solana_presigner::Presigner, + solana_program::system_instruction, + solana_sha256_hasher::hash, + solana_signer::Signer, std::mem::size_of, }; @@ -1156,10 +1165,10 @@ mod tests { #[test] fn test_refs() { let key = Keypair::new(); - let key1 = solana_sdk::pubkey::new_rand(); - let key2 = solana_sdk::pubkey::new_rand(); - let prog1 = solana_sdk::pubkey::new_rand(); - let prog2 = solana_sdk::pubkey::new_rand(); + let key1 = solana_pubkey::new_rand(); + let key2 = solana_pubkey::new_rand(); + let prog1 = solana_pubkey::new_rand(); + let prog2 = solana_pubkey::new_rand(); let instructions = vec![ CompiledInstruction::new(3, &(), vec![0, 1]), CompiledInstruction::new(4, &(), vec![0, 2]), @@ -1227,7 +1236,7 @@ mod tests { fn test_sanitize_txs() { let key = Keypair::new(); let id0 = Pubkey::default(); - let program_id = solana_sdk::pubkey::new_rand(); + let program_id = solana_pubkey::new_rand(); let ix = Instruction::new_with_bincode( program_id, &0, @@ -1326,7 +1335,7 @@ mod tests { fn test_transaction_minimum_serialized_size() { let alice_keypair = Keypair::new(); let alice_pubkey = alice_keypair.pubkey(); - let bob_pubkey = solana_sdk::pubkey::new_rand(); + let bob_pubkey = solana_pubkey::new_rand(); let ix = system_instruction::transfer(&alice_pubkey, &bob_pubkey, 42); let expected_data_size = size_of::() + size_of::(); @@ -1404,7 +1413,7 @@ mod tests { #[should_panic] fn test_partial_sign_mismatched_key() { let keypair = Keypair::new(); - let fee_payer = solana_sdk::pubkey::new_rand(); + let fee_payer = solana_pubkey::new_rand(); let ix = Instruction::new_with_bincode( Pubkey::default(), &0, @@ -1487,7 +1496,7 @@ mod tests { let program_id = Pubkey::default(); let keypair0 = Keypair::new(); let id0 = keypair0.pubkey(); - let id1 = solana_sdk::pubkey::new_rand(); + let id1 = solana_pubkey::new_rand(); let ix = Instruction::new_with_bincode( program_id, &0, @@ -1538,7 +1547,7 @@ mod tests { assert_eq!(tx.signatures[1], presigner_sig); // Wrong key should error, not panic - let another_pubkey = solana_sdk::pubkey::new_rand(); + let another_pubkey = solana_pubkey::new_rand(); let ix = Instruction::new_with_bincode( program_id, &0, diff --git a/sdk/src/transaction/sanitized.rs b/sdk/transaction/src/sanitized.rs similarity index 93% rename from sdk/src/transaction/sanitized.rs rename to sdk/transaction/src/sanitized.rs index af21811d2bbd2b..d60c3e4659524c 100644 --- a/sdk/src/transaction/sanitized.rs +++ b/sdk/transaction/src/sanitized.rs @@ -1,26 +1,21 @@ -#![cfg(feature = "full")] - -pub use crate::message::{AddressLoader, SimpleAddressLoader}; use { - super::SanitizedVersionedTransaction, crate::{ - hash::Hash, - message::{ - legacy, - v0::{self, LoadedAddresses}, - LegacyMessage, SanitizedMessage, VersionedMessage, - }, - precompiles::verify_if_precompile, - pubkey::Pubkey, - reserved_account_keys::ReservedAccountKeys, - signature::Signature, simple_vote_transaction_checker::is_simple_vote_transaction, - transaction::{Result, Transaction, VersionedTransaction}, + versioned::{sanitized::SanitizedVersionedTransaction, VersionedTransaction}, + Transaction, }, - solana_feature_set as feature_set, - solana_program::{instruction::InstructionError, message::SanitizedVersionedMessage}, + solana_hash::Hash, + solana_program::message::{ + legacy, + v0::{self, LoadedAddresses}, + AddressLoader, LegacyMessage, SanitizedMessage, SanitizedVersionedMessage, + VersionedMessage, + }, + solana_pubkey::Pubkey, + solana_reserved_account_keys::ReservedAccountKeys, solana_sanitize::Sanitize, - solana_transaction_error::TransactionError, + solana_signature::Signature, + solana_transaction_error::{TransactionError, TransactionResult as Result}, std::collections::HashSet, }; @@ -259,6 +254,7 @@ impl SanitizedTransaction { self.message.get_durable_nonce() } + #[cfg(feature = "verify")] /// Return the serialized message data to sign. fn message_data(&self) -> Vec { match &self.message { @@ -267,6 +263,7 @@ impl SanitizedTransaction { } } + #[cfg(feature = "verify")] /// Verify the transaction signatures pub fn verify(&self) -> Result<()> { let message_bytes = self.message_data(); @@ -283,12 +280,13 @@ impl SanitizedTransaction { } } + #[cfg(feature = "precompiles")] /// Verify the precompiled programs in this transaction - pub fn verify_precompiles(&self, feature_set: &feature_set::FeatureSet) -> Result<()> { + pub fn verify_precompiles(&self, feature_set: &solana_feature_set::FeatureSet) -> Result<()> { for (index, (program_id, instruction)) in self.message.program_instructions_iter().enumerate() { - verify_if_precompile( + solana_precompiles::verify_if_precompile( program_id, instruction, self.message().instructions(), @@ -297,7 +295,7 @@ impl SanitizedTransaction { .map_err(|err| { TransactionError::InstructionError( index as u8, - InstructionError::Custom(err as u32), + solana_instruction::error::InstructionError::Custom(err as u32), ) })?; } @@ -338,14 +336,13 @@ impl SanitizedTransaction { mod tests { use { super::*, - crate::{ - reserved_account_keys::ReservedAccountKeys, - signer::{keypair::Keypair, Signer}, - }, + solana_keypair::Keypair, solana_program::{ - message::MessageHeader, + message::{MessageHeader, SimpleAddressLoader}, vote::{self, state::Vote}, }, + solana_reserved_account_keys::ReservedAccountKeys, + solana_signer::Signer, }; #[test] diff --git a/sdk/src/simple_vote_transaction_checker.rs b/sdk/transaction/src/simple_vote_transaction_checker.rs similarity index 84% rename from sdk/src/simple_vote_transaction_checker.rs rename to sdk/transaction/src/simple_vote_transaction_checker.rs index cc8ccc02f2484f..7029911552f9ce 100644 --- a/sdk/src/simple_vote_transaction_checker.rs +++ b/sdk/transaction/src/simple_vote_transaction_checker.rs @@ -1,9 +1,6 @@ -#![cfg(feature = "full")] - use { - crate::{message::VersionedMessage, transaction::SanitizedVersionedTransaction}, - solana_pubkey::Pubkey, - solana_signature::Signature, + crate::versioned::sanitized::SanitizedVersionedTransaction, + solana_program::message::VersionedMessage, solana_pubkey::Pubkey, solana_signature::Signature, }; /// Simple vote transaction meets these conditions: @@ -46,6 +43,6 @@ pub fn is_simple_vote_transaction_impl<'a>( && instruction_programs .next() .xor(instruction_programs.next()) - .map(|program_id| program_id == &solana_sdk::vote::program::ID) + .map(|program_id| program_id == &solana_sdk_ids::vote::ID) .unwrap_or(false) } diff --git a/sdk/src/transaction/versioned/mod.rs b/sdk/transaction/src/versioned/mod.rs similarity index 88% rename from sdk/src/transaction/versioned/mod.rs rename to sdk/transaction/src/versioned/mod.rs index c9a30ab5680486..ce19d45ec36ce1 100644 --- a/sdk/src/transaction/versioned/mod.rs +++ b/sdk/transaction/src/versioned/mod.rs @@ -1,42 +1,43 @@ //! Defines a transaction which supports multiple versions of messages. -#![cfg(feature = "full")] - use { - crate::{ - hash::Hash, - message::VersionedMessage, - signature::Signature, - signer::SignerError, - signers::Signers, - transaction::{Result, Transaction}, - }, - serde::Serialize, + crate::Transaction, + solana_program::message::VersionedMessage, solana_sanitize::SanitizeError, - solana_short_vec as short_vec, - solana_transaction_error::TransactionError, + solana_signature::Signature, + solana_signer::{signers::Signers, SignerError}, std::cmp::Ordering, }; - -mod sanitized; - -pub use sanitized::*; +#[cfg(feature = "serde")] +use { + serde_derive::{Deserialize, Serialize}, + solana_short_vec as short_vec, +}; +#[cfg(feature = "bincode")] use { - crate::program_utils::limited_deserialize, - solana_program::{ - nonce::NONCED_TX_MARKER_IX_INDEX, system_instruction::SystemInstruction, system_program, - }, + solana_bincode::limited_deserialize, + solana_program::{system_instruction::SystemInstruction, system_program}, }; +pub mod sanitized; + /// Type that serializes to the string "legacy" -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] +#[cfg_attr( + feature = "serde", + derive(Deserialize, Serialize), + serde(rename_all = "camelCase") +)] +#[derive(Clone, Debug, PartialEq, Eq)] pub enum Legacy { Legacy, } -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase", untagged)] +#[cfg_attr( + feature = "serde", + derive(Deserialize, Serialize), + serde(rename_all = "camelCase", untagged) +)] +#[derive(Clone, Debug, PartialEq, Eq)] pub enum TransactionVersion { Legacy(Legacy), Number(u8), @@ -48,11 +49,12 @@ impl TransactionVersion { // NOTE: Serialization-related changes must be paired with the direct read at sigverify. /// An atomic transaction -#[cfg_attr(feature = "frozen-abi", derive(AbiExample))] -#[derive(Debug, PartialEq, Default, Eq, Clone, Serialize, Deserialize)] +#[cfg_attr(feature = "frozen-abi", derive(solana_frozen_abi_macro::AbiExample))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +#[derive(Debug, PartialEq, Default, Eq, Clone)] pub struct VersionedTransaction { /// List of signatures - #[serde(with = "short_vec")] + #[cfg_attr(feature = "serde", serde(with = "short_vec"))] pub signatures: Vec, /// Message to sign. pub message: VersionedMessage, @@ -170,26 +172,31 @@ impl VersionedTransaction { } } + #[cfg(feature = "verify")] /// Verify the transaction and hash its message - pub fn verify_and_hash_message(&self) -> Result { + pub fn verify_and_hash_message( + &self, + ) -> solana_transaction_error::TransactionResult { let message_bytes = self.message.serialize(); if !self ._verify_with_results(&message_bytes) .iter() .all(|verify_result| *verify_result) { - Err(TransactionError::SignatureFailure) + Err(solana_transaction_error::TransactionError::SignatureFailure) } else { Ok(VersionedMessage::hash_raw_message(&message_bytes)) } } + #[cfg(feature = "verify")] /// Verify the transaction and return a list of verification results pub fn verify_with_results(&self) -> Vec { let message_bytes = self.message.serialize(); self._verify_with_results(&message_bytes) } + #[cfg(feature = "verify")] fn _verify_with_results(&self, message_bytes: &[u8]) -> Vec { self.signatures .iter() @@ -198,12 +205,13 @@ impl VersionedTransaction { .collect() } + #[cfg(feature = "bincode")] /// Returns true if transaction begins with an advance nonce instruction. pub fn uses_durable_nonce(&self) -> bool { let message = &self.message; message .instructions() - .get(NONCED_TX_MARKER_IX_INDEX as usize) + .get(crate::NONCED_TX_MARKER_IX_INDEX as usize) .filter(|instruction| { // Is system program matches!( @@ -212,7 +220,7 @@ impl VersionedTransaction { ) // Is a nonce advance instruction && matches!( - limited_deserialize(&instruction.data), + limited_deserialize(&instruction.data, crate::PACKET_DATA_SIZE as u64,), Ok(SystemInstruction::AdvanceNonceAccount) ) }) @@ -224,15 +232,15 @@ impl VersionedTransaction { mod tests { use { super::*, - crate::{ - message::Message as LegacyMessage, - signer::{keypair::Keypair, Signer}, - system_instruction, - }, + solana_hash::Hash, + solana_keypair::Keypair, solana_program::{ instruction::{AccountMeta, Instruction}, + message::Message as LegacyMessage, pubkey::Pubkey, + system_instruction, }, + solana_signer::Signer, }; #[test] diff --git a/sdk/src/transaction/versioned/sanitized.rs b/sdk/transaction/src/versioned/sanitized.rs similarity index 93% rename from sdk/src/transaction/versioned/sanitized.rs rename to sdk/transaction/src/versioned/sanitized.rs index 6243292fce3526..880f93bdca7cb5 100644 --- a/sdk/src/transaction/versioned/sanitized.rs +++ b/sdk/transaction/src/versioned/sanitized.rs @@ -1,6 +1,6 @@ use { - super::VersionedTransaction, crate::signature::Signature, - solana_program::message::SanitizedVersionedMessage, solana_sanitize::SanitizeError, + crate::versioned::VersionedTransaction, solana_program::message::SanitizedVersionedMessage, + solana_sanitize::SanitizeError, solana_signature::Signature, }; /// Wraps a sanitized `VersionedTransaction` to provide a safe API diff --git a/sdk/transaction/src/wasm.rs b/sdk/transaction/src/wasm.rs new file mode 100644 index 00000000000000..c48723b1c7ded1 --- /dev/null +++ b/sdk/transaction/src/wasm.rs @@ -0,0 +1,58 @@ +//! `Transaction` Javascript interface +#![cfg(target_arch = "wasm32")] +#![allow(non_snake_case)] +use { + crate::Transaction, + solana_hash::Hash, + solana_keypair::Keypair, + solana_program::{message::Message, wasm::instructions::Instructions}, + solana_pubkey::Pubkey, + wasm_bindgen::prelude::*, +}; + +#[wasm_bindgen] +impl Transaction { + /// Create a new `Transaction` + #[wasm_bindgen(constructor)] + pub fn constructor(instructions: Instructions, payer: Option) -> Transaction { + let instructions: Vec<_> = instructions.into(); + Transaction::new_with_payer(&instructions, payer.as_ref()) + } + + /// Return a message containing all data that should be signed. + #[wasm_bindgen(js_name = message)] + pub fn js_message(&self) -> Message { + self.message.clone() + } + + /// Return the serialized message data to sign. + pub fn messageData(&self) -> Box<[u8]> { + self.message_data().into() + } + + #[cfg(feature = "verify")] + /// Verify the transaction + #[wasm_bindgen(js_name = verify)] + pub fn js_verify(&self) -> Result<(), JsValue> { + self.verify() + .map_err(|x| std::string::ToString::to_string(&x).into()) + } + + pub fn partialSign(&mut self, keypair: &Keypair, recent_blockhash: &Hash) { + self.partial_sign(&[keypair], *recent_blockhash); + } + + pub fn isSigned(&self) -> bool { + self.is_signed() + } + + #[cfg(feature = "bincode")] + pub fn toBytes(&self) -> Box<[u8]> { + bincode::serialize(self).unwrap().into() + } + + #[cfg(feature = "bincode")] + pub fn fromBytes(bytes: &[u8]) -> Result { + bincode::deserialize(bytes).map_err(|x| std::string::ToString::to_string(&x).into()) + } +} diff --git a/svm/examples/Cargo.lock b/svm/examples/Cargo.lock index 25731aa1f24f83..d091f5d554dce2 100644 --- a/svm/examples/Cargo.lock +++ b/svm/examples/Cargo.lock @@ -5104,22 +5104,54 @@ dependencies = [ "log", "quinn", "rayon", + "solana-account", + "solana-client-traits", + "solana-commitment-config", "solana-connection-cache", + "solana-epoch-info", + "solana-hash", + "solana-instruction", + "solana-keypair", "solana-measure", + "solana-program", + "solana-pubkey", "solana-pubsub-client", "solana-quic-client", + "solana-quic-definitions", "solana-rpc-client", "solana-rpc-client-api", "solana-rpc-client-nonce-utils", - "solana-sdk", + "solana-signature", + "solana-signer", "solana-streamer", "solana-thin-client", + "solana-time-utils", "solana-tpu-client", + "solana-transaction", + "solana-transaction-error", "solana-udp-client", "thiserror 2.0.3", "tokio", ] +[[package]] +name = "solana-client-traits" +version = "2.2.0" +dependencies = [ + "solana-account", + "solana-commitment-config", + "solana-epoch-info", + "solana-hash", + "solana-instruction", + "solana-keypair", + "solana-program", + "solana-pubkey", + "solana-signature", + "solana-signer", + "solana-transaction", + "solana-transaction-error", +] + [[package]] name = "solana-clock" version = "2.2.0" @@ -6519,6 +6551,7 @@ dependencies = [ "siphasher", "solana-account", "solana-bn254", + "solana-client-traits", "solana-cluster-type", "solana-commitment-config", "solana-compute-budget-interface", @@ -6557,6 +6590,7 @@ dependencies = [ "solana-signature", "solana-signer", "solana-time-utils", + "solana-transaction", "solana-transaction-context", "solana-transaction-error", "thiserror 2.0.3", @@ -7049,6 +7083,31 @@ dependencies = [ "tokio", ] +[[package]] +name = "solana-transaction" +version = "2.2.0" +dependencies = [ + "bincode", + "serde", + "serde_derive", + "solana-bincode", + "solana-feature-set", + "solana-hash", + "solana-instruction", + "solana-keypair", + "solana-precompiles", + "solana-program", + "solana-pubkey", + "solana-reserved-account-keys", + "solana-sanitize", + "solana-sdk-ids", + "solana-short-vec", + "solana-signature", + "solana-signer", + "solana-transaction-error", + "wasm-bindgen", +] + [[package]] name = "solana-transaction-context" version = "2.2.0"