Refactor: cleanup solana_transaction_status crate (#22230)

This commit is contained in:
Justin Starry 2022-01-03 23:45:18 +08:00 committed by GitHub
parent 86acd8f6f9
commit 2a00382d71
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 248 additions and 258 deletions

View File

@ -39,7 +39,7 @@ use {
system_program, system_program,
transaction::Transaction, transaction::Transaction,
}, },
solana_transaction_status::{EncodedTransaction, UiTransactionEncoding}, solana_transaction_status::{Encodable, EncodedTransaction, UiTransactionEncoding},
std::{fmt::Write as FmtWrite, fs::File, io::Write, sync::Arc}, std::{fmt::Write as FmtWrite, fs::File, io::Write, sync::Arc},
}; };
@ -564,10 +564,8 @@ pub fn process_confirm(
.transaction .transaction
.decode() .decode()
.expect("Successful decode"); .expect("Successful decode");
let json_transaction = EncodedTransaction::encode( let json_transaction =
decoded_transaction.clone(), decoded_transaction.encode(UiTransactionEncoding::Json);
UiTransactionEncoding::Json,
);
transaction = Some(CliTransaction { transaction = Some(CliTransaction {
transaction: json_transaction, transaction: json_transaction,
@ -609,7 +607,7 @@ pub fn process_decode_transaction(config: &CliConfig, transaction: &Transaction)
let sigverify_status = CliSignatureVerificationStatus::verify_transaction(transaction); let sigverify_status = CliSignatureVerificationStatus::verify_transaction(transaction);
let decode_transaction = CliTransaction { let decode_transaction = CliTransaction {
decoded_transaction: transaction.clone(), decoded_transaction: transaction.clone(),
transaction: EncodedTransaction::encode(transaction.clone(), UiTransactionEncoding::Json), transaction: transaction.encode(UiTransactionEncoding::Json),
meta: None, meta: None,
block_time: None, block_time: None,
slot: None, slot: None,

View File

@ -30,7 +30,7 @@ use {
transaction::{self, Transaction, TransactionError}, transaction::{self, Transaction, TransactionError},
}, },
solana_transaction_status::{ solana_transaction_status::{
EncodedConfirmedBlock, EncodedConfirmedTransaction, EncodedTransaction, EncodedConfirmedBlock, EncodedConfirmedTransactionWithStatusMeta, EncodedTransaction,
EncodedTransactionWithStatusMeta, Rewards, TransactionConfirmationStatus, EncodedTransactionWithStatusMeta, Rewards, TransactionConfirmationStatus,
TransactionStatus, UiCompiledInstruction, UiMessage, UiRawMessage, UiTransaction, TransactionStatus, UiCompiledInstruction, UiMessage, UiRawMessage, UiTransaction,
UiTransactionEncoding, UiTransactionStatusMeta, UiTransactionEncoding, UiTransactionStatusMeta,
@ -185,7 +185,7 @@ impl RpcSender for MockSender {
value: statuses, value: statuses,
})? })?
} }
"getTransaction" => serde_json::to_value(EncodedConfirmedTransaction { "getTransaction" => serde_json::to_value(EncodedConfirmedTransactionWithStatusMeta {
slot: 2, slot: 2,
transaction: EncodedTransactionWithStatusMeta { transaction: EncodedTransactionWithStatusMeta {
transaction: EncodedTransaction::Json( transaction: EncodedTransaction::Json(

View File

@ -43,8 +43,8 @@ use {
transaction::{self, uses_durable_nonce, Transaction}, transaction::{self, uses_durable_nonce, Transaction},
}, },
solana_transaction_status::{ solana_transaction_status::{
EncodedConfirmedBlock, EncodedConfirmedTransaction, TransactionStatus, UiConfirmedBlock, EncodedConfirmedBlock, EncodedConfirmedTransactionWithStatusMeta, TransactionStatus,
UiTransactionEncoding, UiConfirmedBlock, UiTransactionEncoding,
}, },
solana_vote_program::vote_state::MAX_LOCKOUT_HISTORY, solana_vote_program::vote_state::MAX_LOCKOUT_HISTORY,
std::{ std::{
@ -2943,7 +2943,7 @@ impl RpcClient {
&self, &self,
signature: &Signature, signature: &Signature,
encoding: UiTransactionEncoding, encoding: UiTransactionEncoding,
) -> ClientResult<EncodedConfirmedTransaction> { ) -> ClientResult<EncodedConfirmedTransactionWithStatusMeta> {
self.send( self.send(
self.maybe_map_request(RpcRequest::GetTransaction)?, self.maybe_map_request(RpcRequest::GetTransaction)?,
json!([signature.to_string(), encoding]), json!([signature.to_string(), encoding]),
@ -3006,7 +3006,7 @@ impl RpcClient {
&self, &self,
signature: &Signature, signature: &Signature,
config: RpcTransactionConfig, config: RpcTransactionConfig,
) -> ClientResult<EncodedConfirmedTransaction> { ) -> ClientResult<EncodedConfirmedTransactionWithStatusMeta> {
self.send( self.send(
self.maybe_map_request(RpcRequest::GetTransaction)?, self.maybe_map_request(RpcRequest::GetTransaction)?,
json!([signature.to_string(), config]), json!([signature.to_string(), config]),
@ -3022,7 +3022,7 @@ impl RpcClient {
&self, &self,
signature: &Signature, signature: &Signature,
encoding: UiTransactionEncoding, encoding: UiTransactionEncoding,
) -> ClientResult<EncodedConfirmedTransaction> { ) -> ClientResult<EncodedConfirmedTransactionWithStatusMeta> {
self.send( self.send(
RpcRequest::GetConfirmedTransaction, RpcRequest::GetConfirmedTransaction,
json!([signature.to_string(), encoding]), json!([signature.to_string(), encoding]),
@ -3038,7 +3038,7 @@ impl RpcClient {
&self, &self,
signature: &Signature, signature: &Signature,
config: RpcConfirmedTransactionConfig, config: RpcConfirmedTransactionConfig,
) -> ClientResult<EncodedConfirmedTransaction> { ) -> ClientResult<EncodedConfirmedTransactionWithStatusMeta> {
self.send( self.send(
RpcRequest::GetConfirmedTransaction, RpcRequest::GetConfirmedTransaction,
json!([signature.to_string(), config]), json!([signature.to_string(), config]),

View File

@ -14,7 +14,7 @@ use {
}, },
solana_ledger::{blockstore::Blockstore, blockstore_db::AccessType}, solana_ledger::{blockstore::Blockstore, blockstore_db::AccessType},
solana_sdk::{clock::Slot, pubkey::Pubkey, signature::Signature}, solana_sdk::{clock::Slot, pubkey::Pubkey, signature::Signature},
solana_transaction_status::{ConfirmedBlock, EncodedTransaction, UiTransactionEncoding}, solana_transaction_status::{ConfirmedBlock, Encodable, UiTransactionEncoding},
std::{ std::{
path::Path, path::Path,
process::exit, process::exit,
@ -109,10 +109,10 @@ async fn confirm(
match bigtable.get_confirmed_transaction(signature).await { match bigtable.get_confirmed_transaction(signature).await {
Ok(Some(confirmed_transaction)) => { Ok(Some(confirmed_transaction)) => {
transaction = Some(CliTransaction { transaction = Some(CliTransaction {
transaction: EncodedTransaction::encode( transaction: confirmed_transaction
confirmed_transaction.transaction.transaction.clone(), .transaction
UiTransactionEncoding::Json, .transaction
), .encode(UiTransactionEncoding::Json),
meta: confirmed_transaction.transaction.meta.map(|m| m.into()), meta: confirmed_transaction.transaction.meta.map(|m| m.into()),
block_time: confirmed_transaction.block_time, block_time: confirmed_transaction.block_time,
slot: Some(confirmed_transaction.slot), slot: Some(confirmed_transaction.slot),

View File

@ -41,8 +41,9 @@ use {
}, },
solana_storage_proto::{StoredExtendedRewards, StoredTransactionStatusMeta}, solana_storage_proto::{StoredExtendedRewards, StoredTransactionStatusMeta},
solana_transaction_status::{ solana_transaction_status::{
ConfirmedBlock, ConfirmedTransaction, ConfirmedTransactionStatusWithSignature, Rewards, ConfirmedBlock, ConfirmedTransactionStatusWithSignature,
TransactionStatusMeta, TransactionWithStatusMeta, ConfirmedTransactionWithStatusMeta, Rewards, TransactionStatusMeta,
TransactionWithStatusMeta,
}, },
std::{ std::{
borrow::Cow, borrow::Cow,
@ -2307,7 +2308,7 @@ impl Blockstore {
pub fn get_rooted_transaction( pub fn get_rooted_transaction(
&self, &self,
signature: Signature, signature: Signature,
) -> Result<Option<ConfirmedTransaction>> { ) -> Result<Option<ConfirmedTransactionWithStatusMeta>> {
datapoint_info!( datapoint_info!(
"blockstore-rpc-api", "blockstore-rpc-api",
("method", "get_rooted_transaction".to_string(), String) ("method", "get_rooted_transaction".to_string(), String)
@ -2320,7 +2321,7 @@ impl Blockstore {
&self, &self,
signature: Signature, signature: Signature,
highest_confirmed_slot: Slot, highest_confirmed_slot: Slot,
) -> Result<Option<ConfirmedTransaction>> { ) -> Result<Option<ConfirmedTransactionWithStatusMeta>> {
datapoint_info!( datapoint_info!(
"blockstore-rpc-api", "blockstore-rpc-api",
("method", "get_complete_transaction".to_string(), String) ("method", "get_complete_transaction".to_string(), String)
@ -2337,7 +2338,7 @@ impl Blockstore {
&self, &self,
signature: Signature, signature: Signature,
confirmed_unrooted_slots: &[Slot], confirmed_unrooted_slots: &[Slot],
) -> Result<Option<ConfirmedTransaction>> { ) -> Result<Option<ConfirmedTransactionWithStatusMeta>> {
if let Some((slot, status)) = if let Some((slot, status)) =
self.get_transaction_status(signature, confirmed_unrooted_slots)? self.get_transaction_status(signature, confirmed_unrooted_slots)?
{ {
@ -2351,7 +2352,7 @@ impl Blockstore {
.ok_or(BlockstoreError::UnsupportedTransactionVersion)?; .ok_or(BlockstoreError::UnsupportedTransactionVersion)?;
let block_time = self.get_block_time(slot)?; let block_time = self.get_block_time(slot)?;
Ok(Some(ConfirmedTransaction { Ok(Some(ConfirmedTransactionWithStatusMeta {
slot, slot,
transaction: TransactionWithStatusMeta { transaction: TransactionWithStatusMeta {
transaction, transaction,
@ -7171,7 +7172,7 @@ pub mod tests {
let signature = transaction.transaction.signatures[0]; let signature = transaction.transaction.signatures[0];
assert_eq!( assert_eq!(
blockstore.get_rooted_transaction(signature).unwrap(), blockstore.get_rooted_transaction(signature).unwrap(),
Some(ConfirmedTransaction { Some(ConfirmedTransactionWithStatusMeta {
slot, slot,
transaction: transaction.clone(), transaction: transaction.clone(),
block_time: None block_time: None
@ -7181,7 +7182,7 @@ pub mod tests {
blockstore blockstore
.get_complete_transaction(signature, slot + 1) .get_complete_transaction(signature, slot + 1)
.unwrap(), .unwrap(),
Some(ConfirmedTransaction { Some(ConfirmedTransactionWithStatusMeta {
slot, slot,
transaction, transaction,
block_time: None block_time: None
@ -7277,7 +7278,7 @@ pub mod tests {
blockstore blockstore
.get_complete_transaction(signature, slot) .get_complete_transaction(signature, slot)
.unwrap(), .unwrap(),
Some(ConfirmedTransaction { Some(ConfirmedTransactionWithStatusMeta {
slot, slot,
transaction, transaction,
block_time: None block_time: None

View File

@ -52,8 +52,8 @@ use solana_sdk::{
transaction::{SanitizedTransaction, Transaction, TransactionError}, transaction::{SanitizedTransaction, Transaction, TransactionError},
}; };
use solana_transaction_status::{ use solana_transaction_status::{
token_balances::collect_token_balances, ConfirmedTransaction, InnerInstructions, token_balances::collect_token_balances, ConfirmedTransactionWithStatusMeta, Encodable,
TransactionStatusMeta, TransactionWithStatusMeta, UiTransactionEncoding, InnerInstructions, TransactionStatusMeta, TransactionWithStatusMeta, UiTransactionEncoding,
}; };
use std::{ use std::{
collections::HashMap, convert::TryFrom, env, fs::File, io::Read, path::PathBuf, str::FromStr, collections::HashMap, convert::TryFrom, env, fs::File, io::Read, path::PathBuf, str::FromStr,
@ -320,7 +320,10 @@ fn process_transaction_and_record_inner(
) )
} }
fn execute_transactions(bank: &Bank, txs: Vec<Transaction>) -> Vec<ConfirmedTransaction> { fn execute_transactions(
bank: &Bank,
txs: Vec<Transaction>,
) -> Vec<ConfirmedTransactionWithStatusMeta> {
let batch = bank.prepare_batch_for_tests(txs.clone()); let batch = bank.prepare_batch_for_tests(txs.clone());
let mut timings = ExecuteTimings::default(); let mut timings = ExecuteTimings::default();
let mut mint_decimals = HashMap::new(); let mut mint_decimals = HashMap::new();
@ -402,7 +405,7 @@ fn execute_transactions(bank: &Bank, txs: Vec<Transaction>) -> Vec<ConfirmedTran
rewards: None, rewards: None,
}; };
ConfirmedTransaction { ConfirmedTransactionWithStatusMeta {
slot: bank.slot(), slot: bank.slot(),
transaction: TransactionWithStatusMeta { transaction: TransactionWithStatusMeta {
transaction: tx.clone(), transaction: tx.clone(),
@ -415,7 +418,7 @@ fn execute_transactions(bank: &Bank, txs: Vec<Transaction>) -> Vec<ConfirmedTran
.collect() .collect()
} }
fn print_confirmed_tx(name: &str, confirmed_tx: ConfirmedTransaction) { fn print_confirmed_tx(name: &str, confirmed_tx: ConfirmedTransactionWithStatusMeta) {
let block_time = confirmed_tx.block_time; let block_time = confirmed_tx.block_time;
let tx = confirmed_tx.transaction.transaction.clone(); let tx = confirmed_tx.transaction.transaction.clone();
let encoded = confirmed_tx.encode(UiTransactionEncoding::JsonParsed); let encoded = confirmed_tx.encode(UiTransactionEncoding::JsonParsed);
@ -1739,13 +1742,8 @@ fn test_program_bpf_upgrade() {
"solana_bpf_rust_upgradeable", "solana_bpf_rust_upgradeable",
); );
let mut instruction = Instruction::new_with_bytes( let mut instruction =
program_id, Instruction::new_with_bytes(program_id, &[0], vec![AccountMeta::new(clock::id(), false)]);
&[0],
vec![
AccountMeta::new(clock::id(), false),
],
);
// Call upgrade program // Call upgrade program
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction.clone()); let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction.clone());
@ -1833,13 +1831,8 @@ fn test_program_bpf_upgrade_and_invoke_in_same_tx() {
"solana_bpf_rust_noop", "solana_bpf_rust_noop",
); );
let invoke_instruction = Instruction::new_with_bytes( let invoke_instruction =
program_id, Instruction::new_with_bytes(program_id, &[0], vec![AccountMeta::new(clock::id(), false)]);
&[0],
vec![
AccountMeta::new(clock::id(), false),
],
);
// Call upgradeable program // Call upgradeable program
let result = let result =

View File

@ -76,9 +76,9 @@ use {
solana_storage_bigtable::Error as StorageError, solana_storage_bigtable::Error as StorageError,
solana_streamer::socket::SocketAddrSpace, solana_streamer::socket::SocketAddrSpace,
solana_transaction_status::{ solana_transaction_status::{
ConfirmedBlock, ConfirmedTransactionStatusWithSignature, EncodedConfirmedTransaction, ConfirmedBlock, ConfirmedTransactionStatusWithSignature, Encodable,
Reward, RewardType, TransactionConfirmationStatus, TransactionStatus, UiConfirmedBlock, EncodedConfirmedTransactionWithStatusMeta, Reward, RewardType,
UiTransactionEncoding, TransactionConfirmationStatus, TransactionStatus, UiConfirmedBlock, UiTransactionEncoding,
}, },
solana_vote_program::vote_state::{VoteState, MAX_LOCKOUT_HISTORY}, solana_vote_program::vote_state::{VoteState, MAX_LOCKOUT_HISTORY},
spl_token::{ spl_token::{
@ -1358,7 +1358,7 @@ impl JsonRpcRequestProcessor {
&self, &self,
signature: Signature, signature: Signature,
config: Option<RpcEncodingConfigWrapper<RpcTransactionConfig>>, config: Option<RpcEncodingConfigWrapper<RpcTransactionConfig>>,
) -> Result<Option<EncodedConfirmedTransaction>> { ) -> Result<Option<EncodedConfirmedTransactionWithStatusMeta>> {
let config = config let config = config
.map(|config| config.convert_to_current()) .map(|config| config.convert_to_current())
.unwrap_or_default(); .unwrap_or_default();
@ -3214,7 +3214,7 @@ pub mod rpc_full {
meta: Self::Metadata, meta: Self::Metadata,
signature_str: String, signature_str: String,
config: Option<RpcEncodingConfigWrapper<RpcTransactionConfig>>, config: Option<RpcEncodingConfigWrapper<RpcTransactionConfig>>,
) -> BoxFuture<Result<Option<EncodedConfirmedTransaction>>>; ) -> BoxFuture<Result<Option<EncodedConfirmedTransactionWithStatusMeta>>>;
#[rpc(meta, name = "getSignaturesForAddress")] #[rpc(meta, name = "getSignaturesForAddress")]
fn get_signatures_for_address( fn get_signatures_for_address(
@ -3689,7 +3689,7 @@ pub mod rpc_full {
meta: Self::Metadata, meta: Self::Metadata,
signature_str: String, signature_str: String,
config: Option<RpcEncodingConfigWrapper<RpcTransactionConfig>>, config: Option<RpcEncodingConfigWrapper<RpcTransactionConfig>>,
) -> BoxFuture<Result<Option<EncodedConfirmedTransaction>>> { ) -> BoxFuture<Result<Option<EncodedConfirmedTransactionWithStatusMeta>>> {
debug!("get_transaction rpc request received: {:?}", signature_str); debug!("get_transaction rpc request received: {:?}", signature_str);
let signature = verify_signature(&signature_str); let signature = verify_signature(&signature_str);
if let Err(err) = signature { if let Err(err) = signature {
@ -3928,7 +3928,7 @@ pub mod rpc_deprecated_v1_7 {
meta: Self::Metadata, meta: Self::Metadata,
signature_str: String, signature_str: String,
config: Option<RpcEncodingConfigWrapper<RpcConfirmedTransactionConfig>>, config: Option<RpcEncodingConfigWrapper<RpcConfirmedTransactionConfig>>,
) -> BoxFuture<Result<Option<EncodedConfirmedTransaction>>>; ) -> BoxFuture<Result<Option<EncodedConfirmedTransactionWithStatusMeta>>>;
// DEPRECATED // DEPRECATED
#[rpc(meta, name = "getConfirmedSignaturesForAddress2")] #[rpc(meta, name = "getConfirmedSignaturesForAddress2")]
@ -3998,7 +3998,7 @@ pub mod rpc_deprecated_v1_7 {
meta: Self::Metadata, meta: Self::Metadata,
signature_str: String, signature_str: String,
config: Option<RpcEncodingConfigWrapper<RpcConfirmedTransactionConfig>>, config: Option<RpcEncodingConfigWrapper<RpcConfirmedTransactionConfig>>,
) -> BoxFuture<Result<Option<EncodedConfirmedTransaction>>> { ) -> BoxFuture<Result<Option<EncodedConfirmedTransactionWithStatusMeta>>> {
debug!( debug!(
"get_confirmed_transaction rpc request received: {:?}", "get_confirmed_transaction rpc request received: {:?}",
signature_str signature_str

View File

@ -18,7 +18,7 @@ pub use non_bpf_modules::*;
/// The length of a message header in bytes /// The length of a message header in bytes
pub const MESSAGE_HEADER_LENGTH: usize = 3; pub const MESSAGE_HEADER_LENGTH: usize = 3;
#[derive(Serialize, Deserialize, Default, Debug, PartialEq, Eq, Clone, AbiExample)] #[derive(Serialize, Deserialize, Default, Debug, PartialEq, Eq, Clone, Copy, AbiExample)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct MessageHeader { pub struct MessageHeader {
/// The number of signatures required for this message to be considered valid. The /// The number of signatures required for this message to be considered valid. The

View File

@ -13,8 +13,8 @@ use {
}, },
solana_storage_proto::convert::{generated, tx_by_addr}, solana_storage_proto::convert::{generated, tx_by_addr},
solana_transaction_status::{ solana_transaction_status::{
extract_and_fmt_memos, ConfirmedBlock, ConfirmedTransaction, extract_and_fmt_memos, ConfirmedBlock, ConfirmedTransactionStatusWithSignature,
ConfirmedTransactionStatusWithSignature, Reward, TransactionByAddrInfo, ConfirmedTransactionWithStatusMeta, Reward, TransactionByAddrInfo,
TransactionConfirmationStatus, TransactionStatus, TransactionStatusMeta, TransactionConfirmationStatus, TransactionStatus, TransactionStatusMeta,
TransactionWithStatusMeta, TransactionWithStatusMeta,
}, },
@ -433,7 +433,7 @@ impl LedgerStorage {
pub async fn get_confirmed_transaction( pub async fn get_confirmed_transaction(
&self, &self,
signature: &Signature, signature: &Signature,
) -> Result<Option<ConfirmedTransaction>> { ) -> Result<Option<ConfirmedTransactionWithStatusMeta>> {
debug!( debug!(
"LedgerStorage::get_confirmed_transaction request received: {:?}", "LedgerStorage::get_confirmed_transaction request received: {:?}",
signature signature
@ -466,7 +466,7 @@ impl LedgerStorage {
); );
Ok(None) Ok(None)
} else { } else {
Ok(Some(ConfirmedTransaction { Ok(Some(ConfirmedTransactionWithStatusMeta {
slot, slot,
transaction: bucket_block_transaction, transaction: bucket_block_transaction,
block_time: block.block_time, block_time: block.block_time,

View File

@ -34,6 +34,45 @@ use {
}, },
std::fmt, std::fmt,
}; };
/// Represents types that can be encoded into one of several encoding formats
pub trait Encodable {
type Encoded;
fn encode(self, encoding: UiTransactionEncoding) -> Self::Encoded;
}
#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[serde(rename_all = "camelCase")]
pub enum UiTransactionEncoding {
Binary, // Legacy. Retained for RPC backwards compatibility
Base64,
Base58,
Json,
JsonParsed,
}
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)?;
let s = v.as_str().ok_or(fmt::Error)?;
write!(f, "{}", s)
}
}
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum TransactionDetails {
Full,
Signatures,
None,
}
impl Default for TransactionDetails {
fn default() -> Self {
Self::Full
}
}
/// A duplicate representation of an Instruction for pretty JSON serialization /// A duplicate representation of an Instruction for pretty JSON serialization
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", untagged)] #[serde(rename_all = "camelCase", untagged)]
@ -42,13 +81,6 @@ pub enum UiInstruction {
Parsed(UiParsedInstruction), Parsed(UiParsedInstruction),
} }
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", untagged)]
pub enum UiParsedInstruction {
Parsed(ParsedInstruction),
PartiallyDecoded(UiPartiallyDecodedInstruction),
}
impl UiInstruction { impl UiInstruction {
fn parse(instruction: &CompiledInstruction, message: &Message) -> Self { fn parse(instruction: &CompiledInstruction, message: &Message) -> Self {
let program_id = instruction.program_id(&message.account_keys); let program_id = instruction.program_id(&message.account_keys);
@ -62,6 +94,13 @@ impl UiInstruction {
} }
} }
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", untagged)]
pub enum UiParsedInstruction {
Parsed(ParsedInstruction),
PartiallyDecoded(UiPartiallyDecodedInstruction),
}
/// A duplicate representation of a CompiledInstruction for pretty JSON serialization /// A duplicate representation of a CompiledInstruction for pretty JSON serialization
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
@ -121,6 +160,32 @@ pub struct UiInnerInstructions {
pub instructions: Vec<UiInstruction>, pub instructions: Vec<UiInstruction>,
} }
impl UiInnerInstructions {
fn parse(inner_instructions: InnerInstructions, message: &Message) -> Self {
Self {
index: inner_instructions.index,
instructions: inner_instructions
.instructions
.iter()
.map(|ix| UiInstruction::parse(ix, message))
.collect(),
}
}
}
impl From<InnerInstructions> for UiInnerInstructions {
fn from(inner_instructions: InnerInstructions) -> Self {
Self {
index: inner_instructions.index,
instructions: inner_instructions
.instructions
.iter()
.map(|ix| UiInstruction::Compiled(ix.into()))
.collect(),
}
}
}
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct TransactionTokenBalance { pub struct TransactionTokenBalance {
pub account_index: u8, pub account_index: u8,
@ -154,32 +219,6 @@ impl From<TransactionTokenBalance> for UiTransactionTokenBalance {
} }
} }
impl UiInnerInstructions {
fn parse(inner_instructions: InnerInstructions, message: &Message) -> Self {
Self {
index: inner_instructions.index,
instructions: inner_instructions
.instructions
.iter()
.map(|ix| UiInstruction::parse(ix, message))
.collect(),
}
}
}
impl From<InnerInstructions> for UiInnerInstructions {
fn from(inner_instructions: InnerInstructions) -> Self {
Self {
index: inner_instructions.index,
instructions: inner_instructions
.instructions
.iter()
.map(|ix| UiInstruction::Compiled(ix.into()))
.collect(),
}
}
}
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct TransactionStatusMeta { pub struct TransactionStatusMeta {
pub status: Result<()>, pub status: Result<()>,
@ -241,10 +280,10 @@ impl UiTransactionStatusMeta {
log_messages: meta.log_messages, log_messages: meta.log_messages,
pre_token_balances: meta pre_token_balances: meta
.pre_token_balances .pre_token_balances
.map(|balance| balance.into_iter().map(|balance| balance.into()).collect()), .map(|balance| balance.into_iter().map(Into::into).collect()),
post_token_balances: meta post_token_balances: meta
.post_token_balances .post_token_balances
.map(|balance| balance.into_iter().map(|balance| balance.into()).collect()), .map(|balance| balance.into_iter().map(Into::into).collect()),
rewards: meta.rewards, rewards: meta.rewards,
} }
} }
@ -260,14 +299,14 @@ impl From<TransactionStatusMeta> for UiTransactionStatusMeta {
post_balances: meta.post_balances, post_balances: meta.post_balances,
inner_instructions: meta inner_instructions: meta
.inner_instructions .inner_instructions
.map(|ixs| ixs.into_iter().map(|ix| ix.into()).collect()), .map(|ixs| ixs.into_iter().map(Into::into).collect()),
log_messages: meta.log_messages, log_messages: meta.log_messages,
pre_token_balances: meta pre_token_balances: meta
.pre_token_balances .pre_token_balances
.map(|balance| balance.into_iter().map(|balance| balance.into()).collect()), .map(|balance| balance.into_iter().map(Into::into).collect()),
post_token_balances: meta post_token_balances: meta
.post_token_balances .post_token_balances
.map(|balance| balance.into_iter().map(|balance| balance.into()).collect()), .map(|balance| balance.into_iter().map(Into::into).collect()),
rewards: meta.rewards, rewards: meta.rewards,
} }
} }
@ -358,9 +397,10 @@ pub struct ConfirmedBlock {
pub block_height: Option<u64>, pub block_height: Option<u64>,
} }
impl ConfirmedBlock { impl Encodable for ConfirmedBlock {
pub fn encode(self, encoding: UiTransactionEncoding) -> EncodedConfirmedBlock { type Encoded = EncodedConfirmedBlock;
EncodedConfirmedBlock { fn encode(self, encoding: UiTransactionEncoding) -> Self::Encoded {
Self::Encoded {
previous_blockhash: self.previous_blockhash, previous_blockhash: self.previous_blockhash,
blockhash: self.blockhash, blockhash: self.blockhash,
parent_slot: self.parent_slot, parent_slot: self.parent_slot,
@ -374,7 +414,9 @@ impl ConfirmedBlock {
block_height: self.block_height, block_height: self.block_height,
} }
} }
}
impl ConfirmedBlock {
pub fn configure( pub fn configure(
self, self,
encoding: UiTransactionEncoding, encoding: UiTransactionEncoding,
@ -431,6 +473,20 @@ pub struct EncodedConfirmedBlock {
pub block_height: Option<u64>, pub block_height: Option<u64>,
} }
impl From<UiConfirmedBlock> for EncodedConfirmedBlock {
fn from(block: UiConfirmedBlock) -> Self {
Self {
previous_blockhash: block.previous_blockhash,
blockhash: block.blockhash,
parent_slot: block.parent_slot,
transactions: block.transactions.unwrap_or_default(),
rewards: block.rewards.unwrap_or_default(),
block_time: block.block_time,
block_height: block.block_height,
}
}
}
#[derive(Debug, PartialEq, Serialize, Deserialize)] #[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct UiConfirmedBlock { pub struct UiConfirmedBlock {
@ -462,107 +518,23 @@ impl From<EncodedConfirmedBlock> for UiConfirmedBlock {
} }
} }
impl From<UiConfirmedBlock> for EncodedConfirmedBlock {
fn from(block: UiConfirmedBlock) -> Self {
Self {
previous_blockhash: block.previous_blockhash,
blockhash: block.blockhash,
parent_slot: block.parent_slot,
transactions: block.transactions.unwrap_or_default(),
rewards: block.rewards.unwrap_or_default(),
block_time: block.block_time,
block_height: block.block_height,
}
}
}
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum TransactionDetails {
Full,
Signatures,
None,
}
impl Default for TransactionDetails {
fn default() -> Self {
Self::Full
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct ConfirmedTransaction {
pub slot: Slot,
pub transaction: TransactionWithStatusMeta,
pub block_time: Option<UnixTimestamp>,
}
impl ConfirmedTransaction {
pub fn encode(self, encoding: UiTransactionEncoding) -> EncodedConfirmedTransaction {
EncodedConfirmedTransaction {
slot: self.slot,
transaction: self.transaction.encode(encoding),
block_time: self.block_time,
}
}
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct EncodedConfirmedTransaction {
pub slot: Slot,
#[serde(flatten)]
pub transaction: EncodedTransactionWithStatusMeta,
pub block_time: Option<UnixTimestamp>,
}
/// A duplicate representation of a Transaction for pretty JSON serialization
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UiTransaction {
pub signatures: Vec<String>,
pub message: UiMessage,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", untagged)]
pub enum UiMessage {
Parsed(UiParsedMessage),
Raw(UiRawMessage),
}
/// A duplicate representation of a Message, in raw format, for pretty JSON serialization
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UiRawMessage {
pub header: MessageHeader,
pub account_keys: Vec<String>,
pub recent_blockhash: String,
pub instructions: Vec<UiCompiledInstruction>,
}
/// A duplicate representation of a Message, in parsed format, for pretty JSON serialization
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UiParsedMessage {
pub account_keys: Vec<ParsedAccount>,
pub recent_blockhash: String,
pub instructions: Vec<UiInstruction>,
}
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct TransactionWithStatusMeta { pub struct TransactionWithStatusMeta {
pub transaction: Transaction, pub transaction: Transaction,
pub meta: Option<TransactionStatusMeta>, pub meta: Option<TransactionStatusMeta>,
} }
impl TransactionWithStatusMeta { impl Encodable for TransactionWithStatusMeta {
fn encode(self, encoding: UiTransactionEncoding) -> EncodedTransactionWithStatusMeta { type Encoded = EncodedTransactionWithStatusMeta;
let message = self.transaction.message(); fn encode(self, encoding: UiTransactionEncoding) -> Self::Encoded {
let meta = self.meta.map(|meta| meta.encode(encoding, message)); Self::Encoded {
EncodedTransactionWithStatusMeta { transaction: self.transaction.encode(encoding),
transaction: EncodedTransaction::encode(self.transaction, encoding), meta: self.meta.map(|meta| match encoding {
meta, UiTransactionEncoding::JsonParsed => {
UiTransactionStatusMeta::parse(meta, self.transaction.message())
}
_ => UiTransactionStatusMeta::from(meta),
}),
} }
} }
} }
@ -573,32 +545,31 @@ pub struct EncodedTransactionWithStatusMeta {
pub transaction: EncodedTransaction, pub transaction: EncodedTransaction,
pub meta: Option<UiTransactionStatusMeta>, pub meta: Option<UiTransactionStatusMeta>,
} }
#[derive(Debug, Clone, PartialEq)]
pub struct ConfirmedTransactionWithStatusMeta {
pub slot: Slot,
pub transaction: TransactionWithStatusMeta,
pub block_time: Option<UnixTimestamp>,
}
impl TransactionStatusMeta { impl Encodable for ConfirmedTransactionWithStatusMeta {
fn encode(self, encoding: UiTransactionEncoding, message: &Message) -> UiTransactionStatusMeta { type Encoded = EncodedConfirmedTransactionWithStatusMeta;
match encoding { fn encode(self, encoding: UiTransactionEncoding) -> Self::Encoded {
UiTransactionEncoding::JsonParsed => UiTransactionStatusMeta::parse(self, message), Self::Encoded {
_ => self.into(), slot: self.slot,
transaction: self.transaction.encode(encoding),
block_time: self.block_time,
} }
} }
} }
#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, Hash, PartialEq)] #[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub enum UiTransactionEncoding { pub struct EncodedConfirmedTransactionWithStatusMeta {
Binary, // Legacy. Retained for RPC backwards compatibility pub slot: Slot,
Base64, #[serde(flatten)]
Base58, pub transaction: EncodedTransactionWithStatusMeta,
Json, pub block_time: Option<UnixTimestamp>,
JsonParsed,
}
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)?;
let s = v.as_str().ok_or(fmt::Error)?;
write!(f, "{}", s)
}
} }
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
@ -609,63 +580,32 @@ pub enum EncodedTransaction {
Json(UiTransaction), Json(UiTransaction),
} }
impl EncodedTransaction { impl Encodable for &Transaction {
pub fn encode(transaction: Transaction, encoding: UiTransactionEncoding) -> Self { type Encoded = EncodedTransaction;
fn encode(self, encoding: UiTransactionEncoding) -> Self::Encoded {
match encoding { match encoding {
UiTransactionEncoding::Binary => EncodedTransaction::LegacyBinary( UiTransactionEncoding::Binary => EncodedTransaction::LegacyBinary(
bs58::encode(bincode::serialize(&transaction).unwrap()).into_string(), bs58::encode(bincode::serialize(self).unwrap()).into_string(),
), ),
UiTransactionEncoding::Base58 => EncodedTransaction::Binary( UiTransactionEncoding::Base58 => EncodedTransaction::Binary(
bs58::encode(bincode::serialize(&transaction).unwrap()).into_string(), bs58::encode(bincode::serialize(self).unwrap()).into_string(),
encoding, encoding,
), ),
UiTransactionEncoding::Base64 => EncodedTransaction::Binary( UiTransactionEncoding::Base64 => EncodedTransaction::Binary(
base64::encode(bincode::serialize(&transaction).unwrap()), base64::encode(bincode::serialize(self).unwrap()),
encoding, encoding,
), ),
UiTransactionEncoding::Json | UiTransactionEncoding::JsonParsed => { UiTransactionEncoding::Json | UiTransactionEncoding::JsonParsed => {
let message = if encoding == UiTransactionEncoding::Json {
UiMessage::Raw(UiRawMessage {
header: transaction.message.header,
account_keys: transaction
.message
.account_keys
.iter()
.map(|pubkey| pubkey.to_string())
.collect(),
recent_blockhash: transaction.message.recent_blockhash.to_string(),
instructions: transaction
.message
.instructions
.iter()
.map(|instruction| instruction.into())
.collect(),
})
} else {
UiMessage::Parsed(UiParsedMessage {
account_keys: parse_accounts(&transaction.message),
recent_blockhash: transaction.message.recent_blockhash.to_string(),
instructions: transaction
.message
.instructions
.iter()
.map(|instruction| {
UiInstruction::parse(instruction, &transaction.message)
})
.collect(),
})
};
EncodedTransaction::Json(UiTransaction { EncodedTransaction::Json(UiTransaction {
signatures: transaction signatures: self.signatures.iter().map(ToString::to_string).collect(),
.signatures message: self.message.encode(encoding),
.iter()
.map(|sig| sig.to_string())
.collect(),
message,
}) })
} }
} }
} }
}
impl EncodedTransaction {
pub fn decode(&self) -> Option<Transaction> { pub fn decode(&self) -> Option<Transaction> {
let transaction: Option<Transaction> = match self { let transaction: Option<Transaction> = match self {
EncodedTransaction::Json(_) => None, EncodedTransaction::Json(_) => None,
@ -690,6 +630,64 @@ impl EncodedTransaction {
} }
} }
/// A duplicate representation of a Transaction for pretty JSON serialization
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UiTransaction {
pub signatures: Vec<String>,
pub message: UiMessage,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", untagged)]
pub enum UiMessage {
Parsed(UiParsedMessage),
Raw(UiRawMessage),
}
impl Encodable for &Message {
type Encoded = UiMessage;
fn encode(self, encoding: UiTransactionEncoding) -> Self::Encoded {
if encoding == UiTransactionEncoding::JsonParsed {
UiMessage::Parsed(UiParsedMessage {
account_keys: parse_accounts(self),
recent_blockhash: self.recent_blockhash.to_string(),
instructions: self
.instructions
.iter()
.map(|instruction| UiInstruction::parse(instruction, self))
.collect(),
})
} else {
UiMessage::Raw(UiRawMessage {
header: self.header,
account_keys: self.account_keys.iter().map(ToString::to_string).collect(),
recent_blockhash: self.recent_blockhash.to_string(),
instructions: self.instructions.iter().map(Into::into).collect(),
})
}
}
}
/// A duplicate representation of a Message, in raw format, for pretty JSON serialization
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UiRawMessage {
pub header: MessageHeader,
pub account_keys: Vec<String>,
pub recent_blockhash: String,
pub instructions: Vec<UiCompiledInstruction>,
}
/// A duplicate representation of a Message, in parsed format, for pretty JSON serialization
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UiParsedMessage {
pub account_keys: Vec<ParsedAccount>,
pub recent_blockhash: String,
pub instructions: Vec<UiInstruction>,
}
// A serialized `Vec<TransactionByAddrInfo>` is stored in the `tx-by-addr` table. The row keys are // A serialized `Vec<TransactionByAddrInfo>` is stored in the `tx-by-addr` table. The row keys are
// the one's compliment of the slot so that rows may be listed in reverse order // the one's compliment of the slot so that rows may be listed in reverse order
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]