From 3342abfc1f0039d16cf6c43c6c3913883a0697fd Mon Sep 17 00:00:00 2001 From: feiyu Date: Thu, 25 Dec 2025 13:36:31 +0700 Subject: [PATCH 1/9] add -generate-vanity-address feature --- README.md | 4 ++ argparser.h | 12 ++++++ global.h | 3 ++ main.cpp | 3 ++ structs.h | 1 + wallet_utils.cpp | 97 +++++++++++++++++++++++++++++++++++++++++++----- wallet_utils.h | 8 +++- 7 files changed, 118 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 17a30901..7c451fe3 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,10 @@ Commands: [WALLET COMMANDS] -showkeys Generate identity, public key and private key from seed. Seed must be passed either from params or configuration file. + -generate-vanity-address + Generates a vanity address matching the expected characters using multiple threads, with an option to match as a suffix. + Example: ./qubic-cli -generate-vanity-address ABC 1 false (will generate an address starting with ABC) + ./qubic-cli -generate-vanity-address XYZ 4 true (will generate an address ending with XYZ using 4 threads) -getbalance Balance of an identity (amount of qubic, number of in/out txs) -getasset diff --git a/argparser.h b/argparser.h index 58b6c801..69c184b7 100644 --- a/argparser.h +++ b/argparser.h @@ -50,6 +50,8 @@ void print_help() printf("\n[WALLET COMMANDS]\n"); printf("\t-showkeys\n"); printf("\t\tGenerate identity, public key and private key from seed. Seed must be passed either from params or configuration file.\n"); + printf("\t-generate-vanity-address \n"); + printf("\t\tGenerates a vanity address matching the expected characters using multiple threads, with an option to match as a suffix.\n"); printf("\t-getbalance \n"); printf("\t\tBalance of an identity (amount of qubic, number of in/out txs)\n"); printf("\t-getasset \n"); @@ -728,6 +730,16 @@ void parseArgument(int argc, char** argv) CHECK_OVER_PARAMETERS break; } + if (strcmp(argv[i], "-generate-vanity-address") == 0) + { + g_cmd = GENERATE_VANITY_ADDRESS; + g_vanityPattern = argv[i + 1]; + g_vanityGenerationThreads = uint32_t(charToNumber(argv[i + 2])); + g_isVanitySuffix = (strcmp(argv[i + 3], "1") == 0 || strcasecmp(argv[i + 3], "true") == 0); + i += 4; + CHECK_OVER_PARAMETERS + break; + } if (strcmp(argv[i], "-getbalance") == 0) { CHECK_NUMBER_OF_PARAMETERS(1) diff --git a/global.h b/global.h index 7a87a9dd..932a607e 100644 --- a/global.h +++ b/global.h @@ -43,6 +43,9 @@ char g_loggingMode = 0; char* g_compChatString = nullptr; uint64_t g_executionFeeMultiplierNumerator = 1; uint64_t g_executionFeeMultiplierDenominator = 1; +char *g_vanityPattern = nullptr; +unsigned int g_vanityGenerationThreads = 1; +bool g_isVanitySuffix = false; char* g_dumpBinaryFileInput = nullptr; char* g_dumpBinaryFileOutput = nullptr; diff --git a/main.cpp b/main.cpp index 67cdc8f7..0a452fec 100644 --- a/main.cpp +++ b/main.cpp @@ -34,6 +34,9 @@ int run(int argc, char* argv[]) sanityCheckSeed(g_seed); printWalletInfo(g_seed); break; + case GENERATE_VANITY_ADDRESS: + generateVanityAddress(g_vanityPattern, g_vanityGenerationThreads, g_isVanitySuffix); + break; case GET_CURRENT_TICK: sanityCheckNode(g_nodeIp, g_nodePort); printTickInfoFromNode(g_nodeIp, g_nodePort); diff --git a/structs.h b/structs.h index 1529b279..8f89d864 100644 --- a/structs.h +++ b/structs.h @@ -9,6 +9,7 @@ enum COMMAND { SHOW_KEYS, + GENERATE_VANITY_ADDRESS, GET_CURRENT_TICK, GET_BALANCE, GET_ASSET, diff --git a/wallet_utils.cpp b/wallet_utils.cpp index edcc6647..752d731c 100644 --- a/wallet_utils.cpp +++ b/wallet_utils.cpp @@ -1,17 +1,19 @@ #include -#include #include #include #include +#include +#include -#include "utils.h" -#include "node_utils.h" -#include "key_utils.h" -#include "logger.h" -#include "structs.h" +#include "wallet_utils.h" #include "connection.h" #include "k12_and_key_utils.h" +#include "key_utils.h" +#include "logger.h" +#include "node_utils.h" #include "sc_utils.h" +#include "structs.h" +#include "utils.h" void printWalletInfo(const char* seed) { @@ -125,7 +127,7 @@ void printBalance(const char* publicIdentity, const char* nodeIp, int nodePort) LOG("Spectum Digest: %s\n", hex); } -void printReceipt(Transaction& tx, const char* txHash = nullptr, const uint8_t* extraData = nullptr, int moneyFlew = -1) +void printReceipt(Transaction& tx, const char* txHash, const uint8_t* extraData, int moneyFlew) { char sourceIdentity[128] = {0}; char dstIdentity[128] = {0}; @@ -331,7 +333,7 @@ void makeContractTransaction(const char* nodeIp, int nodePort, int extraDataSize, const void* extraData, uint32_t scheduledTickOffset, - QCPtr* qcPtr = nullptr) + QCPtr* qcPtr) { QCPtr qc = (!qcPtr) ? make_qc(nodeIp, nodePort) : *qcPtr; @@ -393,7 +395,7 @@ bool runContractFunction(const char* nodeIp, int nodePort, size_t inputSize, void* outputPtr, size_t outputSize, - QCPtr* qcPtr = nullptr) + QCPtr* qcPtr) { QCPtr qc = (!qcPtr) ? make_qc(nodeIp, nodePort) : *qcPtr; std::vector packet(sizeof(RequestResponseHeader) + sizeof(RequestContractFunction) + inputSize); @@ -703,3 +705,80 @@ void printActiveIPOs(const char* nodeIp, int nodePort) LOG("- contract index: %u, asset name: %s\n", ipo.contractIndex, ipo.assetName); } } + +VanityAddress generateVanityAddress(const char* pattern, unsigned int vanityGenerationThreads, bool isSufix) { + auto isAddressValid = [](const char* identity, const char* pattern, bool isSufix) -> bool { + size_t patternLen = strlen(pattern); + size_t identityLen = strlen(identity); + if (isSufix) { + if (patternLen > identityLen) return false; + return strcmp(identity + (identityLen - patternLen), pattern) == 0; + } else { + if (patternLen > identityLen) return false; + return strncmp(identity, pattern, patternLen) == 0; + } + }; + + unsigned long long estimatedAttempts = std::pow(24, strlen(pattern)); + std::atomic attemptsCounter(0); + + auto startTime = std::chrono::high_resolution_clock::now(); + auto lastPrintTime = startTime; + + // random seed (55 lowercase char) + auto randomSeed = []() -> std::string { + const char charset[] = "abcdefghijklmnopqrstuvwxyz"; + const size_t max_index = (sizeof(charset) - 1); + std::string str(55, 0); + for (size_t i = 0; i < 55; ++i) { + str[i] = charset[rand() % max_index]; + } + return str; + }; + + auto generateThread = [&](VanityAddress& result, const char* pattern, bool isSufix, bool& found) { + while (!found) { + uint8_t publicKey[32] = {0}; + char identity[61] = {0}; + auto seed = randomSeed(); + getPublicKeyFromSeed(seed.c_str(), publicKey); + getIdentityFromPublicKey(publicKey, identity, false); + if (isAddressValid(identity, pattern, isSufix)) { + memcpy(result.seed, seed.c_str(), sizeof(result.seed)); + memcpy(result.identity, identity, sizeof(result.identity)); + found = true; + break; + } + attemptsCounter++; + auto currentTime = std::chrono::high_resolution_clock::now(); + auto durationSinceLastPrint = std::chrono::duration_cast(currentTime - lastPrintTime).count(); + if (durationSinceLastPrint >= 1) { + lastPrintTime = currentTime; + auto elapsedTime = std::chrono::duration_cast(currentTime - startTime).count(); + double attemptsPerSecond = attemptsCounter.load() / (elapsedTime > 0 ? elapsedTime : 1); + double percentTried = (double)attemptsCounter.load() / (double)estimatedAttempts * 100.0; + LOG("Attempts: %llu | Estimated Attempts: %llu (%.6f%%) | Attempts/s: %.2f | Elapsed Time: %llus\n", + attemptsCounter.load(), estimatedAttempts, percentTried, attemptsPerSecond, elapsedTime); + } + } + }; + + // Start multiple threads to speed up the search + const unsigned int numThreads = std::min(vanityGenerationThreads, std::thread::hardware_concurrency()); + std::vector threads; + VanityAddress result; + bool found = false; + for (unsigned int i = 0; i < numThreads; ++i) { + threads.emplace_back(generateThread, std::ref(result), pattern, isSufix, std::ref(found)); + } + std::string patternStr = isSufix ? "*" + std::string(pattern) : std::string(pattern) + "*"; + printf("-------- Starting vanity address generation with %u threads | Pattern %s --------\n", numThreads, patternStr.c_str()); + for (auto& t : threads) { + t.join(); + } + + printf("Found vanity address!\n"); + printf("Seed: %s\n", result.seed); + printf("Identity: %s\n", result.identity); + return result; +} \ No newline at end of file diff --git a/wallet_utils.h b/wallet_utils.h index 2d6f1479..1ebb8594 100644 --- a/wallet_utils.h +++ b/wallet_utils.h @@ -3,6 +3,11 @@ #include "structs.h" #include "connection.h" +struct VanityAddress { + char seed[55 + 1]; + char identity[60 + 1]; +}; + void printWalletInfo(const char* seed); void printBalance(const char* publicIdentity, const char* nodeIp, int nodePort); void makeStandardTransaction(const char* nodeIp, int nodePort, const char* seed, @@ -60,4 +65,5 @@ void makeIPOBid(const char* nodeIp, int nodePort, uint16_t numberOfShare, uint32_t scheduledTickOffset); void printIPOStatus(const char* nodeIp, int nodePort, uint32_t contractIndex); -void printActiveIPOs(const char* nodeIp, int nodePort); \ No newline at end of file +void printActiveIPOs(const char* nodeIp, int nodePort); +VanityAddress generateVanityAddress(const char* pattern, unsigned int vanityGenerationThreads, bool isSufix = false); From eeb066b4221ce8394b5be39c3450d6b86ca0b95b Mon Sep 17 00:00:00 2001 From: feiyu Date: Thu, 25 Dec 2025 13:45:38 +0700 Subject: [PATCH 2/9] fix warning --- wallet_utils.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/wallet_utils.cpp b/wallet_utils.cpp index 752d731c..d653e47f 100644 --- a/wallet_utils.cpp +++ b/wallet_utils.cpp @@ -749,14 +749,18 @@ VanityAddress generateVanityAddress(const char* pattern, unsigned int vanityGene found = true; break; } - attemptsCounter++; + ++attemptsCounter; auto currentTime = std::chrono::high_resolution_clock::now(); auto durationSinceLastPrint = std::chrono::duration_cast(currentTime - lastPrintTime).count(); if (durationSinceLastPrint >= 1) { lastPrintTime = currentTime; - auto elapsedTime = std::chrono::duration_cast(currentTime - startTime).count(); - double attemptsPerSecond = attemptsCounter.load() / (elapsedTime > 0 ? elapsedTime : 1); - double percentTried = (double)attemptsCounter.load() / (double)estimatedAttempts * 100.0; + const auto elapsedTime = std::chrono::duration_cast(currentTime - startTime).count(); + const auto attempts = static_cast(attemptsCounter.load()); + const double seconds = static_cast(elapsedTime) > 0.0 + ? static_cast(elapsedTime) + : 1.0; + const double attemptsPerSecond = attempts / seconds; + const double percentTried = static_cast(attemptsCounter.load()) / static_cast(estimatedAttempts) * 100.0; LOG("Attempts: %llu | Estimated Attempts: %llu (%.6f%%) | Attempts/s: %.2f | Elapsed Time: %llus\n", attemptsCounter.load(), estimatedAttempts, percentTried, attemptsPerSecond, elapsedTime); } @@ -766,7 +770,7 @@ VanityAddress generateVanityAddress(const char* pattern, unsigned int vanityGene // Start multiple threads to speed up the search const unsigned int numThreads = std::min(vanityGenerationThreads, std::thread::hardware_concurrency()); std::vector threads; - VanityAddress result; + VanityAddress result{}; bool found = false; for (unsigned int i = 0; i < numThreads; ++i) { threads.emplace_back(generateThread, std::ref(result), pattern, isSufix, std::ref(found)); From 80a6d619868637bc2ae1d0dadf899e57ccf7b81f Mon Sep 17 00:00:00 2001 From: feiyu Date: Thu, 25 Dec 2025 13:56:11 +0700 Subject: [PATCH 3/9] fix warning 2 --- wallet_utils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wallet_utils.cpp b/wallet_utils.cpp index d653e47f..8cd1963f 100644 --- a/wallet_utils.cpp +++ b/wallet_utils.cpp @@ -719,7 +719,7 @@ VanityAddress generateVanityAddress(const char* pattern, unsigned int vanityGene } }; - unsigned long long estimatedAttempts = std::pow(24, strlen(pattern)); + unsigned long long estimatedAttempts = static_cast(std::pow(24, strlen(pattern))); std::atomic attemptsCounter(0); auto startTime = std::chrono::high_resolution_clock::now(); @@ -727,7 +727,7 @@ VanityAddress generateVanityAddress(const char* pattern, unsigned int vanityGene // random seed (55 lowercase char) auto randomSeed = []() -> std::string { - const char charset[] = "abcdefghijklmnopqrstuvwxyz"; + constexpr char charset[] = "abcdefghijklmnopqrstuvwxyz"; const size_t max_index = (sizeof(charset) - 1); std::string str(55, 0); for (size_t i = 0; i < 55; ++i) { From e55c22627f482ecde94d9fa443684778faafbd45 Mon Sep 17 00:00:00 2001 From: feiyu Date: Sat, 27 Dec 2025 15:57:34 +0700 Subject: [PATCH 4/9] update random --- wallet_utils.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/wallet_utils.cpp b/wallet_utils.cpp index 8cd1963f..c0e3b1fa 100644 --- a/wallet_utils.cpp +++ b/wallet_utils.cpp @@ -726,12 +726,15 @@ VanityAddress generateVanityAddress(const char* pattern, unsigned int vanityGene auto lastPrintTime = startTime; // random seed (55 lowercase char) - auto randomSeed = []() -> std::string { - constexpr char charset[] = "abcdefghijklmnopqrstuvwxyz"; - const size_t max_index = (sizeof(charset) - 1); + constexpr char charset[] = "abcdefghijklmnopqrstuvwxyz"; + std::random_device rd; + std::seed_seq seq{ rd(), rd(), rd(), rd(), rd(), rd(), rd(), rd() }; + std::mt19937 gen(seq); + std::uniform_int_distribution dist(0, sizeof(charset) - 2); + auto randomSeed = [&dist, &gen, &charset]() -> std::string { std::string str(55, 0); for (size_t i = 0; i < 55; ++i) { - str[i] = charset[rand() % max_index]; + str[i] = charset[dist(gen)]; } return str; }; From 168bc2c1fd13adb30ef48e4f00b76ae21230e840 Mon Sep 17 00:00:00 2001 From: feiyu Date: Sun, 28 Dec 2025 16:21:35 +0700 Subject: [PATCH 5/9] use threadlocal for random state --- wallet_utils.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/wallet_utils.cpp b/wallet_utils.cpp index c0e3b1fa..6a8d14b3 100644 --- a/wallet_utils.cpp +++ b/wallet_utils.cpp @@ -727,16 +727,19 @@ VanityAddress generateVanityAddress(const char* pattern, unsigned int vanityGene // random seed (55 lowercase char) constexpr char charset[] = "abcdefghijklmnopqrstuvwxyz"; - std::random_device rd; - std::seed_seq seq{ rd(), rd(), rd(), rd(), rd(), rd(), rd(), rd() }; - std::mt19937 gen(seq); - std::uniform_int_distribution dist(0, sizeof(charset) - 2); - auto randomSeed = [&dist, &gen, &charset]() -> std::string { - std::string str(55, 0); - for (size_t i = 0; i < 55; ++i) { - str[i] = charset[dist(gen)]; - } - return str; + auto randomSeed = [&charset]() -> std::string { + thread_local std::mt19937 gen([] { + std::random_device rd; + std::seed_seq seq{rd(), rd(), rd(), rd(), rd(), rd(), rd(), rd()}; + return std::mt19937(seq); + }()); + + thread_local std::uniform_int_distribution dist(0, sizeof(charset) - 2); + std::string str(55, 0); + for (size_t i = 0; i < 55; ++i) { + str[i] = charset[dist(gen)]; + } + return str; }; auto generateThread = [&](VanityAddress& result, const char* pattern, bool isSufix, bool& found) { From 69ee3fe7fef94fc2ca881461b30969cbb54bbe18 Mon Sep 17 00:00:00 2001 From: feiyu Date: Sun, 28 Dec 2025 16:26:45 +0700 Subject: [PATCH 6/9] fix possible datarace --- wallet_utils.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/wallet_utils.cpp b/wallet_utils.cpp index 6a8d14b3..111d6994 100644 --- a/wallet_utils.cpp +++ b/wallet_utils.cpp @@ -742,17 +742,19 @@ VanityAddress generateVanityAddress(const char* pattern, unsigned int vanityGene return str; }; - auto generateThread = [&](VanityAddress& result, const char* pattern, bool isSufix, bool& found) { - while (!found) { + auto generateThread = [&](VanityAddress& result, const char* pattern, bool isSufix, std::atomic& found) { + while (!found.load(std::memory_order_acquire)) { uint8_t publicKey[32] = {0}; char identity[61] = {0}; auto seed = randomSeed(); getPublicKeyFromSeed(seed.c_str(), publicKey); getIdentityFromPublicKey(publicKey, identity, false); if (isAddressValid(identity, pattern, isSufix)) { - memcpy(result.seed, seed.c_str(), sizeof(result.seed)); - memcpy(result.identity, identity, sizeof(result.identity)); - found = true; + if (!found.exchange(true)) { + memcpy(result.seed, seed.c_str(), sizeof(result.seed)); + memcpy(result.identity, identity, sizeof(result.identity)); + } + found.store(true, std::memory_order_release); break; } ++attemptsCounter; @@ -777,7 +779,7 @@ VanityAddress generateVanityAddress(const char* pattern, unsigned int vanityGene const unsigned int numThreads = std::min(vanityGenerationThreads, std::thread::hardware_concurrency()); std::vector threads; VanityAddress result{}; - bool found = false; + std::atomic found{false}; for (unsigned int i = 0; i < numThreads; ++i) { threads.emplace_back(generateThread, std::ref(result), pattern, isSufix, std::ref(found)); } From a8f9e7b9b238bfbbccfe1da23cd4ee2c9f542fbb Mon Sep 17 00:00:00 2001 From: feiyu Date: Tue, 13 Jan 2026 13:09:21 +0700 Subject: [PATCH 7/9] improve security --- CMakeLists.txt | 6 ++++++ wallet_utils.cpp | 36 +++++++++++++++++++++++------------- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b6a3bb2e..221812a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,5 +65,11 @@ set_property(TARGET qubic-cli PROPERTY COMPILE_WARNING_AS_ERROR ON) ADD_LIBRARY(fourq-qubic SHARED fourq_qubic.cpp) set_property(TARGET fourq-qubic PROPERTY SOVERSION 1) target_compile_options(fourq-qubic PRIVATE -DBUILD_4Q_LIB) + +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + target_compile_options(qubic-cli PRIVATE -mrdrnd) + target_compile_options(fourq-qubic PRIVATE -mrdrnd) +endif() + install(TARGETS fourq-qubic LIBRARY) diff --git a/wallet_utils.cpp b/wallet_utils.cpp index 111d6994..1cd4b337 100644 --- a/wallet_utils.cpp +++ b/wallet_utils.cpp @@ -719,6 +719,17 @@ VanityAddress generateVanityAddress(const char* pattern, unsigned int vanityGene } }; + auto get_hw_entropy = []() -> unsigned long long { + unsigned long long val = 0; + // Try RDRAND (Intel/AMD hardware RNG) + if (_rdrand64_step(&val)) { + return val; + } + // Fallback to OS entropy if RDRAND fails or isn't supported + std::random_device rd; + return (static_cast(rd()) << 32) | rd(); + }; + unsigned long long estimatedAttempts = static_cast(std::pow(24, strlen(pattern))); std::atomic attemptsCounter(0); @@ -727,19 +738,18 @@ VanityAddress generateVanityAddress(const char* pattern, unsigned int vanityGene // random seed (55 lowercase char) constexpr char charset[] = "abcdefghijklmnopqrstuvwxyz"; - auto randomSeed = [&charset]() -> std::string { - thread_local std::mt19937 gen([] { - std::random_device rd; - std::seed_seq seq{rd(), rd(), rd(), rd(), rd(), rd(), rd(), rd()}; - return std::mt19937(seq); - }()); - - thread_local std::uniform_int_distribution dist(0, sizeof(charset) - 2); - std::string str(55, 0); - for (size_t i = 0; i < 55; ++i) { - str[i] = charset[dist(gen)]; - } - return str; + constexpr size_t charset_len = sizeof(charset) - 1; + auto randomSeed = [&]() -> std::string { + std::string str(55, 0); + for (size_t i = 0; i < 55; ++i) { + // We use a simple rejection sampling to avoid modulo bias + uint64_t rand_val; + do { + rand_val = get_hw_entropy(); + } while (rand_val >= (UINT64_MAX - (UINT64_MAX % charset_len))); + str[i] = charset[rand_val % charset_len]; + } + return str; }; auto generateThread = [&](VanityAddress& result, const char* pattern, bool isSufix, std::atomic& found) { From a4683a4d78dcb6830e22091a3ecbda4b7f75c072 Mon Sep 17 00:00:00 2001 From: feiyu Date: Tue, 13 Jan 2026 13:14:31 +0700 Subject: [PATCH 8/9] fix possible datarace --- wallet_utils.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wallet_utils.cpp b/wallet_utils.cpp index 1cd4b337..bfdb684a 100644 --- a/wallet_utils.cpp +++ b/wallet_utils.cpp @@ -752,7 +752,7 @@ VanityAddress generateVanityAddress(const char* pattern, unsigned int vanityGene return str; }; - auto generateThread = [&](VanityAddress& result, const char* pattern, bool isSufix, std::atomic& found) { + auto generateThread = [&](VanityAddress& result, const char* pattern, bool isSufix, std::atomic& found, int threadId) { while (!found.load(std::memory_order_acquire)) { uint8_t publicKey[32] = {0}; char identity[61] = {0}; @@ -770,7 +770,7 @@ VanityAddress generateVanityAddress(const char* pattern, unsigned int vanityGene ++attemptsCounter; auto currentTime = std::chrono::high_resolution_clock::now(); auto durationSinceLastPrint = std::chrono::duration_cast(currentTime - lastPrintTime).count(); - if (durationSinceLastPrint >= 1) { + if (durationSinceLastPrint >= 1 && threadId == 0) { lastPrintTime = currentTime; const auto elapsedTime = std::chrono::duration_cast(currentTime - startTime).count(); const auto attempts = static_cast(attemptsCounter.load()); @@ -791,7 +791,7 @@ VanityAddress generateVanityAddress(const char* pattern, unsigned int vanityGene VanityAddress result{}; std::atomic found{false}; for (unsigned int i = 0; i < numThreads; ++i) { - threads.emplace_back(generateThread, std::ref(result), pattern, isSufix, std::ref(found)); + threads.emplace_back(generateThread, std::ref(result), pattern, isSufix, std::ref(found), i); } std::string patternStr = isSufix ? "*" + std::string(pattern) : std::string(pattern) + "*"; printf("-------- Starting vanity address generation with %u threads | Pattern %s --------\n", numThreads, patternStr.c_str()); From 99eb93fb81d960b5368a48722ed2d3aeb718610b Mon Sep 17 00:00:00 2001 From: feiyu Date: Tue, 13 Jan 2026 14:13:20 +0700 Subject: [PATCH 9/9] fix % display bug --- wallet_utils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wallet_utils.cpp b/wallet_utils.cpp index bfdb684a..9d6bee90 100644 --- a/wallet_utils.cpp +++ b/wallet_utils.cpp @@ -730,7 +730,7 @@ VanityAddress generateVanityAddress(const char* pattern, unsigned int vanityGene return (static_cast(rd()) << 32) | rd(); }; - unsigned long long estimatedAttempts = static_cast(std::pow(24, strlen(pattern))); + unsigned long long estimatedAttempts = static_cast(std::pow(26, strlen(pattern))); std::atomic attemptsCounter(0); auto startTime = std::chrono::high_resolution_clock::now();