From 993ae2885210dfb7b9a6a7b8457ef0730fb83050 Mon Sep 17 00:00:00 2001 From: Hrik Bhowal Date: Thu, 1 Feb 2024 14:08:20 -0800 Subject: [PATCH] feat: search by total zeros --- src/cli.rs | 44 +++++++++---- src/kernels/keccak256.cl | 8 +++ src/lib.rs | 135 ++++++++++++++++++++++++++++----------- src/main.rs | 73 ++++++++++++++------- 4 files changed, 189 insertions(+), 71 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index 7c60868..2740ca8 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,4 +1,4 @@ -use clap::{command, ArgGroup, Args, Parser, Subcommand}; +use clap::{command, ArgAction, ArgGroup, Args, Parser, Subcommand}; #[derive(Parser)] #[command(arg_required_else_help = true)] @@ -9,7 +9,8 @@ pub struct Cli { } #[derive(Args)] -#[clap(group = ArgGroup::new("mining-pattern").required(true))] +#[clap(group = ArgGroup::new("search-criteria").multiple(true).required(true))] +#[clap(group = ArgGroup::new("zeros-threshold"))] pub struct CliArgs { #[arg( id = "factory", @@ -29,7 +30,7 @@ pub struct CliArgs { long_help = "Set the GPU device ID.", help_heading = "Crunching options" )] - pub gpu_device_id: String, + pub gpu_device_id: u8, #[arg( id = "caller", @@ -48,27 +49,48 @@ pub struct CliArgs { help_heading = "Crunching options", visible_alias = "crp" )] - pub chain_id: Option, + pub chain_id: Option, #[arg( id = "zeros", long = "leading", short = 'z', - group = "mining-pattern", - long_help = "Minimum number of leading zero bytes. Cannot be used in combination with -m.\n\nExample: -z 4.", + group = "search-criteria", + long_help = "Minimum number of leading zero bytes. Cannot be used in combination with --matching.\n\nExample: --leading 4.", help_heading = "Crunching options" )] - pub zeros: Option, + pub zeros: Option, + + #[arg( + id = "total", + long = "total", + short = 't', + group = "search-criteria", + long_help = "Total number of zero bytes. If used in conjunction with --leading, search criteria will be both thresholds. Pass --either to search for either threshold.\n\nExample: --total 32.", + help_heading = "Crunching options" + )] + pub total: Option, + + #[arg( + id = "either", + long = "either", + long_help = "Search for either threshold. Must be used with --leading and --total.", + requires_all = &["zeros", "total"], + action = ArgAction::SetTrue, + help_heading = "Crunching options" + )] + pub either: bool, #[arg( id = "pattern", long = "matching", short = 'm', - group = "mining-pattern", - long_help = "Matching pattern for the contract address. Cannot be used in combination with -z.\n\nExample: -m ba5edXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXba5ed.", - help_heading = "Crunching options" + group = "search-criteria", + long_help = "Matching pattern for the contract address. Cannot be used in combination with --leading.\n\nExample: --matching ba5edXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXba5ed.", + help_heading = "Crunching options", + conflicts_with_all = &["zeros", "total"] )] - pub pattern: Option, + pub pattern: Option>, #[arg( id = "output", diff --git a/src/kernels/keccak256.cl b/src/kernels/keccak256.cl index 6798835..45fb49a 100644 --- a/src/kernels/keccak256.cl +++ b/src/kernels/keccak256.cl @@ -215,6 +215,14 @@ static inline bool isMatching(uchar const *d) return true; } +#define hasTotal(d) ( \ + (!(d[0])) + (!(d[1])) + (!(d[2])) + (!(d[3])) + \ + (!(d[4])) + (!(d[5])) + (!(d[6])) + (!(d[7])) + \ + (!(d[8])) + (!(d[9])) + (!(d[10])) + (!(d[11])) + \ + (!(d[12])) + (!(d[13])) + (!(d[14])) + (!(d[15])) + \ + (!(d[16])) + (!(d[17])) + (!(d[18])) + (!(d[19])) \ +>= TOTAL_ZEROES) + #if LEADING_ZEROES == 8 #define hasLeading(d) (!(((uint*)d)[0]) && !(((uint*)d)[1])) #elif LEADING_ZEROES == 7 diff --git a/src/lib.rs b/src/lib.rs index 4d260d8..83e559f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,8 +34,23 @@ pub enum CreateXVariant { } pub enum RewardVariant { - LeadingZeros { leading_zeros_threshold: u8 }, - Matching { pattern: String }, + LeadingZeros { + zeros_threshold: u8, + }, + TotalZeros { + zeros_threshold: u8, + }, + LeadingAndTotalZeros { + leading_zeros_threshold: u8, + total_zeros_threshold: u8, + }, + LeadingOrTotalZeros { + leading_zeros_threshold: u8, + total_zeros_threshold: u8, + }, + Matching { + pattern: Box, + }, } pub enum SaltVariant { @@ -52,32 +67,25 @@ pub enum SaltVariant { Random, } -pub struct Config { +pub struct Config<'a> { gpu_device: u8, factory_address: [u8; 20], salt_variant: SaltVariant, variant: CreateXVariant, reward: RewardVariant, - output: String, + output: &'a str, } -impl Config { +impl<'a> Config<'a> { pub fn new( - gpu_device: &str, - factory_address: &String, - calling_address: Option<&String>, - chain_id: Option<&String>, - init_code_hash: Option<&String>, + gpu_device: u8, + factory_address: &str, + calling_address: Option<&str>, + chain_id: Option, + init_code_hash: Option<&str>, reward: RewardVariant, - output: &String, + output: &'a str, ) -> Result { - let chain_id = chain_id.map(|chain_id| { - chain_id - // Chain ids are technically 32 bytes, but 8 bytes should be enough - .parse::() - .expect("could not parse chain id argument as u64") - }); - // convert main arguments from hex string to vector of bytes let factory_address_vec = hex::decode(factory_address).expect("could not decode factory address argument"); @@ -110,21 +118,21 @@ impl Config { None => CreateXVariant::Create3 {}, }; - // convert gpu argument to u8 - let Ok(gpu_device) = gpu_device.parse::() else { - return Err("invalid gpu device value"); - }; - match &reward { - RewardVariant::LeadingZeros { + RewardVariant::LeadingZeros { zeros_threshold } + | RewardVariant::TotalZeros { zeros_threshold } => { + validate_zeros_threshold(zeros_threshold)?; + } + RewardVariant::LeadingOrTotalZeros { + leading_zeros_threshold, + total_zeros_threshold, + } + | RewardVariant::LeadingAndTotalZeros { leading_zeros_threshold, + total_zeros_threshold, } => { - if leading_zeros_threshold == &0 { - return Err("leading zeros threshold must be greater than 0"); - } - if leading_zeros_threshold > &20 { - return Err("leading zeros threshold must be less than 20"); - } + validate_zeros_threshold(leading_zeros_threshold)?; + validate_zeros_threshold(total_zeros_threshold)?; } RewardVariant::Matching { pattern } => { if pattern.len() != 40 { @@ -136,6 +144,17 @@ impl Config { } } + fn validate_zeros_threshold(threhsold: &u8) -> Result<(), &'static str> { + if threhsold == &0u8 { + return Err("threshold must be greater than 0"); + } + if threhsold > &20u8 { + return Err("threshold must be less than 20"); + } + + Ok(()) + } + let salt_variant = match (chain_id, calling_address) { (Some(chain_id), Some(calling_address)) if calling_address != [0u8; 20] => { SaltVariant::CrosschainSender { @@ -156,7 +175,7 @@ impl Config { salt_variant, variant: create_variant, reward, - output: output.to_string(), + output, }) } } @@ -327,9 +346,26 @@ pub fn gpu(config: Config) -> ocl::Result<()> { ))?; let threshold_string = match config.reward { - RewardVariant::LeadingZeros { + RewardVariant::LeadingZeros { zeros_threshold } => { + format!("with {} leading zero byte(s)", zeros_threshold) + } + RewardVariant::TotalZeros { zeros_threshold } => { + format!("with {} total zero byte(s)", zeros_threshold) + } + RewardVariant::LeadingAndTotalZeros { leading_zeros_threshold, - } => format!("with {} leading zero byte(s)", leading_zeros_threshold), + total_zeros_threshold, + } => format!( + "with {} leading and {} total zero byte(s)", + leading_zeros_threshold, total_zeros_threshold + ), + RewardVariant::LeadingOrTotalZeros { + leading_zeros_threshold, + total_zeros_threshold, + } => format!( + "with {} leading or {} total zero byte(s)", + leading_zeros_threshold, total_zeros_threshold + ), RewardVariant::Matching { ref pattern } => { format!("matching pattern {}", pattern) } @@ -456,7 +492,7 @@ fn output_file(config: &Config) -> File { .append(true) .create(true) .read(true) - .open(config.output.clone()) + .open(config.output) .unwrap_or_else(|_| panic!("Could not create or open {} file.", config.output)) } @@ -488,11 +524,38 @@ fn mk_kernel_src(config: &Config) -> String { }; match &config.reward { - RewardVariant::LeadingZeros { + RewardVariant::LeadingZeros { zeros_threshold } => { + writeln!(src, "#define LEADING_ZEROES {zeros_threshold}").unwrap(); + writeln!(src, "#define SUCCESS_CONDITION() hasLeading(digest)").unwrap(); + } + RewardVariant::TotalZeros { zeros_threshold } => { + writeln!(src, "#define LEADING_ZEROES 0").unwrap(); + writeln!(src, "#define TOTAL_ZEROES {zeros_threshold}").unwrap(); + writeln!(src, "#define SUCCESS_CONDITION() hasTotal(digest)").unwrap(); + } + RewardVariant::LeadingAndTotalZeros { leading_zeros_threshold, + total_zeros_threshold, } => { writeln!(src, "#define LEADING_ZEROES {leading_zeros_threshold}").unwrap(); - writeln!(src, "#define SUCCESS_CONDITION() hasLeading(digest)").unwrap(); + writeln!(src, "#define TOTAL_ZEROES {total_zeros_threshold}").unwrap(); + writeln!( + src, + "#define SUCCESS_CONDITION() hasLeading(digest) && hasTotal(digest)" + ) + .unwrap(); + } + RewardVariant::LeadingOrTotalZeros { + leading_zeros_threshold, + total_zeros_threshold, + } => { + writeln!(src, "#define LEADING_ZEROES {leading_zeros_threshold}").unwrap(); + writeln!(src, "#define TOTAL_ZEROES {total_zeros_threshold}").unwrap(); + writeln!( + src, + "#define SUCCESS_CONDITION() hasLeading(digest) || hasTotal(digest)" + ) + .unwrap(); } RewardVariant::Matching { pattern } => { writeln!(src, "#define LEADING_ZEROES 0").unwrap(); diff --git a/src/main.rs b/src/main.rs index 91a5ec3..36e962e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,29 +14,44 @@ fn main() { let caller = args.cli_args.caller; let chain_id = args.cli_args.chain_id; let init_code_hash = args.init_code_hash; - let reward = match (args.cli_args.zeros, args.cli_args.pattern) { - (Some(zeros), None) => RewardVariant::LeadingZeros { - leading_zeros_threshold: zeros - .parse::() - .expect("Leading zeros threshold must be a number"), + let reward = match ( + args.cli_args.zeros, + args.cli_args.total, + args.cli_args.either, + args.cli_args.pattern, + ) { + (Some(zeros), None, false, None) => RewardVariant::LeadingZeros { + zeros_threshold: zeros, + }, + (None, Some(total), false, None) => RewardVariant::TotalZeros { + zeros_threshold: total, }, - (None, Some(pattern)) => RewardVariant::Matching { - pattern: pattern.to_string(), + (Some(zeros), Some(total), false, None) => RewardVariant::LeadingAndTotalZeros { + leading_zeros_threshold: zeros, + total_zeros_threshold: total, }, + (Some(zeros), Some(total), true, None) => RewardVariant::LeadingOrTotalZeros { + leading_zeros_threshold: zeros, + total_zeros_threshold: total, + }, + (None, None, false, Some(pattern)) => RewardVariant::Matching { pattern }, _ => unreachable!(), }; let output = args.cli_args.output; - let _ = match Config::new( - &gpu_device_id, + match Config::new( + gpu_device_id, &factory, - caller.as_ref(), - chain_id.as_ref(), + caller.as_deref(), + chain_id, Some(&init_code_hash), reward, &output, ) { - Ok(config) => gpu(config), + Ok(config) => match gpu(config) { + Ok(_) => (), + Err(e) => panic!("{}", e), + }, Err(e) => panic!("{}", e), }; } @@ -45,29 +60,39 @@ fn main() { let factory = args.factory; let caller = args.caller; let chain_id = args.chain_id; - let reward = match (args.zeros, args.pattern) { - (Some(zeros), None) => RewardVariant::LeadingZeros { - leading_zeros_threshold: zeros - .parse::() - .expect("Leading zeros threshold must be a number"), + let reward = match (args.zeros, args.total, args.either, args.pattern) { + (Some(zeros), None, false, None) => RewardVariant::LeadingZeros { + zeros_threshold: zeros, }, - (None, Some(pattern)) => RewardVariant::Matching { - pattern: pattern.to_string(), + (None, Some(total), false, None) => RewardVariant::TotalZeros { + zeros_threshold: total, }, + (Some(zeros), Some(total), false, None) => RewardVariant::LeadingAndTotalZeros { + leading_zeros_threshold: zeros, + total_zeros_threshold: total, + }, + (Some(zeros), Some(total), true, None) => RewardVariant::LeadingOrTotalZeros { + leading_zeros_threshold: zeros, + total_zeros_threshold: total, + }, + (None, None, false, Some(pattern)) => RewardVariant::Matching { pattern }, _ => unreachable!(), }; let output = args.output; - let _ = match Config::new( - &gpu_device_id, + match Config::new( + gpu_device_id, &factory, - caller.as_ref(), - chain_id.as_ref(), + caller.as_deref(), + chain_id, None, reward, &output, ) { - Ok(config) => gpu(config), + Ok(config) => match gpu(config) { + Ok(_) => (), + Err(e) => panic!("{}", e), + }, Err(e) => panic!("{}", e), }; }