use crate::cli::SettingType; use console::style; use solana_sdk::{ hash::Hash, native_token::lamports_to_sol, program_utils::limited_deserialize, transaction::Transaction, }; use solana_transaction_status::RpcTransactionStatusMeta; use std::{fmt, io}; // Pretty print a "name value" pub fn println_name_value(name: &str, value: &str) { let styled_value = if value == "" { style("(not set)").italic() } else { style(value) }; println!("{} {}", style(name).bold(), styled_value); } pub fn writeln_name_value(f: &mut fmt::Formatter, name: &str, value: &str) -> fmt::Result { let styled_value = if value == "" { style("(not set)").italic() } else { style(value) }; writeln!(f, "{} {}", style(name).bold(), styled_value) } pub fn println_name_value_or(name: &str, value: &str, setting_type: SettingType) { let description = match setting_type { SettingType::Explicit => "", SettingType::Computed => "(computed)", SettingType::SystemDefault => "(default)", }; println!( "{} {} {}", style(name).bold(), style(value), style(description).italic(), ); } pub fn println_signers( blockhash: &Hash, signers: &[String], absent: &[String], bad_sig: &[String], ) { println!(); println!("Blockhash: {}", blockhash); if !signers.is_empty() { println!("Signers (Pubkey=Signature):"); signers.iter().for_each(|signer| println!(" {}", signer)) } if !absent.is_empty() { println!("Absent Signers (Pubkey):"); absent.iter().for_each(|pubkey| println!(" {}", pubkey)) } if !bad_sig.is_empty() { println!("Bad Signatures (Pubkey):"); bad_sig.iter().for_each(|pubkey| println!(" {}", pubkey)) } println!(); } pub fn write_transaction( w: &mut W, transaction: &Transaction, transaction_status: &Option, prefix: &str, ) -> io::Result<()> { let message = &transaction.message; writeln!( w, "{}Recent Blockhash: {:?}", prefix, message.recent_blockhash )?; for (signature_index, signature) in transaction.signatures.iter().enumerate() { writeln!( w, "{}Signature {}: {:?}", prefix, signature_index, signature )?; } writeln!(w, "{}{:?}", prefix, message.header)?; for (account_index, account) in message.account_keys.iter().enumerate() { writeln!(w, "{}Account {}: {:?}", prefix, account_index, account)?; } for (instruction_index, instruction) in message.instructions.iter().enumerate() { let program_pubkey = message.account_keys[instruction.program_id_index as usize]; writeln!(w, "{}Instruction {}", prefix, instruction_index)?; writeln!( w, "{} Program: {} ({})", prefix, program_pubkey, instruction.program_id_index )?; for (account_index, account) in instruction.accounts.iter().enumerate() { let account_pubkey = message.account_keys[*account as usize]; writeln!( w, "{} Account {}: {} ({})", prefix, account_index, account_pubkey, account )?; } let mut raw = true; if program_pubkey == solana_vote_program::id() { if let Ok(vote_instruction) = limited_deserialize::< solana_vote_program::vote_instruction::VoteInstruction, >(&instruction.data) { writeln!(w, "{} {:?}", prefix, vote_instruction)?; raw = false; } } else if program_pubkey == solana_stake_program::id() { if let Ok(stake_instruction) = limited_deserialize::< solana_stake_program::stake_instruction::StakeInstruction, >(&instruction.data) { writeln!(w, "{} {:?}", prefix, stake_instruction)?; raw = false; } } else if program_pubkey == solana_sdk::system_program::id() { if let Ok(system_instruction) = limited_deserialize::< solana_sdk::system_instruction::SystemInstruction, >(&instruction.data) { writeln!(w, "{} {:?}", prefix, system_instruction)?; raw = false; } } if raw { writeln!(w, "{} Data: {:?}", prefix, instruction.data)?; } } if let Some(transaction_status) = transaction_status { writeln!( w, "{}Status: {}", prefix, match &transaction_status.status { Ok(_) => "Ok".into(), Err(err) => err.to_string(), } )?; writeln!( w, "{} Fee: {} SOL", prefix, lamports_to_sol(transaction_status.fee) )?; assert_eq!( transaction_status.pre_balances.len(), transaction_status.post_balances.len() ); for (i, (pre, post)) in transaction_status .pre_balances .iter() .zip(transaction_status.post_balances.iter()) .enumerate() { if pre == post { writeln!( w, "{} Account {} balance: {} SOL", prefix, i, lamports_to_sol(*pre) )?; } else { writeln!( w, "{} Account {} balance: {} SOL -> {} SOL", prefix, i, lamports_to_sol(*pre), lamports_to_sol(*post) )?; } } } else { writeln!(w, "{}Status: Unavailable", prefix)?; } Ok(()) } pub fn println_transaction( transaction: &Transaction, transaction_status: &Option, prefix: &str, ) { let mut w = Vec::new(); if write_transaction(&mut w, transaction, transaction_status, prefix).is_ok() { if let Ok(s) = String::from_utf8(w) { print!("{}", s); } } }