#[macro_use] extern crate serde_derive; use bincode; use solana_sdk::{ clock::Slot, message::MessageHeader, transaction::{Result, Transaction, TransactionError}, }; /// A duplicate representation of a Message for pretty JSON serialization #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct RpcCompiledInstruction { pub program_id_index: u8, pub accounts: Vec, pub data: String, } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct TransactionStatusMeta { pub status: Result<()>, pub fee: u64, pub pre_balances: Vec, pub post_balances: Vec, } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct RpcTransactionStatusMeta { pub err: Option, pub status: Result<()>, // This field is deprecated. See https://github.com/solana-labs/solana/issues/9302 pub fee: u64, pub pre_balances: Vec, pub post_balances: Vec, } impl From for RpcTransactionStatusMeta { fn from(meta: TransactionStatusMeta) -> Self { Self { err: meta.status.clone().err(), status: meta.status, fee: meta.fee, pre_balances: meta.pre_balances, post_balances: meta.post_balances, } } } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct TransactionStatus { pub slot: Slot, pub confirmations: Option, pub status: Result<()>, pub err: Option, } #[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct Reward { pub pubkey: String, pub lamports: i64, } pub type Rewards = Vec; #[derive(Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ConfirmedBlock { pub previous_blockhash: String, pub blockhash: String, pub parent_slot: Slot, pub transactions: Vec, pub rewards: Rewards, } /// A duplicate representation of a Transaction for pretty JSON serialization #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct RpcTransaction { pub signatures: Vec, pub message: RpcMessage, } /// A duplicate representation of a Message for pretty JSON serialization #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct RpcMessage { pub header: MessageHeader, pub account_keys: Vec, pub recent_blockhash: String, pub instructions: Vec, } #[derive(Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct TransactionWithStatusMeta { pub transaction: EncodedTransaction, pub meta: Option, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] #[serde(rename_all = "camelCase")] pub enum TransactionEncoding { Binary, Json, } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase", untagged)] pub enum EncodedTransaction { Binary(String), Json(RpcTransaction), } impl EncodedTransaction { pub fn encode(transaction: Transaction, encoding: TransactionEncoding) -> Self { if encoding == TransactionEncoding::Json { EncodedTransaction::Json(RpcTransaction { signatures: transaction .signatures .iter() .map(|sig| sig.to_string()) .collect(), message: RpcMessage { 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| RpcCompiledInstruction { program_id_index: instruction.program_id_index, accounts: instruction.accounts.clone(), data: bs58::encode(instruction.data.clone()).into_string(), }) .collect(), }, }) } else { EncodedTransaction::Binary( bs58::encode(bincode::serialize(&transaction).unwrap()).into_string(), ) } } pub fn decode(&self) -> Option { match self { EncodedTransaction::Json(_) => None, EncodedTransaction::Binary(blob) => bs58::decode(blob) .into_vec() .ok() .and_then(|bytes| bincode::deserialize(&bytes).ok()), } } }