2020-02-29 11:39:07 -05:00
|
|
|
use crate::cli::SettingType;
|
2019-08-08 11:13:06 -06:00
|
|
|
use console::style;
|
2020-05-31 23:00:51 -07:00
|
|
|
use indicatif::{ProgressBar, ProgressStyle};
|
2020-04-15 20:51:05 -07:00
|
|
|
use solana_sdk::{
|
|
|
|
hash::Hash, native_token::lamports_to_sol, program_utils::limited_deserialize,
|
|
|
|
transaction::Transaction,
|
|
|
|
};
|
|
|
|
use solana_transaction_status::RpcTransactionStatusMeta;
|
2020-05-01 17:48:22 -07:00
|
|
|
use std::{fmt, io};
|
2019-08-08 11:13:06 -06:00
|
|
|
|
|
|
|
// 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);
|
|
|
|
}
|
2019-09-05 10:14:23 -07:00
|
|
|
|
2020-04-14 13:10:25 -06:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2020-02-29 11:39:07 -05:00
|
|
|
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)",
|
2019-09-05 10:14:23 -07:00
|
|
|
};
|
2020-02-29 11:39:07 -05:00
|
|
|
|
|
|
|
println!(
|
|
|
|
"{} {} {}",
|
|
|
|
style(name).bold(),
|
|
|
|
style(value),
|
|
|
|
style(description).italic(),
|
|
|
|
);
|
2019-09-05 10:14:23 -07:00
|
|
|
}
|
2019-11-25 21:09:57 -08:00
|
|
|
|
2020-03-18 21:49:38 -06:00
|
|
|
pub fn println_signers(
|
|
|
|
blockhash: &Hash,
|
|
|
|
signers: &[String],
|
|
|
|
absent: &[String],
|
|
|
|
bad_sig: &[String],
|
|
|
|
) {
|
2019-11-25 21:09:57 -08:00
|
|
|
println!();
|
2020-03-18 21:49:38 -06:00
|
|
|
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))
|
|
|
|
}
|
2019-11-25 21:09:57 -08:00
|
|
|
println!();
|
|
|
|
}
|
2020-04-15 20:51:05 -07:00
|
|
|
|
2020-05-01 17:48:22 -07:00
|
|
|
pub fn write_transaction<W: io::Write>(
|
|
|
|
w: &mut W,
|
2020-04-15 20:51:05 -07:00
|
|
|
transaction: &Transaction,
|
|
|
|
transaction_status: &Option<RpcTransactionStatusMeta>,
|
|
|
|
prefix: &str,
|
2020-05-01 17:48:22 -07:00
|
|
|
) -> io::Result<()> {
|
2020-04-15 20:51:05 -07:00
|
|
|
let message = &transaction.message;
|
2020-05-01 17:48:22 -07:00
|
|
|
writeln!(
|
|
|
|
w,
|
|
|
|
"{}Recent Blockhash: {:?}",
|
|
|
|
prefix, message.recent_blockhash
|
|
|
|
)?;
|
2020-04-15 20:51:05 -07:00
|
|
|
for (signature_index, signature) in transaction.signatures.iter().enumerate() {
|
2020-05-01 17:48:22 -07:00
|
|
|
writeln!(
|
|
|
|
w,
|
|
|
|
"{}Signature {}: {:?}",
|
|
|
|
prefix, signature_index, signature
|
|
|
|
)?;
|
2020-04-15 20:51:05 -07:00
|
|
|
}
|
2020-05-01 17:48:22 -07:00
|
|
|
writeln!(w, "{}{:?}", prefix, message.header)?;
|
2020-04-15 20:51:05 -07:00
|
|
|
for (account_index, account) in message.account_keys.iter().enumerate() {
|
2020-05-01 17:48:22 -07:00
|
|
|
writeln!(w, "{}Account {}: {:?}", prefix, account_index, account)?;
|
2020-04-15 20:51:05 -07:00
|
|
|
}
|
|
|
|
for (instruction_index, instruction) in message.instructions.iter().enumerate() {
|
|
|
|
let program_pubkey = message.account_keys[instruction.program_id_index as usize];
|
2020-05-01 17:48:22 -07:00
|
|
|
writeln!(w, "{}Instruction {}", prefix, instruction_index)?;
|
|
|
|
writeln!(
|
|
|
|
w,
|
2020-04-15 20:51:05 -07:00
|
|
|
"{} Program: {} ({})",
|
|
|
|
prefix, program_pubkey, instruction.program_id_index
|
2020-05-01 17:48:22 -07:00
|
|
|
)?;
|
2020-04-15 20:51:05 -07:00
|
|
|
for (account_index, account) in instruction.accounts.iter().enumerate() {
|
|
|
|
let account_pubkey = message.account_keys[*account as usize];
|
2020-05-01 17:48:22 -07:00
|
|
|
writeln!(
|
|
|
|
w,
|
2020-04-15 20:51:05 -07:00
|
|
|
"{} Account {}: {} ({})",
|
|
|
|
prefix, account_index, account_pubkey, account
|
2020-05-01 17:48:22 -07:00
|
|
|
)?;
|
2020-04-15 20:51:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2020-05-01 17:48:22 -07:00
|
|
|
writeln!(w, "{} {:?}", prefix, vote_instruction)?;
|
2020-04-15 20:51:05 -07:00
|
|
|
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)
|
|
|
|
{
|
2020-05-01 17:48:22 -07:00
|
|
|
writeln!(w, "{} {:?}", prefix, stake_instruction)?;
|
2020-04-15 20:51:05 -07:00
|
|
|
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)
|
|
|
|
{
|
2020-05-01 17:48:22 -07:00
|
|
|
writeln!(w, "{} {:?}", prefix, system_instruction)?;
|
2020-04-15 20:51:05 -07:00
|
|
|
raw = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if raw {
|
2020-05-01 17:48:22 -07:00
|
|
|
writeln!(w, "{} Data: {:?}", prefix, instruction.data)?;
|
2020-04-15 20:51:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(transaction_status) = transaction_status {
|
2020-05-01 17:48:22 -07:00
|
|
|
writeln!(
|
|
|
|
w,
|
2020-04-15 20:51:05 -07:00
|
|
|
"{}Status: {}",
|
|
|
|
prefix,
|
|
|
|
match &transaction_status.status {
|
|
|
|
Ok(_) => "Ok".into(),
|
|
|
|
Err(err) => err.to_string(),
|
|
|
|
}
|
2020-05-01 17:48:22 -07:00
|
|
|
)?;
|
2020-05-05 22:10:41 -07:00
|
|
|
writeln!(
|
|
|
|
w,
|
|
|
|
"{} Fee: {} SOL",
|
|
|
|
prefix,
|
|
|
|
lamports_to_sol(transaction_status.fee)
|
|
|
|
)?;
|
2020-04-15 20:51:05 -07:00
|
|
|
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 {
|
2020-05-01 17:48:22 -07:00
|
|
|
writeln!(
|
|
|
|
w,
|
2020-04-15 20:51:05 -07:00
|
|
|
"{} Account {} balance: {} SOL",
|
|
|
|
prefix,
|
|
|
|
i,
|
|
|
|
lamports_to_sol(*pre)
|
2020-05-01 17:48:22 -07:00
|
|
|
)?;
|
2020-04-15 20:51:05 -07:00
|
|
|
} else {
|
2020-05-01 17:48:22 -07:00
|
|
|
writeln!(
|
|
|
|
w,
|
2020-04-15 20:51:05 -07:00
|
|
|
"{} Account {} balance: {} SOL -> {} SOL",
|
|
|
|
prefix,
|
|
|
|
i,
|
|
|
|
lamports_to_sol(*pre),
|
|
|
|
lamports_to_sol(*post)
|
2020-05-01 17:48:22 -07:00
|
|
|
)?;
|
2020-04-15 20:51:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2020-05-01 17:48:22 -07:00
|
|
|
writeln!(w, "{}Status: Unavailable", prefix)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn println_transaction(
|
|
|
|
transaction: &Transaction,
|
|
|
|
transaction_status: &Option<RpcTransactionStatusMeta>,
|
|
|
|
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);
|
|
|
|
}
|
2020-04-15 20:51:05 -07:00
|
|
|
}
|
|
|
|
}
|
2020-05-31 23:00:51 -07:00
|
|
|
|
|
|
|
/// Creates a new process bar for processing that will take an unknown amount of time
|
|
|
|
pub fn new_spinner_progress_bar() -> ProgressBar {
|
|
|
|
let progress_bar = ProgressBar::new(42);
|
|
|
|
progress_bar
|
|
|
|
.set_style(ProgressStyle::default_spinner().template("{spinner:.green} {wide_msg}"));
|
|
|
|
progress_bar.enable_steady_tick(100);
|
|
|
|
progress_bar
|
|
|
|
}
|