Skip to content

Commit

Permalink
Add a CSV printer (solana-labs#23)
Browse files Browse the repository at this point in the history
  • Loading branch information
garious committed May 7, 2020
1 parent 5258447 commit 6f288be
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 3 deletions.
83 changes: 83 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Debug unit tests in library 'solana-tokens'",
"cargo": {
"args": [
"test",
"--no-run",
"--lib",
"--package=solana-tokens"
],
"filter": {
"name": "solana-tokens",
"kind": "lib"
}
},
"args": [],
"cwd": "${workspaceFolder}"
},
{
"type": "lldb",
"request": "launch",
"name": "Debug executable 'solana-tokens'",
"cargo": {
"args": [
"build",
"--bin=solana-tokens",
"--package=solana-tokens"
],
"filter": {
"name": "solana-tokens",
"kind": "bin"
}
},
"args": [],
"cwd": "${workspaceFolder}"
},
{
"type": "lldb",
"request": "launch",
"name": "Debug unit tests in executable 'solana-tokens'",
"cargo": {
"args": [
"test",
"--no-run",
"--bin=solana-tokens",
"--package=solana-tokens"
],
"filter": {
"name": "solana-tokens",
"kind": "bin"
}
},
"args": [],
"cwd": "${workspaceFolder}"
},
{
"type": "lldb",
"request": "launch",
"name": "Debug integration test 'tokens'",
"cargo": {
"args": [
"test",
"--no-run",
"--test=tokens",
"--package=solana-tokens"
],
"filter": {
"name": "tokens",
"kind": "test"
}
},
"args": [],
"cwd": "${workspaceFolder}"
}
]
}
32 changes: 31 additions & 1 deletion src/arg_parser.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::args::{Args, BalancesArgs, Command, DistributeStakeArgs, DistributeTokensArgs};
use crate::args::{
Args, BalancesArgs, Command, DistributeStakeArgs, DistributeTokensArgs, PrintDbArgs,
};
use clap::{value_t, value_t_or_exit, App, Arg, ArgMatches, SubCommand};
use solana_clap_utils::input_validators::{is_valid_pubkey, is_valid_signer};
use solana_cli_config::CONFIG_FILE;
Expand Down Expand Up @@ -189,6 +191,26 @@ where
.help("Dollars per SOL"),
),
)
.subcommand(
SubCommand::with_name("print-database")
.about("Print the database to a CSV file")
.arg(
Arg::with_name("transactions_db")
.required(true)
.index(1)
.takes_value(true)
.value_name("FILE")
.help("Transactions database file"),
)
.arg(
Arg::with_name("output_path")
.long("output-path")
.required(true)
.takes_value(true)
.value_name("FILE")
.help("Output file"),
),
)
.get_matches_from(args)
}

Expand Down Expand Up @@ -228,6 +250,13 @@ fn parse_balances_args(matches: &ArgMatches<'_>) -> BalancesArgs {
}
}

fn parse_print_db_args(matches: &ArgMatches<'_>) -> PrintDbArgs {
PrintDbArgs {
transactions_db: value_t_or_exit!(matches, "transactions_db", String),
output_path: value_t_or_exit!(matches, "output_path", String),
}
}

