Refactor: Add transaction binary encoding enum (#23546)
This commit is contained in:
parent
65e2d9b2f2
commit
249d926d1b
|
@ -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<CliCommandInfo, CliError> {
|
||||
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),
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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<String> {
|
||||
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::<VersionedTransaction>(data, encoding)?;
|
||||
decode_and_deserialize::<VersionedTransaction>(data, binary_encoding)?;
|
||||
|
||||
let preflight_commitment = config
|
||||
.preflight_commitment
|
||||
|
@ -3568,9 +3574,15 @@ pub mod rpc_full {
|
|||
) -> Result<RpcResponse<RpcSimulateTransactionResult>> {
|
||||
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::<VersionedTransaction>(data, encoding)?;
|
||||
decode_and_deserialize::<VersionedTransaction>(data, binary_encoding)?;
|
||||
|
||||
let bank = &*meta.bank(config.commitment);
|
||||
if config.replace_recent_blockhash {
|
||||
|
@ -3804,7 +3816,7 @@ pub mod rpc_full {
|
|||
) -> Result<RpcResponse<Option<u64>>> {
|
||||
debug!("get_fee_for_message rpc request received");
|
||||
let (_, message) =
|
||||
decode_and_deserialize::<Message>(data, UiTransactionEncoding::Base64)?;
|
||||
decode_and_deserialize::<Message>(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<T>(
|
||||
encoded: String,
|
||||
encoding: UiTransactionEncoding,
|
||||
encoding: TransactionBinaryEncoding,
|
||||
) -> Result<(Vec<u8>, 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::<Transaction>(tx58, UiTransactionEncoding::Base58).unwrap_err(),
|
||||
decode_and_deserialize::<Transaction>(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::<Transaction>(tx64, UiTransactionEncoding::Base64).unwrap_err(),
|
||||
decode_and_deserialize::<Transaction>(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::<Transaction>(tx58, UiTransactionEncoding::Base58).unwrap_err(),
|
||||
decode_and_deserialize::<Transaction>(tx58, TransactionBinaryEncoding::Base58)
|
||||
.unwrap_err(),
|
||||
expect
|
||||
);
|
||||
let tx64 = base64::encode(&tx_ser);
|
||||
assert_eq!(
|
||||
decode_and_deserialize::<Transaction>(tx64, UiTransactionEncoding::Base64).unwrap_err(),
|
||||
decode_and_deserialize::<Transaction>(tx64, TransactionBinaryEncoding::Base64)
|
||||
.unwrap_err(),
|
||||
expect
|
||||
);
|
||||
}
|
||||
|
@ -7804,7 +7814,7 @@ pub mod tests {
|
|||
|
||||
let unsanitary_versioned_tx = decode_and_deserialize::<VersionedTransaction>(
|
||||
unsanitary_tx58,
|
||||
UiTransactionEncoding::Base58,
|
||||
TransactionBinaryEncoding::Base58,
|
||||
)
|
||||
.unwrap()
|
||||
.1;
|
||||
|
|
|
@ -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<TransactionBinaryEncoding> {
|
||||
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());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue