diff --git a/cli/src/wallet.rs b/cli/src/wallet.rs index 5b0b000d14..35002cedea 100644 --- a/cli/src/wallet.rs +++ b/cli/src/wallet.rs @@ -39,7 +39,9 @@ use { system_program, transaction::Transaction, }, - solana_transaction_status::{Encodable, EncodedTransaction, UiTransactionEncoding}, + solana_transaction_status::{ + Encodable, EncodedTransaction, TransactionBinaryEncoding, UiTransactionEncoding, + }, std::{fmt::Write as FmtWrite, fs::File, io::Write, sync::Arc}, }; @@ -189,7 +191,7 @@ impl WalletSubCommands for App<'_, '_> { Arg::with_name("encoding") .index(2) .value_name("ENCODING") - .possible_values(&["base58", "base64"]) // Subset of `UiTransactionEncoding` enum + .possible_values(&["base58", "base64"]) // Variants of `TransactionBinaryEncoding` enum .default_value("base58") .takes_value(true) .required(true) @@ -341,13 +343,13 @@ pub fn parse_balance( pub fn parse_decode_transaction(matches: &ArgMatches<'_>) -> Result { let blob = value_t_or_exit!(matches, "transaction", String); - let encoding = match matches.value_of("encoding").unwrap() { - "base58" => UiTransactionEncoding::Base58, - "base64" => UiTransactionEncoding::Base64, + let binary_encoding = match matches.value_of("encoding").unwrap() { + "base58" => TransactionBinaryEncoding::Base58, + "base64" => TransactionBinaryEncoding::Base64, _ => unreachable!(), }; - let encoded_transaction = EncodedTransaction::Binary(blob, encoding); + let encoded_transaction = EncodedTransaction::Binary(blob, binary_encoding); if let Some(transaction) = encoded_transaction.decode() { Ok(CliCommandInfo { command: CliCommand::DecodeTransaction(transaction), diff --git a/client/src/mock_sender.rs b/client/src/mock_sender.rs index 0642283148..3b6c0856df 100644 --- a/client/src/mock_sender.rs +++ b/client/src/mock_sender.rs @@ -32,9 +32,9 @@ use { }, solana_transaction_status::{ EncodedConfirmedBlock, EncodedConfirmedTransactionWithStatusMeta, EncodedTransaction, - EncodedTransactionWithStatusMeta, Rewards, TransactionConfirmationStatus, - TransactionStatus, UiCompiledInstruction, UiMessage, UiRawMessage, UiTransaction, - UiTransactionEncoding, UiTransactionStatusMeta, + EncodedTransactionWithStatusMeta, Rewards, TransactionBinaryEncoding, + TransactionConfirmationStatus, TransactionStatus, UiCompiledInstruction, UiMessage, + UiRawMessage, UiTransaction, UiTransactionStatusMeta, }, solana_version::Version, std::{collections::HashMap, net::SocketAddr, str::FromStr, sync::RwLock}, @@ -381,7 +381,7 @@ impl RpcSender for MockSender { pLHxcaShD81xBNaFDgnA2nkkdHnKtZt4hVSfKAmw3VRZbjrZ7L2fKZBx21CwsG\ hD6onjM2M3qZW5C8J6d1pj41MxKmZgPBSha3MyKkNLkAGFASK" .to_string(), - UiTransactionEncoding::Base58, + TransactionBinaryEncoding::Base58, ), meta: None, version: Some(TransactionVersion::LEGACY), diff --git a/rpc/src/rpc.rs b/rpc/src/rpc.rs index cb62c84854..1a0dcdeb6c 100644 --- a/rpc/src/rpc.rs +++ b/rpc/src/rpc.rs @@ -82,8 +82,8 @@ use { solana_transaction_status::{ BlockEncodingOptions, ConfirmedBlock, ConfirmedTransactionStatusWithSignature, ConfirmedTransactionWithStatusMeta, EncodedConfirmedTransactionWithStatusMeta, Reward, - RewardType, TransactionConfirmationStatus, TransactionStatus, UiConfirmedBlock, - UiTransactionEncoding, + RewardType, TransactionBinaryEncoding, TransactionConfirmationStatus, TransactionStatus, + UiConfirmedBlock, UiTransactionEncoding, }, solana_vote_program::vote_state::{VoteState, MAX_LOCKOUT_HISTORY}, spl_token::{ @@ -3468,9 +3468,15 @@ pub mod rpc_full { ) -> Result { debug!("send_transaction rpc request received"); let config = config.unwrap_or_default(); - let encoding = config.encoding.unwrap_or(UiTransactionEncoding::Base58); + let tx_encoding = config.encoding.unwrap_or(UiTransactionEncoding::Base58); + let binary_encoding = tx_encoding.into_binary_encoding().ok_or_else(|| { + Error::invalid_params(format!( + "unsupported encoding: {}. Supported encodings: base58, base64", + tx_encoding + )) + })?; let (wire_transaction, unsanitized_tx) = - decode_and_deserialize::(data, encoding)?; + decode_and_deserialize::(data, binary_encoding)?; let preflight_commitment = config .preflight_commitment @@ -3568,9 +3574,15 @@ pub mod rpc_full { ) -> Result> { debug!("simulate_transaction rpc request received"); let config = config.unwrap_or_default(); - let encoding = config.encoding.unwrap_or(UiTransactionEncoding::Base58); + let tx_encoding = config.encoding.unwrap_or(UiTransactionEncoding::Base58); + let binary_encoding = tx_encoding.into_binary_encoding().ok_or_else(|| { + Error::invalid_params(format!( + "unsupported encoding: {}. Supported encodings: base58, base64", + tx_encoding + )) + })?; let (_, mut unsanitized_tx) = - decode_and_deserialize::(data, encoding)?; + decode_and_deserialize::(data, binary_encoding)?; let bank = &*meta.bank(config.commitment); if config.replace_recent_blockhash { @@ -3804,7 +3816,7 @@ pub mod rpc_full { ) -> Result>> { debug!("get_fee_for_message rpc request received"); let (_, message) = - decode_and_deserialize::(data, UiTransactionEncoding::Base64)?; + decode_and_deserialize::(data, TransactionBinaryEncoding::Base64)?; let sanitized_message = SanitizedMessage::try_from(message).map_err(|err| { Error::invalid_params(format!("invalid transaction message: {}", err)) })?; @@ -4206,13 +4218,13 @@ const MAX_BASE58_SIZE: usize = 1683; // Golden, bump if PACKET_DATA_SIZE changes const MAX_BASE64_SIZE: usize = 1644; // Golden, bump if PACKET_DATA_SIZE changes fn decode_and_deserialize( encoded: String, - encoding: UiTransactionEncoding, + encoding: TransactionBinaryEncoding, ) -> Result<(Vec, T)> where T: serde::de::DeserializeOwned, { let wire_output = match encoding { - UiTransactionEncoding::Base58 => { + TransactionBinaryEncoding::Base58 => { inc_new_counter_info!("rpc-base58_encoded_tx", 1); if encoded.len() > MAX_BASE58_SIZE { return Err(Error::invalid_params(format!( @@ -4227,7 +4239,7 @@ where .into_vec() .map_err(|e| Error::invalid_params(format!("{:?}", e)))? } - UiTransactionEncoding::Base64 => { + TransactionBinaryEncoding::Base64 => { inc_new_counter_info!("rpc-base64_encoded_tx", 1); if encoded.len() > MAX_BASE64_SIZE { return Err(Error::invalid_params(format!( @@ -4240,12 +4252,6 @@ where } base64::decode(encoded).map_err(|e| Error::invalid_params(format!("{:?}", e)))? } - _ => { - return Err(Error::invalid_params(format!( - "unsupported encoding: {}. Supported encodings: base58, base64", - encoding - ))) - } }; if wire_output.len() > PACKET_DATA_SIZE { let err = format!( @@ -7763,7 +7769,8 @@ pub mod tests { tx58_len, MAX_BASE58_SIZE, PACKET_DATA_SIZE, )); assert_eq!( - decode_and_deserialize::(tx58, UiTransactionEncoding::Base58).unwrap_err(), + decode_and_deserialize::(tx58, TransactionBinaryEncoding::Base58) + .unwrap_err(), expect58 ); let tx64 = base64::encode(&tx_ser); @@ -7773,7 +7780,8 @@ pub mod tests { tx64_len, MAX_BASE64_SIZE, PACKET_DATA_SIZE, )); assert_eq!( - decode_and_deserialize::(tx64, UiTransactionEncoding::Base64).unwrap_err(), + decode_and_deserialize::(tx64, TransactionBinaryEncoding::Base64) + .unwrap_err(), expect64 ); let too_big = PACKET_DATA_SIZE + 1; @@ -7784,12 +7792,14 @@ pub mod tests { too_big, PACKET_DATA_SIZE )); assert_eq!( - decode_and_deserialize::(tx58, UiTransactionEncoding::Base58).unwrap_err(), + decode_and_deserialize::(tx58, TransactionBinaryEncoding::Base58) + .unwrap_err(), expect ); let tx64 = base64::encode(&tx_ser); assert_eq!( - decode_and_deserialize::(tx64, UiTransactionEncoding::Base64).unwrap_err(), + decode_and_deserialize::(tx64, TransactionBinaryEncoding::Base64) + .unwrap_err(), expect ); } @@ -7804,7 +7814,7 @@ pub mod tests { let unsanitary_versioned_tx = decode_and_deserialize::( unsanitary_tx58, - UiTransactionEncoding::Base58, + TransactionBinaryEncoding::Base58, ) .unwrap() .1; diff --git a/transaction-status/src/lib.rs b/transaction-status/src/lib.rs index 865b69b07e..b539da3cdf 100644 --- a/transaction-status/src/lib.rs +++ b/transaction-status/src/lib.rs @@ -70,6 +70,13 @@ pub trait EncodableWithMeta { ) -> Self::Encoded; } +#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[serde(rename_all = "camelCase")] +pub enum TransactionBinaryEncoding { + Base58, + Base64, +} + #[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, Hash, PartialEq)] #[serde(rename_all = "camelCase")] pub enum UiTransactionEncoding { @@ -80,6 +87,16 @@ pub enum UiTransactionEncoding { JsonParsed, } +impl UiTransactionEncoding { + pub fn into_binary_encoding(&self) -> Option { + match self { + Self::Binary | Self::Base58 => Some(TransactionBinaryEncoding::Base58), + Self::Base64 => Some(TransactionBinaryEncoding::Base64), + _ => None, + } + } +} + impl fmt::Display for UiTransactionEncoding { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let v = serde_json::to_value(self).map_err(|_| fmt::Error)?; @@ -801,7 +818,7 @@ pub struct EncodedConfirmedTransactionWithStatusMeta { #[serde(rename_all = "camelCase", untagged)] pub enum EncodedTransaction { LegacyBinary(String), // Old way of expressing base-58, retained for RPC backwards compatibility - Binary(String, UiTransactionEncoding), + Binary(String, TransactionBinaryEncoding), Json(UiTransaction), } @@ -818,11 +835,11 @@ impl EncodableWithMeta for VersionedTransaction { ), UiTransactionEncoding::Base58 => EncodedTransaction::Binary( bs58::encode(bincode::serialize(self).unwrap()).into_string(), - encoding, + TransactionBinaryEncoding::Base58, ), UiTransactionEncoding::Base64 => EncodedTransaction::Binary( base64::encode(bincode::serialize(self).unwrap()), - encoding, + TransactionBinaryEncoding::Base64, ), UiTransactionEncoding::Json | UiTransactionEncoding::JsonParsed => { EncodedTransaction::Json(UiTransaction { @@ -846,11 +863,11 @@ impl Encodable for Transaction { ), UiTransactionEncoding::Base58 => EncodedTransaction::Binary( bs58::encode(bincode::serialize(self).unwrap()).into_string(), - encoding, + TransactionBinaryEncoding::Base58, ), UiTransactionEncoding::Base64 => EncodedTransaction::Binary( base64::encode(bincode::serialize(self).unwrap()), - encoding, + TransactionBinaryEncoding::Base64, ), UiTransactionEncoding::Json | UiTransactionEncoding::JsonParsed => { EncodedTransaction::Json(UiTransaction { @@ -871,16 +888,13 @@ impl EncodedTransaction { .ok() .and_then(|bytes| bincode::deserialize(&bytes).ok()), EncodedTransaction::Binary(blob, encoding) => match *encoding { - UiTransactionEncoding::Base58 => bs58::decode(blob) + TransactionBinaryEncoding::Base58 => bs58::decode(blob) .into_vec() .ok() .and_then(|bytes| bincode::deserialize(&bytes).ok()), - UiTransactionEncoding::Base64 => base64::decode(blob) + TransactionBinaryEncoding::Base64 => base64::decode(blob) .ok() .and_then(|bytes| bincode::deserialize(&bytes).ok()), - UiTransactionEncoding::Binary - | UiTransactionEncoding::Json - | UiTransactionEncoding::JsonParsed => None, }, }; transaction.filter(|transaction| transaction.sanitize().is_ok()) @@ -1030,7 +1044,7 @@ mod test { pLHxcaShD81xBNaFDgnA2nkkdHnKtZt4hVSfKAmw3VRZbjrZ7L2fKZBx21CwsG\ hD6onjM2M3qZW5C8J6d1pj41MxKmZgPBSha3MyKkNLkAGFASK" .to_string(), - UiTransactionEncoding::Base58, + TransactionBinaryEncoding::Base58, ); assert!(unsanitary_transaction.decode().is_none()); }