pub fn parse_args<I, T>(args: I) -> Args<String, String>
where
I: IntoIterator<Item = T>,
Expand All @@ -245,6 +274,7 @@ where
Command::DistributeStake(parse_distribute_stake_args(matches))
}
("balances", Some(matches)) => Command::Balances(parse_balances_args(matches)),
("print-database", Some(matches)) => Command::PrintDb(parse_print_db_args(matches)),
_ => {
eprintln!("{}", matches.usage());
exit(1);
Expand Down
7 changes: 7 additions & 0 deletions src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,16 @@ pub struct BalancesArgs {
pub dollars_per_sol: Option<f64>,
}

pub struct PrintDbArgs {
pub transactions_db: String,
pub output_path: String,
}

pub enum Command<P, K> {
DistributeTokens(DistributeTokensArgs<K>),
DistributeStake(DistributeStakeArgs<P, K>),
Balances(BalancesArgs),
PrintDb(PrintDbArgs),
}

pub struct Args<P, K> {
Expand Down Expand Up @@ -106,5 +112,6 @@ pub fn resolve_command(
Ok(Command::DistributeStake(resolved_args))
}
Command::Balances(args) => Ok(Command::Balances(args)),
Command::PrintDb(args) => Ok(Command::PrintDb(args)),
}
}
3 changes: 3 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ fn main() -> Result<(), Box<dyn Error>> {
Command::Balances(args) => {
tokens::process_balances(&thin_client, &args)?;
}
Command::PrintDb(args) => {
tokens::process_print_db(&args)?;
}
}
Ok(())
}
58 changes: 56 additions & 2 deletions src/tokens.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::args::{BalancesArgs, DistributeStakeArgs, DistributeTokensArgs};
use crate::args::{BalancesArgs, DistributeStakeArgs, DistributeTokensArgs, PrintDbArgs};
use crate::thin_client::{Client, ThinClient};
use console::style;
use csv::{ReaderBuilder, Trim};
Expand All @@ -18,7 +18,7 @@ use solana_stake_program::{
stake_state::{Authorized, Lockup, StakeAuthorize},
};
use solana_transaction_status::TransactionStatus;
use std::{cmp, path::Path, process};
use std::{cmp, io, path::Path, process};

#[derive(Serialize, Deserialize, Debug, Clone)]
struct Bid {
Expand All @@ -40,8 +40,19 @@ struct TransactionInfo {
finalized: bool,
}

#[derive(Serialize, Deserialize, Debug, Default, PartialEq)]
struct SignedTransactionInfo {
recipient: String,
amount: f64,
new_stake_account_address: String,
finalized: bool,
signature: String,
}

#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("I/O error")]
IoError(#[from] io::Error),
#[error("CSV error")]
CsvError(#[from] csv::Error),
#[error("PickleDb error")]
Expand Down Expand Up @@ -256,6 +267,21 @@ fn open_db(path: &str, dry_run: bool) -> Result<PickleDb, pickledb::error::Error
}
}

pub fn print_db<P: AsRef<Path>>(db: &PickleDb, path: &P) -> Result<(), io::Error> {
let mut wtr = csv::WriterBuilder::new().from_path(path).unwrap();
for (signature, info) in read_transaction_data(db) {
let signed_info = SignedTransactionInfo {
recipient: info.recipient,
amount: info.amount,
new_stake_account_address: info.new_stake_account_address,
finalized: info.finalized,
signature: signature.to_string(),
};
wtr.serialize(&signed_info)?;
}
wtr.flush()
}

fn read_transaction_data(db: &PickleDb) -> Vec<(Signature, TransactionInfo)> {
db.iter()
.map(|kv| {
Expand Down Expand Up @@ -557,6 +583,12 @@ pub fn process_balances<T: Client>(
Ok(())
}

pub fn process_print_db(args: &PrintDbArgs) -> Result<(), Error> {
let db = open_db(&args.transactions_db, true)?;
print_db(&db, &args.output_path)?;
Ok(())
}

use solana_sdk::{pubkey::Pubkey, signature::Keypair};
use tempfile::{tempdir, NamedTempFile};
pub fn test_process_distribute_tokens_with_client<C: Client>(client: C, sender_keypair: Keypair) {
Expand Down Expand Up @@ -917,4 +949,26 @@ mod tests {
transaction_info
);
}

#[test]
fn test_print_db() {
let mut db =
PickleDb::new_yaml(NamedTempFile::new().unwrap(), PickleDbDumpPolicy::NeverDump);
let signature = Signature::default();
let transaction_info = TransactionInfo::default();
db.set(&signature.to_string(), &transaction_info).unwrap();

let csv_file = NamedTempFile::new().unwrap();
print_db(&db, &csv_file).unwrap();

let mut rdr = ReaderBuilder::new().trim(Trim::All).from_reader(csv_file);
let signed_infos: Vec<SignedTransactionInfo> =
rdr.deserialize().map(|entry| entry.unwrap()).collect();

let signed_info = SignedTransactionInfo {
signature: Signature::default().to_string(),
..SignedTransactionInfo::default()
};
assert_eq!(signed_infos, vec![signed_info]);
}
}

0 comments on commit 6f288be

Please sign in to comment.