diff --git a/src/avg.rs b/src/avg.rs new file mode 100644 index 0000000..097b981 --- /dev/null +++ b/src/avg.rs @@ -0,0 +1,59 @@ +use std::time::Instant; + +use rayon::prelude::*; +use pow_sha256::ConfigBuilder; + +use crate::utils::get_random; + +#[derive(clap::Args, Debug, Clone)] +#[command(author, version, about, long_about = None)] +pub struct AvgGenerate { + #[arg(long)] + pub start: u32, + #[arg(long)] + pub max: u32, + #[arg(long)] + pub trials: u32, + #[arg(long)] + pub db: url::Url, +} + +impl AvgGenerate { + pub fn run(&self) { + (self.start..self.max) + .into_par_iter() + .for_each(|difficulty| { + let mut summary = String::new(); + let mut times: Vec = Vec::with_capacity(self.trials as usize); + + for _ in 0..self.trials { + let salt = get_random(32); + let string = get_random(32); + let pow_config = ConfigBuilder::default().salt(salt.clone()).build().unwrap(); + + let start = Instant::now(); + pow_config.prove_work(&string, difficulty).unwrap(); + let finish = Instant::now(); + let time_elapsed = finish.duration_since(start); + + let time = time_elapsed.as_micros(); + log::info!("Difficulty factor {difficulty} generated in {time}"); + times.push(time); + } + let mean = (times.iter().sum::() / self.trials as u128) as u32; + let simple_variance: u32 = (times + .iter() + .map(|d| { + let x = (*d as u32 - mean) as u32; + x * x + }) + .sum::()) + / (self.trials as u32 - 1); + let simple_variance: usize = (simple_variance as f32).sqrt() as usize; + let min = times.iter().min().unwrap(); + let max = times.iter().max().unwrap(); + summary = format!("{summary}\ndifficulty: {difficulty} min: {min} max: {max} mean: {mean} variance {simple_variance}"); + println!("{summary}"); + }); + } +} diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 0000000..b99d99b --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,45 @@ +use clap::Parser; + +use crate::avg::AvgGenerate; +use crate::diff::ForDiff; +use crate::gen::GenerateDeriveArgs; +use crate::migrate_pg::SledToPostgres; +use crate::print::PrintRes; + +#[derive(Parser)] // requires `derive` feature +#[command(name = "cargo")] +#[command(bin_name = "cargo")] +pub enum PoWdCli { + Generate(GenerateDeriveArgs), + PrintDB(PrintRes), + SledToPostgres(SledToPostgres), + ForDiff(ForDiff), + AvgGenerate(AvgGenerate), +} + +impl PoWdCli { + pub async fn run() { + match PoWdCli::parse() { + PoWdCli::Generate(args) => { + println!("{:?}", args); + args.run(); + } + PoWdCli::PrintDB(args) => { + println!("{:?}", args); + args.run() + } + + PoWdCli::SledToPostgres(args) => { + args.run().await; + } + PoWdCli::ForDiff(args) => { + println!("{:?}", args); + args.run(); + } + + PoWdCli::AvgGenerate(args) => { + args.run().await; + } + } + } +} diff --git a/src/diff.rs b/src/diff.rs new file mode 100644 index 0000000..6266c9c --- /dev/null +++ b/src/diff.rs @@ -0,0 +1,58 @@ +use std::time::Instant; + +use pow_sha256::ConfigBuilder; + +use crate::utils::get_random; + +#[derive(clap::Args, Debug, Clone)] +#[command(author, version, about, long_about = None)] +pub struct ForDiff { + #[arg(long)] + pub factors: String, +} + +impl ForDiff { + pub fn run(&self) { + let factors: Vec = self + .factors + .split(',') + .map(|d| d.parse::().unwrap()) + .collect(); + let mut summary = String::new(); + for difficulty in factors.iter() { + let trials = 100; + let mut times: Vec = Vec::with_capacity(trials); + + for _ in 0..trials { + let salt = get_random(32); + let string = get_random(32); + let pow_config = ConfigBuilder::default().salt(salt.clone()).build().unwrap(); + + let start = Instant::now(); + pow_config.prove_work(&string, *difficulty).unwrap(); + let finish = Instant::now(); + let time_elapsed = finish.duration_since(start); + + let time = time_elapsed.as_micros(); + log::info!("Difficulty factor {difficulty} generated in {time}"); + times.push(time); + } + let mean = (times.iter().sum::() / trials as u128) as u32; + let simple_variance: u32 = (times + .iter() + .map(|d| { + let x = (*d as u32 - mean) as u32; + x * x + }) + .sum::()) + / (trials as u32 - 1); + let simple_variance: usize = (simple_variance as f32).sqrt() as usize; + let min = times.iter().min().unwrap(); + let max = times.iter().max().unwrap(); + summary = format!("{summary}\ndifficulty: {difficulty} min: {min} max: {max} mean: {mean} variance {simple_variance}"); + } + println!("{summary}"); + } +} + + diff --git a/src/gen.rs b/src/gen.rs new file mode 100644 index 0000000..aa2d9c0 --- /dev/null +++ b/src/gen.rs @@ -0,0 +1,61 @@ +use std::time::Instant; + +use pow_sha256::ConfigBuilder; +use rayon::prelude::*; +use serde::{Deserialize, Serialize}; + +use crate::utils::get_random; + + +#[derive(clap::Args, Debug, Clone)] +#[command(author, version, about, long_about = None)] +pub struct GenerateDeriveArgs { + #[arg(long)] + pub start: u32, + #[arg(long)] + pub max: u32, + #[arg(long)] + pub db: std::path::PathBuf, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Log { + pub string: String, + pub salt: String, + pub time: u128, +} + +impl GenerateDeriveArgs { + pub fn run(&self) { + let db = sled::open(&self.db).unwrap(); + let salt = get_random(32); + let string = get_random(32); + let pow_config = ConfigBuilder::default().salt(salt.clone()).build().unwrap(); + + (self.start..self.max) + .into_par_iter() + .for_each(|difficulty| { + let start = Instant::now(); + pow_config.prove_work(&string, difficulty).unwrap(); + let finish = Instant::now(); + let time_elapsed = finish.duration_since(start); + + let time = time_elapsed.as_micros(); + if difficulty % 10000 == 0 { + log::info!("Difficulty factor {difficulty} generated in {time}"); + } + + let log = Log { + salt: salt.clone(), + time, + string: string.clone(), + }; + + db.insert( + bincode::serialize(&difficulty).unwrap(), + bincode::serialize(&log).unwrap(), + ) + .unwrap(); + }); + } +} diff --git a/src/main.rs b/src/main.rs index 1270f8c..1138094 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,221 +2,21 @@ // // SPDX-License-Identifier: AGPL-3.0-or-later -use clap::Parser; -use pow_sha256::ConfigBuilder; -use rayon::prelude::*; -use serde::{Deserialize, Serialize}; -use sqlx::postgres::PgPoolOptions; -use std::time::Duration; -use std::time::Instant; +mod avg; +mod cli; +mod db; +mod diff; +mod print; +mod gen; +mod migrate_pg; +mod utils; -#[derive(Parser)] // requires `derive` feature -#[command(name = "cargo")] -#[command(bin_name = "cargo")] -enum PoWdCli { - Generate(GenerateDeriveArgs), - PrintDB(PrintRes), - Sqlite(Sqlite), - ForDiff(ForDiff), -} +pub(crate) use gen::Log; -#[derive(clap::Args, Debug, Clone)] -#[command(author, version, about, long_about = None)] -struct ForDiff { - #[arg(long)] - factors: String, -} - -impl ForDiff { - fn run(&self) { - let factors: Vec = self - .factors - .split(',') - .map(|d| d.parse::().unwrap()) - .collect(); - let mut summary = String::new(); - for difficulty in factors.iter() { - let trials = 100; - let mut times: Vec = Vec::with_capacity(trials); - - for _ in 0..trials { - let salt = get_random(32); - let string = get_random(32); - let pow_config = ConfigBuilder::default().salt(salt.clone()).build().unwrap(); - - let start = Instant::now(); - pow_config.prove_work(&string, *difficulty).unwrap(); - let finish = Instant::now(); - let time_elapsed = finish.duration_since(start); - - let time = time_elapsed.as_micros(); - log::info!("Difficulty factor {difficulty} generated in {time}"); - times.push(time); - } - let mean = (times.iter().sum::() / trials as u128) as u32; - let simple_variance: u32 = (times - .iter() - .map(|d| { - let x = (*d as u32 - mean) as u32; - x * x - }) - .sum::()) - / (trials as u32 - 1); - let simple_variance: usize = ((simple_variance as f32).sqrt() as usize); - let min = times.iter().min().unwrap(); - let max = times.iter().max().unwrap(); - summary = format!("{summary}\ndifficulty: {difficulty} min: {min} max: {max} mean: {mean} variance {simple_variance}"); - } - println!("{summary}"); - } -} - -#[derive(clap::Args, Debug, Clone)] -#[command(author, version, about, long_about = None)] -struct GenerateDeriveArgs { - #[arg(long)] - start: u32, - #[arg(long)] - max: u32, - #[arg(long)] - db: std::path::PathBuf, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -struct Log { - string: String, - salt: String, - time: u128, -} - -impl GenerateDeriveArgs { - fn run(&self) { - let db = sled::open(&self.db).unwrap(); - let salt = get_random(32); - let string = get_random(32); - let pow_config = ConfigBuilder::default().salt(salt.clone()).build().unwrap(); - - (self.start..self.max) - .into_par_iter() - .for_each(|difficulty| { - let start = Instant::now(); - pow_config.prove_work(&string, difficulty).unwrap(); - let finish = Instant::now(); - let time_elapsed = finish.duration_since(start); - - let time = time_elapsed.as_micros(); - if difficulty % 10000 == 0 { - log::info!("Difficulty factor {difficulty} generated in {time}"); - } - - let log = Log { - salt: salt.clone(), - time, - string: string.clone(), - }; - - db.insert( - bincode::serialize(&difficulty).unwrap(), - bincode::serialize(&log).unwrap(), - ) - .unwrap(); - }); - } -} - -#[derive(clap::Args, Debug, Clone)] -#[command(author, version, about, long_about = None)] -struct PrintRes { - #[arg(long)] - db: std::path::PathBuf, -} - -#[derive(clap::Args, Debug, Clone)] -#[command(author, version, about, long_about = None)] -struct Sqlite { - #[arg(long)] - sled: std::path::PathBuf, - #[arg(long)] - sqlite: url::Url, -} - -#[derive(clap::Args, Debug, Clone)] -#[command(author, version, about, long_about = None)] -struct Plot { - #[arg(long)] - graph: std::path::PathBuf, - #[arg(long)] - sqlite: url::Url, -} #[actix_rt::main] async fn main() { std::env::set_var("RUST_LOG", "INFO"); pretty_env_logger::init(); - match PoWdCli::parse() { - PoWdCli::Generate(args) => { - println!("{:?}", args); - args.run(); - } - PoWdCli::PrintDB(args) => { - println!("{:?}", args); - let db = sled::open(args.db).unwrap(); - for entry in db.iter() { - let (difficulty, entry) = entry.unwrap(); - let log: Log = bincode::deserialize::(&entry[..]).unwrap(); - let difficulty: u32 = bincode::deserialize::(&difficulty).unwrap(); - println!("{difficulty}: {}", log.time); - } - } - - PoWdCli::Sqlite(args) => { - let sqlite_db = PgPoolOptions::new() - .max_connections(1) - .acquire_timeout(Duration::new(1000, 0)) - .idle_timeout(Duration::new(1000, 0)) - .connect(&args.sqlite.to_string()) - .await - .unwrap(); - - sqlx::migrate!("./migrations/") - .run(&sqlite_db) - .await - .unwrap(); - - println!("{:?}", args); - let sled_db = sled::open(args.sled).unwrap(); - for entry in sled_db.iter() { - let (difficulty, entry) = entry.unwrap(); - let log: Log = bincode::deserialize::(&entry[..]).unwrap(); - let difficulty: u32 = bincode::deserialize::(&difficulty).unwrap(); - - let time = log.time as i32; - sqlx::query!( - "INSERT INTO logs (string, salt, time, difficulty) VALUES ($1, $2, $3, $4) ON CONFLICT(difficulty) DO NOTHING;", - log.string, - log.salt, - time, - difficulty as i32, - ).execute(&sqlite_db).await.unwrap(); - } - } - PoWdCli::ForDiff(args) => { - println!("{:?}", args); - args.run(); - } - } -} - -pub fn get_random(len: usize) -> String { - use std::iter; - - use rand::{distributions::Alphanumeric, rngs::ThreadRng, thread_rng, Rng}; - - let mut rng: ThreadRng = thread_rng(); - - iter::repeat(()) - .map(|()| rng.sample(Alphanumeric)) - .map(char::from) - .take(len) - .collect::() + cli::PoWdCli::run().await; } diff --git a/src/migrate_pg.rs b/src/migrate_pg.rs new file mode 100644 index 0000000..018ce30 --- /dev/null +++ b/src/migrate_pg.rs @@ -0,0 +1,25 @@ +use crate::db; +use crate::Log; + +#[derive(clap::Args, Debug, Clone)] +#[command(author, version, about, long_about = None)] +pub struct SledToPostgres { + #[arg(long)] + pub sled: std::path::PathBuf, + #[arg(long)] + pub pg: url::Url, +} + +impl SledToPostgres { + pub async fn run(&self) { + let pool = db::DB::new(&self.pg, 1).await; + let sled_db = sled::open(&self.sled).unwrap(); + for entry in sled_db.iter() { + let (difficulty, entry) = entry.unwrap(); + let log: Log = bincode::deserialize::(&entry[..]).unwrap(); + let difficulty: u32 = bincode::deserialize::(&difficulty).unwrap(); + + pool.write_log(&log, difficulty).await; + } + } +} diff --git a/src/print.rs b/src/print.rs new file mode 100644 index 0000000..2f8ae89 --- /dev/null +++ b/src/print.rs @@ -0,0 +1,20 @@ +use crate::Log; + +#[derive(clap::Args, Debug, Clone)] +#[command(author, version, about, long_about = None)] +pub struct PrintRes { + #[arg(long)] + pub db: std::path::PathBuf, +} + +impl PrintRes { + pub fn run(&self) { + let db = sled::open(&self.db).unwrap(); + for entry in db.iter() { + let (difficulty, entry) = entry.unwrap(); + let log: Log = bincode::deserialize::(&entry[..]).unwrap(); + let difficulty: u32 = bincode::deserialize::(&difficulty).unwrap(); + println!("{difficulty}: {}", log.time); + } + } +} diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..138d6ad --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,13 @@ +pub fn get_random(len: usize) -> String { + use std::iter; + + use rand::{distributions::Alphanumeric, rngs::ThreadRng, thread_rng, Rng}; + + let mut rng: ThreadRng = thread_rng(); + + iter::repeat(()) + .map(|()| rng.sample(Alphanumeric)) + .map(char::from) + .take(len) + .collect::() +}