main.rs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. use std::{process::exit, sync::mpsc::channel};
  2. use clap::Parser;
  3. use indicatif::{ProgressBar, ProgressStyle};
  4. use rand::rngs::OsRng;
  5. use rayon::prelude::*;
  6. use darkfi::{
  7. cli_desc,
  8. crypto::{
  9. address::Address,
  10. keypair::{Keypair, SecretKey},
  11. },
  12. };
  13. #[derive(Parser)]
  14. #[clap(name = "vanityaddr", about = cli_desc!(), version)]
  15. #[clap(arg_required_else_help(true))]
  16. struct Args {
  17. /// Prefixes to search (must start with 1)
  18. prefix: Vec<String>,
  19. /// Should the search be case-sensitive
  20. #[clap(short)]
  21. case_sensitive: bool,
  22. /// Number of threads to use (defaults to number of available CPUs)
  23. #[clap(short, parse(try_from_str))]
  24. threads: Option<usize>,
  25. }
  26. struct DrkAddr {
  27. pub address: String,
  28. pub secret: SecretKey,
  29. }
  30. impl DrkAddr {
  31. pub fn new() -> Self {
  32. let kp = Keypair::random(&mut OsRng);
  33. let addr = Address::from(kp.public);
  34. Self { secret: kp.secret, address: format!("{}", addr) }
  35. }
  36. pub fn starts_with(&self, prefix: &str, case_sensitive: bool) -> bool {
  37. if case_sensitive {
  38. self.address.starts_with(prefix)
  39. } else {
  40. self.address.to_lowercase().starts_with(prefix.to_lowercase().as_str())
  41. }
  42. }
  43. pub fn starts_with_any(&self, prefixes: &[String], case_sensitive: bool) -> bool {
  44. for prefix in prefixes {
  45. if self.starts_with(prefix, case_sensitive) {
  46. return true
  47. }
  48. }
  49. false
  50. }
  51. }
  52. fn main() {
  53. let args = Args::parse();
  54. if args.prefix.is_empty() {
  55. eprintln!("Error: No prefix given to search.");
  56. exit(1);
  57. }
  58. for (idx, prefix) in args.prefix.iter().enumerate() {
  59. if !prefix.starts_with('1') {
  60. eprintln!("Error: Address prefix at index {} must start with \"1\".", idx);
  61. exit(1);
  62. }
  63. }
  64. // Check if prefixes are valid base58
  65. for (idx, prefix) in args.prefix.iter().enumerate() {
  66. match bs58::decode(prefix).into_vec() {
  67. Ok(_) => {}
  68. Err(e) => {
  69. eprintln!("Error: Invalid base58 for prefix {}: {}", idx, e);
  70. exit(1);
  71. }
  72. };
  73. }
  74. // Threadpool
  75. let num_threads = if args.threads.is_some() { args.threads.unwrap() } else { num_cpus::get() };
  76. let rayon_pool = rayon::ThreadPoolBuilder::new().num_threads(num_threads).build().unwrap();
  77. // Handle SIGINT
  78. let (tx, rx) = channel();
  79. ctrlc::set_handler(move || tx.send(()).expect("Could not send signal on channel"))
  80. .expect("Error setting SIGINT handler");
  81. // Something fancy
  82. let progress = ProgressBar::new_spinner();
  83. let template =
  84. ProgressStyle::default_bar().template("[{elapsed_precise}] {pos} attempts").unwrap();
  85. progress.set_style(template);
  86. // Fire off the threadpool
  87. rayon_pool.spawn(move || {
  88. let addr = rayon::iter::repeat(DrkAddr::new)
  89. .inspect(|_| progress.inc(1))
  90. .map(|create| create())
  91. .find_any(|address| address.starts_with_any(&args.prefix, args.case_sensitive))
  92. .expect("Failed to find an address match");
  93. // The above will keep running until it finds a match or until the
  94. // program terminates. Only if a match is found shall the following
  95. // code be executed and the program exit successfully:
  96. let attempts = progress.position();
  97. progress.finish_and_clear();
  98. println!(
  99. "{{\"address\":\"{}\",\"attempts\":{},\"secret\":\"{:?}\"}}",
  100. addr.address, attempts, addr.secret.0
  101. );
  102. exit(0);
  103. });
  104. // This now blocks and lets our threadpool execute in the background.
  105. rx.recv().expect("Could not receive from channel");
  106. eprintln!("\rCaught SIGINT, exiting...");
  107. exit(127);
  108. }