From f81314199d0cb76a0ce28ea2bc540ef8941e8fc0 Mon Sep 17 00:00:00 2001 From: Surinder Singh Matoo Date: Wed, 20 Nov 2024 01:14:54 +0530 Subject: [PATCH] bug fix --- .github/workflows/release.yml | 79 +++++++++++++++++---- src/cache.rs | 125 ++++++++++++++++------------------ src/main.rs | 105 ++++++++++++++++------------ 3 files changed, 187 insertions(+), 122 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a6b09ae..6241c1e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,18 +1,32 @@ -name: Release for macOS +name: Build and upload assets permissions: contents: write actions: write on: - workflow_dispatch: - push: - tags: - - 'v*' # Triggers workflow for tags like "v1.0.0" - + release: + types: [ published ] + # push: + # tags: + # - 'v*' # Triggers workflow for tags like "v1.0.0" +env: + repo_name: "kaspa-wallet-recovery" + binary: "kaspa-wallet-recovery-${{ github.ref_name }}" jobs: build: - runs-on: macos-latest + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + # Build gnu-linux on ubuntu-18.04 and musl on ubuntu latest + # os: [ ubuntu-18.04, ubuntu-latest, windows-latest, macos-latest ] + os: [ macos-latest, windows-latest ] + name: Building, ${{ matrix.os }} steps: + - name: Fix CRLF on Windows + if: runner.os == 'Windows' + run: git config --global core.autocrlf false + - name: Checkout Code uses: actions/checkout@v3 @@ -22,29 +36,64 @@ jobs: profile: minimal toolchain: stable override: true + - name: Set up rust + if: runner.os == 'macOS' run: rustup target add x86_64-apple-darwin - name: Build for macOS (x86_64) + if: runner.os == 'macOS' run: cargo build --release --target x86_64-apple-darwin - name: Build for macOS (ARM64) + if: runner.os == 'macOS' run: cargo build --release --target aarch64-apple-darwin - - name: Package Binaries + - name: Package macOS Binaries + if: runner.os == 'macOS' run: | - mkdir release-darwin-x86_64 - cp target/x86_64-apple-darwin/release/kaspa-wallet-recovery release-darwin-x86_64/kaspa-wallet-recovery-x86_64 - tar -czvf kaspa-wallet-recovery-darwin-x86_64.tar.gz release-darwin-x86_64 - mkdir release-darwin-arm64 - cp target/aarch64-apple-darwin/release/kaspa-wallet-recovery release-darwin-arm64/kaspa-wallet-recovery-arm64 - tar -czvf kaspa-wallet-recovery-darwin-arm64.tar.gz release-darwin-arm64 + folder="${{env.binary}}-osx-x86_64" + mkdir "${folder}" + cp target/x86_64-apple-darwin/release/${{ env.repo_name }} ${folder}/${{env.repo_name}}-x86_64 + tar -czvf ${{env.binary}}-osx-x86_64.tar.gz ${folder} + folder="${{env.binary}}-osx-arm64" + mkdir "${folder}" + cp target/aarch64-apple-darwin/release/${{ env.repo_name }} ${folder}/${{env.repo_name}}-arm64 + tar -czvf ${{env.binary}}-osx-arm64.tar.gz ${folder} - name: Create GitHub Release + id: "create_release" + if: runner.os == 'macOS' uses: ncipollo/release-action@v1 with: + allowUpdates: true token: ${{ secrets.GITHUB_TOKEN }} tag: ${{ github.ref_name }} name: Release ${{ github.ref_name }} - artifacts: kaspa-wallet-recovery-darwin-x86_64.tar.gz,kaspa-wallet-recovery-darwin-arm64.tar.gz + + artifacts: ${{env.binary}}-osx-x86_64.tar.gz,${{env.binary}}-osx-arm64.tar.gz + + - name: Build on Windows + if: runner.os == 'Windows' + shell: bash + run: | + cargo build --release + mkdir bin || true + cp target/release/${{ env.repo_name }}.exe bin/${{env.binary}}-win64.exe + archive="bin/${{env.binary}}-win64.zip" + asset_name="${{env.binary}}-win64.zip" + powershell "Compress-Archive bin/* \"${archive}\"" + echo "archive=${archive}" >> $GITHUB_ENV + echo "asset_name=${asset_name}" >> $GITHUB_ENV + + - name: Upload release asset + if: runner.os == 'Windows' + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ github.event.release.upload_url }} + asset_path: "./${{ env.archive }}" + asset_name: "${{ env.asset_name }}" + asset_content_type: application/zip \ No newline at end of file diff --git a/src/cache.rs b/src/cache.rs index 34f618e..2715830 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -1,10 +1,12 @@ -use serde::{Deserialize, Serialize}; -use std::{fs::{self, File}, io::{Write, BufWriter}}; -use serde_json; use crate::config::*; -use crate::{HmacSha512, Error, Mac, ToHex}; -use std::sync::{Arc, Mutex}; +use crate::{Error, HmacSha512, Mac, ToHex}; +use serde::{Deserialize, Serialize}; use std::collections::HashSet; +use std::sync::{Arc, Mutex}; +use std::{ + fs::{self, File}, + io::{BufWriter, Write}, +}; // Enum definition #[derive(Serialize, Deserialize, Debug, Clone)] @@ -20,21 +22,28 @@ pub struct Cache { indexes: Arc>>, #[serde(skip)] - file: String + file: String, } impl Default for Cache { fn default() -> Self { - Cache{ - indexes: Arc::new(Mutex::new(vec![WordChecked::None; 12])), - file: String::new() - } + Cache { + indexes: Arc::new(Mutex::new(vec![WordChecked::None; 0])), + file: String::new(), + } } } impl Cache { - pub fn load()-> Result{ - let hmac: HmacSha512 = HmacSha512::new_from_slice(format!("kaspa-wallet-recovery-{}-", MNEMONIC).as_bytes()).map_err(kaspa_bip32::Error::Hmac)?; - let hash = hmac.finalize().into_bytes().to_vec().to_hex().split_off(100); + pub fn load() -> Result { + let hmac: HmacSha512 = + HmacSha512::new_from_slice(format!("kaspa-wallet-recovery-{}-", MNEMONIC).as_bytes()) + .map_err(kaspa_bip32::Error::Hmac)?; + let hash = hmac + .finalize() + .into_bytes() + .to_vec() + .to_hex() + .split_off(100); let file_path = format!("cache/{}.json", hash); fs::create_dir_all("cache").expect("could not create cache dir."); let mut c = read_json(&file_path).unwrap_or_default(); @@ -42,78 +51,64 @@ impl Cache { Ok(c) } - pub fn is_checked(&self, index: usize, word: &String)->bool{ - match self.indexes.lock().unwrap().get(index){ - Some(c)=>{ - match c { - WordChecked::All=>true, - WordChecked::None=>false, - WordChecked::Words(list)=>{ - list.contains(word) - } - - } - } - None=>false + pub fn is_checked(&self, index: usize, word: &String) -> bool { + match self.indexes.lock().unwrap().get(index) { + Some(c) => match c { + WordChecked::All => true, + WordChecked::None => false, + WordChecked::Words(list) => list.contains(word), + }, + None => false, } } - - - pub fn mark_checked(&self, index: usize, word: &str){ - let insert = match self.indexes.lock().unwrap().get_mut(index){ - Some(c)=>{ - match c { - WordChecked::All=>false, - WordChecked::None=>true, - WordChecked::Words(list)=>{ - list.insert(word.into()); - false - } - + pub fn mark_checked(&self, index: usize, word: &str) { + let insert = match self.indexes.lock().unwrap().get_mut(index) { + Some(c) => match c { + WordChecked::All => false, + WordChecked::None => true, + WordChecked::Words(list) => { + list.insert(word.into()); + false } - } - None=>true + }, + None => true, }; if insert { - self.indexes.lock().unwrap().insert(index, WordChecked::Words([word.to_string()].into())) + self.indexes + .lock() + .unwrap() + .insert(index, WordChecked::Words([word.to_string()].into())) } } - pub fn mark_all(&self, index: usize, all_words: &Vec<&str>){ - let insert = match self.indexes.lock().unwrap().get(index){ - Some(c)=>{ - match c { - WordChecked::All=>false, - WordChecked::None=>false, - WordChecked::Words(list)=>{ - all_words.iter().all(|word| list.contains(*word)) - } - - } - } - None=>false + pub fn mark_all(&self, index: usize, all_words: &[&str]) { + let insert = match self.indexes.lock().unwrap().get(index) { + Some(c) => match c { + WordChecked::All => false, + WordChecked::None => false, + WordChecked::Words(list) => all_words.iter().all(|word| list.contains(*word)), + }, + None => false, }; if insert { - self.indexes.lock().unwrap().insert(index, WordChecked::All); + self.indexes.lock().unwrap()[index] = WordChecked::All; self.save(); - } + } } // pub fn mark_clear(&mut self, index: usize){ - // self.indexes.insert(index, WordChecked::None); + // self.indexes.insert(index, WordChecked::None); // } - pub fn save(&self){ - write_json(&self.file, self).map_err(|err|{ - println!("write_json failed : {:?}", err) - }).ok(); + pub fn save(&self) { + write_json(&self.file, self) + .map_err(|err| println!("write_json failed : {:?}", err)) + .ok(); } - } - // Read from JSON file fn read_json(file_path: &str) -> Result> { let json_str = fs::read_to_string(file_path)?; @@ -128,4 +123,4 @@ fn write_json(file_path: &str, cache: &Cache) -> Result<(), Box Result { + //return Ok(false); let seed = mnemonic.create_seed(None); let seed_bytes = Vec::::from_hex(seed.as_str()).map_err(|_| Error::Custom("Invalid seed".into()))?; @@ -145,16 +146,13 @@ fn main() -> Result<(), Error> { let now = SystemTime::now(); println!("Attempt to fix 1 word in the mnemonic."); - if one_word(MNEMONIC, &target_address)?{ + if one_word(MNEMONIC, &target_address)? { // } else if FIX_2_WORDS { println!("Now attempt to fix up to 2 words in the mnemonic."); two_words(MNEMONIC, &target_address)?; } - println!( - "Finished in {:?}", - now.elapsed().unwrap() - ); + println!("Finished in {:?}", now.elapsed().unwrap()); Ok(()) } @@ -164,7 +162,7 @@ fn two_words(wallet_mnemonic: &'static str, target_address: &Arc
) -> Re let word_list = Arc::new(word_list); let all_words = word_list.clone(); let word_list_chuncks = word_list - .chunks(700) + .chunks(64) .map(|a| Arc::new(a.iter().map(|s| String::from(*s)).collect::>())) .collect::>(); @@ -175,9 +173,12 @@ fn two_words(wallet_mnemonic: &'static str, target_address: &Arc
) -> Re let length = wallet_mnemonic.len(); let cache = Cache::load()?; - let mut handles = vec![]; + + let found_mnemonic = Arc::new(Mutex::new(None)); for index1 in 0..(length - 1) { + let mut handles = vec![]; //println!("index1: {index1} ================================= "); + let now = SystemTime::now(); for (thread_index, word_list) in word_list_chuncks.clone().into_iter().enumerate() { println!( "Starting Index-1: {thread_index:>2} {index1}", @@ -188,12 +189,19 @@ fn two_words(wallet_mnemonic: &'static str, target_address: &Arc
) -> Re let abortable = abortable.clone(); let all_words = all_words.clone(); let cache = cache.clone(); - - let handle = thread::spawn(move || -> bool{ + let found_mnemonic = found_mnemonic.clone(); + let handle = thread::spawn(move || -> bool { + if abortable.is_aborted() { + return false; + } let now = SystemTime::now(); + let mut wallet_mnemonic_clone = wallet_mnemonic.clone(); for (i, word1) in word_list.as_ref().iter().enumerate() { + if abortable.is_aborted() { + return false; + } let now = SystemTime::now(); - if cache.is_checked(index1, word1){ + if cache.is_checked(index1, word1) { println!( "INDEX: {thread_index:>2} {:>2} | TIME: {:>8.6}s | WORD: {:>4} {:<15} | SKIPPED", index1, @@ -203,33 +211,40 @@ fn two_words(wallet_mnemonic: &'static str, target_address: &Arc
) -> Re ); continue; } - let mut wallet_mnemonic_clone = wallet_mnemonic.clone(); + wallet_mnemonic_clone[index1] = word1; for index2 in (index1 + 1)..length { // if abortable.is_aborted(){ - // return Ok(false); + // return false; // } //println!("index1: {index1}, index2: {index2}"); + let old_word = wallet_mnemonic_clone[index2]; for word2 in all_words.as_ref() { wallet_mnemonic_clone[index2] = *word2; - let mnemonic = - match Mnemonic::new(wallet_mnemonic_clone.join(" "), Language::English) - { - Ok(mnemonic) => mnemonic, - Err(_err) => { - //println!("mnemonic error: {:?}, {}", _err, mnemonic_phrase); - continue; - } - }; + let mnemonic = match Mnemonic::new( + wallet_mnemonic_clone.join(" "), + Language::English, + ) { + Ok(mnemonic) => mnemonic, + Err(_err) => { + //println!("mnemonic error: {:?}, {}", _err, mnemonic_phrase); + continue; + } + }; // println!("=======================\nCreating wallet with: {word1} {word2}"); match check_wallet(&mnemonic, &target_address) { Ok(found) => { if found { - println!("🎉 Match found, 🔑: {}", mnemonic.phrase_string()); + println!( + "🎉 Match found, 🔑: {}", + mnemonic.phrase_string() + ); + *found_mnemonic.lock().unwrap() = + Some(mnemonic.phrase_string()); abortable.abort(); - return true + return true; } } Err(err) => { @@ -237,9 +252,10 @@ fn two_words(wallet_mnemonic: &'static str, target_address: &Arc
) -> Re } } } + wallet_mnemonic_clone[index2] = old_word; } - + //if word1=="pumpkin"{ println!( "INDEX: {thread_index:>2} {:>2} | TIME: {:>8.6}s | WORD: {:>4} {:<15}", index1, @@ -247,11 +263,11 @@ fn two_words(wallet_mnemonic: &'static str, target_address: &Arc
) -> Re i, word1 ); + //} cache.mark_checked(index1, word1); - cache.save(); - + //cache.save(); } - cache.mark_all(index1, &all_words); + //cache.save(); println!( "INDEX: {:>2} {:>2} | FINISHED IN TIME: {:>8.6}s", @@ -263,16 +279,25 @@ fn two_words(wallet_mnemonic: &'static str, target_address: &Arc
) -> Re }); handles.push(handle); } - } - //println!("handles: {}", handles.len()); - - for handle in handles { - if handle.join().unwrap(){ - return Ok(true) + for handle in handles { + handle.join().unwrap(); + } + cache.mark_all(index1, &all_words); + cache.save(); + println!( + "INDEX {:>2} FINISHED IN {:>8.6}s", + index1, + now.elapsed().unwrap().as_secs_f64() + ); + if let Some(s) = found_mnemonic.lock().unwrap().as_ref() { + println!("🎉 Match found, 🔑: {s}"); + return Ok(true); } } + //println!("handles: {}", handles.len()); + Ok(false) } @@ -297,11 +322,7 @@ fn one_word(wallet_mnemonic: &'static str, target_address: &Arc
) -> Res if abortable.is_aborted() { return false; } - println!( - "INDEX: {:>2} | WORD: {:<15}", - index1, - word1 - ); + println!("INDEX: {:>2} | WORD: {:<15}", index1, word1); let mnemonic_phrase = wallet_mnemonic_clone.join(" "); // if word1 == "bitter" && word2 == "doll"{