diff --git a/Cargo.lock b/Cargo.lock index 6ee073f5d..e26b78abe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2443,6 +2443,15 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +[[package]] +name = "pest" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +dependencies = [ + "ucd-trie", +] + [[package]] name = "pickledb" version = "0.4.1" @@ -3016,7 +3025,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" dependencies = [ - "semver", + "semver 0.9.0", ] [[package]] @@ -3139,7 +3148,16 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" dependencies = [ - "semver-parser", + "semver-parser 0.7.0", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser 0.10.1", ] [[package]] @@ -3148,6 +3166,15 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +[[package]] +name = "semver-parser" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ef146c2ad5e5f4b037cd6ce2ebb775401729b19a82040c1beac9d36c7d1428" +dependencies = [ + "pest", +] + [[package]] name = "serde" version = "1.0.112" @@ -3682,6 +3709,7 @@ dependencies = [ "log 0.4.8", "rayon", "reqwest", + "semver 0.11.0", "serde", "serde_derive", "serde_json", @@ -3691,6 +3719,7 @@ dependencies = [ "solana-net-utils", "solana-sdk 1.5.0", "solana-transaction-status", + "solana-version", "solana-vote-program", "thiserror", "tungstenite", @@ -3993,7 +4022,7 @@ dependencies = [ "lazy_static", "nix", "reqwest", - "semver", + "semver 0.9.0", "serde", "serde_derive", "serde_yaml", @@ -4349,7 +4378,7 @@ dependencies = [ "num-derive", "num-traits", "parking_lot 0.10.2", - "semver", + "semver 0.9.0", "solana-sdk 1.5.0", "thiserror", "url 2.1.1", @@ -5879,6 +5908,12 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" +[[package]] +name = "ucd-trie" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" + [[package]] name = "unicase" version = "1.4.2" diff --git a/client/Cargo.toml b/client/Cargo.toml index 2d08fa7fe..c8b436337 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -18,6 +18,7 @@ jsonrpc-core = "15.0.0" log = "0.4.8" rayon = "1.4.0" reqwest = { version = "0.10.8", default-features = false, features = ["blocking", "rustls-tls", "json"] } +semver = "0.11.0" serde = "1.0.112" serde_derive = "1.0.103" serde_json = "1.0.56" @@ -26,6 +27,7 @@ solana-clap-utils = { path = "../clap-utils", version = "1.5.0" } solana-net-utils = { path = "../net-utils", version = "1.5.0" } solana-sdk = { path = "../sdk", version = "1.5.0" } solana-transaction-status = { path = "../transaction-status", version = "1.5.0" } +solana-version = { path = "../version", version = "1.5.0" } solana-vote-program = { path = "../programs/vote", version = "1.5.0" } thiserror = "1.0" tungstenite = "0.10.1" diff --git a/client/src/mock_sender.rs b/client/src/mock_sender.rs index 2461b99f8..0588f6eaa 100644 --- a/client/src/mock_sender.rs +++ b/client/src/mock_sender.rs @@ -1,10 +1,10 @@ use crate::{ client_error::Result, rpc_request::RpcRequest, - rpc_response::{Response, RpcResponseContext}, + rpc_response::{Response, RpcResponseContext, RpcVersionInfo}, rpc_sender::RpcSender, }; -use serde_json::{Number, Value}; +use serde_json::{json, Number, Value}; use solana_sdk::{ fee_calculator::{FeeCalculator, FeeRateGovernor}, instruction::InstructionError, @@ -12,6 +12,7 @@ use solana_sdk::{ transaction::{self, Transaction, TransactionError}, }; use solana_transaction_status::TransactionStatus; +use solana_version::Version; use std::{collections::HashMap, sync::RwLock}; pub const PUBKEY: &str = "7RoSF9fUmdphVCpabEoefH81WwrW7orsWonXWqTXkKV8"; @@ -119,6 +120,13 @@ impl RpcSender for MockSender { Value::String(signature) } RpcRequest::GetMinimumBalanceForRentExemption => Value::Number(Number::from(20)), + RpcRequest::GetVersion => { + let version = Version::default(); + json!(RpcVersionInfo { + solana_core: version.to_string(), + feature_set: Some(version.feature_set), + }) + } _ => Value::Null, }; Ok(val) diff --git a/client/src/rpc_client.rs b/client/src/rpc_client.rs index c9f36ff7c..e7d0b2d53 100644 --- a/client/src/rpc_client.rs +++ b/client/src/rpc_client.rs @@ -41,12 +41,14 @@ use solana_transaction_status::{ use solana_vote_program::vote_state::MAX_LOCKOUT_HISTORY; use std::{ net::SocketAddr, + sync::RwLock, thread::sleep, time::{Duration, Instant}, }; pub struct RpcClient { sender: Box, + default_cluster_transaction_encoding: RwLock>, } fn serialize_encode_transaction( @@ -73,6 +75,7 @@ impl RpcClient { pub fn new_sender(sender: T) -> Self { Self { sender: Box::new(sender), + default_cluster_transaction_encoding: RwLock::new(None), } } @@ -128,12 +131,41 @@ impl RpcClient { self.send_transaction_with_config(transaction, RpcSendTransactionConfig::default()) } + fn default_cluster_transaction_encoding(&self) -> Result { + let default_cluster_transaction_encoding = + self.default_cluster_transaction_encoding.read().unwrap(); + if let Some(encoding) = *default_cluster_transaction_encoding { + Ok(encoding) + } else { + drop(default_cluster_transaction_encoding); + let cluster_version = self.get_version().map_err(|e| { + RpcError::RpcRequestError(format!("cluster version query failed: {}", e)) + })?; + let cluster_version = + semver::Version::parse(&cluster_version.solana_core).map_err(|e| { + RpcError::RpcRequestError(format!("failed to parse cluster version: {}", e)) + })?; + // Prefer base64 since 1.3.16 + let encoding = if cluster_version < semver::Version::new(1, 3, 16) { + UiTransactionEncoding::Base58 + } else { + UiTransactionEncoding::Base64 + }; + *self.default_cluster_transaction_encoding.write().unwrap() = Some(encoding); + Ok(encoding) + } + } + pub fn send_transaction_with_config( &self, transaction: &Transaction, config: RpcSendTransactionConfig, ) -> ClientResult { - let encoding = config.encoding.unwrap_or(UiTransactionEncoding::Base64); + let encoding = if let Some(encoding) = config.encoding { + encoding + } else { + self.default_cluster_transaction_encoding()? + }; let config = RpcSendTransactionConfig { encoding: Some(encoding), ..config @@ -174,7 +206,11 @@ impl RpcClient { transaction: &Transaction, config: RpcSimulateTransactionConfig, ) -> RpcResult { - let encoding = config.encoding.unwrap_or(UiTransactionEncoding::Base64); + let encoding = if let Some(encoding) = config.encoding { + encoding + } else { + self.default_cluster_transaction_encoding()? + }; let config = RpcSimulateTransactionConfig { encoding: Some(encoding), ..config