mirror of
https://github.com/tcsenpai/ethereum-vanity-address-generator-cuda.git
synced 2025-06-02 16:50:08 +00:00
update
This commit is contained in:
parent
e91b0bbc99
commit
edfa73c823
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
.env
|
||||
best_matches.json
|
||||
cuda_matches.json
|
||||
__pycache__
|
||||
found_addresses.txt
|
100
README.md
100
README.md
@ -1,6 +1,6 @@
|
||||
# Ethereum Vanity Address Generator with CUDA
|
||||
|
||||
A high-performance Ethereum vanity address generator that uses CUDA GPU acceleration to quickly generate Ethereum addresses matching a desired prefix pattern. It also includes optional balance checking functionality across multiple RPC endpoints.
|
||||
A high-performance Ethereum vanity address generator that uses CUDA GPU acceleration to quickly generate Ethereum addresses matching a desired prefix pattern. It includes optional balance checking functionality across multiple RPC endpoints and tracks best partial matches.
|
||||
|
||||
## Features
|
||||
|
||||
@ -10,7 +10,9 @@ A high-performance Ethereum vanity address generator that uses CUDA GPU accelera
|
||||
- ⚡ Batch processing for efficient balance checks
|
||||
- 🔄 Automatic RPC failover and rate limit handling
|
||||
- 📊 Real-time status updates and progress tracking
|
||||
- 💾 Automatic saving of addresses with balances to file
|
||||
- 💾 Automatic saving of matches and addresses with balances
|
||||
- 🎯 Tracks best partial matches and saves them to JSON
|
||||
- 🔐 Secure private key generation using CUDA's RNG
|
||||
|
||||
## Requirements
|
||||
|
||||
@ -23,59 +25,97 @@ A high-performance Ethereum vanity address generator that uses CUDA GPU accelera
|
||||
## Installation
|
||||
|
||||
1. Clone the repository:
|
||||
```bash
|
||||
git clone https://github.com/tcsenpai/eth-vanity-address-generator-cuda.git
|
||||
```
|
||||
```bash
|
||||
git clone https://github.com/tcsenpai/eth-vanity-address-generator-cuda.git
|
||||
```
|
||||
2. Install dependencies:
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
3. Configure settings in `.env` file:
|
||||
```bash
|
||||
# Enable balance checking (true/false)
|
||||
CHECK_BALANCES=true
|
||||
# RPC URL for Ethereum node
|
||||
RPC_URL=https://eth.llamarpc.com
|
||||
# How many addresses to check in each batch
|
||||
BALANCE_BATCH_SIZE=100
|
||||
# Desired address prefix
|
||||
PREFIX=dEAD000000000000000042069420694206942069
|
||||
SYNC_MODE=false # Set to true for synchronous balance checking
|
||||
```
|
||||
|
||||
```bash
|
||||
# Enable balance checking (true/false)
|
||||
CHECK_BALANCES=true
|
||||
|
||||
# RPC URLs for redundancy
|
||||
RPC_URLS=[
|
||||
"https://eth.llamarpc.com",
|
||||
"https://rpc.ankr.com/eth",
|
||||
"https://ethereum.publicnode.com",
|
||||
"https://1rpc.io/eth"
|
||||
]
|
||||
|
||||
# How many addresses to check in each batch
|
||||
BALANCE_BATCH_SIZE=100
|
||||
|
||||
# Desired address prefix
|
||||
PREFIX=dEAD000000000000000042069420694206942069
|
||||
|
||||
# Set to true for synchronous balance checking
|
||||
SYNC_MODE=false
|
||||
|
||||
# CUDA batch size for address generation
|
||||
BATCH_SIZE=500
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
1. Run the script:
|
||||
```bash
|
||||
python main.py
|
||||
```
|
||||
You can run either the pure CUDA version or the version with balance checking:
|
||||
|
||||
2. Enter your desired address prefix when prompted, or configure it in the `.env` file.
|
||||
1. CUDA-only version:
|
||||
|
||||
The script will begin generating addresses and checking balances if enabled. Status updates are printed every 10 seconds showing:
|
||||
```bash
|
||||
./find_address_fullcuda.sh
|
||||
```
|
||||
|
||||
2. CUDA with balance checking:
|
||||
```bash
|
||||
./find_address_and_check_balance.sh
|
||||
```
|
||||
|
||||
The script will begin generating addresses and checking balances if enabled. Status updates are printed every 10 seconds (5s for the full cuda version without balance checking) and show:
|
||||
|
||||
- Time elapsed
|
||||
- Total attempts
|
||||
- Generation speed
|
||||
- Prefix check speed
|
||||
- Balance check status
|
||||
- Best match found so far
|
||||
|
||||
When a matching address is found, it will be displayed along with its private key.
|
||||
|
||||
## Output Files
|
||||
|
||||
- `found_addresses.txt`: Contains addresses found with balances
|
||||
- `best_matches.json`: Tracks the best partial matches found
|
||||
- `cuda_matches.json`: Records all matches found by the CUDA miner
|
||||
|
||||
## Configuration
|
||||
|
||||
The following settings can be configured in the `.env` file:
|
||||
|
||||
- `CHECK_BALANCES`: Enable/disable balance checking
|
||||
- `RPC_URL`: Ethereum RPC endpoint URL
|
||||
- `BALANCE_BATCH_SIZE`: Number of addresses to check in each batch
|
||||
- `CHECK_BALANCES`: Enable/disable balance checking (only works with balance checking version)
|
||||
- `RPC_URLS`: List of Ethereum RPC endpoints for redundancy (only works with balance checking version)
|
||||
- `BALANCE_BATCH_SIZE`: Number of addresses to check in each batch (only works with balance checking version)
|
||||
- `PREFIX`: Target address prefix
|
||||
- `SYNC_MODE`: Use synchronous or asynchronous balance checking
|
||||
- `BATCH_SIZE`: CUDA batch size for address generation
|
||||
|
||||
## Tips
|
||||
|
||||
- Longer prefixes will take exponentially more time to find
|
||||
- Consider using shorter prefixes for testing
|
||||
- Multiple RPC endpoints are used for redundancy
|
||||
- Found addresses with balances are saved to `found.txt`
|
||||
- Multiple RPC endpoints provide redundancy and failover
|
||||
- The system automatically tracks and saves best partial matches
|
||||
- CUDA batch size is optimized for RTX series GPUs
|
||||
- Balance checking automatically determines optimal batch sizes for each RPC
|
||||
|
||||
## Performance
|
||||
|
||||
The following metrics are based on a RTX 4060 Mobile GPU (8GB VRAM).
|
||||
|
||||
- The full cuda version without balance checking manages to check about 25,000,000 (25 million) addresses per second.
|
||||
- The balance checking version manages to check about 2000 prefixes and 1000 balances per second. Disabling balance checking increases the speed to about 12,000 prefixes per second.
|
||||
|
11
env.example
Normal file
11
env.example
Normal file
@ -0,0 +1,11 @@
|
||||
# Enable balance checking (true/false)
|
||||
CHECK_BALANCES=true
|
||||
# RPC URL for Ethereum node
|
||||
RPC_URL=https://eth.llamarpc.com
|
||||
# How many addresses to check in each batch
|
||||
BALANCE_BATCH_SIZE=100
|
||||
# Desired address prefix
|
||||
PREFIX=dEAD000000000000000042069420694206942069
|
||||
SYNC_MODE=false # Set to true for synchronous balance checking
|
||||
# CUDA batch size for address generation
|
||||
BATCH_SIZE=500
|
5
find_address_and_check_balance.sh
Executable file
5
find_address_and_check_balance.sh
Executable file
@ -0,0 +1,5 @@
|
||||
export CUDA_CACHE_DISABLE=0
|
||||
export CUDA_CACHE_MAXSIZE=2147483647
|
||||
export CUDA_CACHE_PATH=/tmp/cuda-cache
|
||||
|
||||
python vanity_and_balance.py
|
@ -2,4 +2,4 @@ export CUDA_CACHE_DISABLE=0
|
||||
export CUDA_CACHE_MAXSIZE=2147483647
|
||||
export CUDA_CACHE_PATH=/tmp/cuda-cache
|
||||
|
||||
python main.py
|
||||
python vanity_cuda.py
|
157
libs/cudacode.py
Normal file
157
libs/cudacode.py
Normal file
@ -0,0 +1,157 @@
|
||||
CUDA_CRYPTO_CODE = """
|
||||
#include <stdint.h>
|
||||
#include <cuda_runtime.h>
|
||||
#include <curand_kernel.h>
|
||||
|
||||
#define KECCAK_ROUNDS 24
|
||||
#define BATCH_SIZE 65536
|
||||
|
||||
// Keccak round constants
|
||||
__device__ __constant__ uint64_t keccak_round_constants[24] = {
|
||||
0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808AULL,
|
||||
0x8000000080008000ULL, 0x000000000000808BULL, 0x0000000080000001ULL,
|
||||
0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008AULL,
|
||||
0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000AULL,
|
||||
0x000000008000808BULL, 0x800000000000008BULL, 0x8000000000008089ULL,
|
||||
0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL,
|
||||
0x000000000000800AULL, 0x800000008000000AULL, 0x8000000080008081ULL,
|
||||
0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL
|
||||
};
|
||||
|
||||
// Keccak state rotation offsets
|
||||
__device__ __constant__ int keccak_rotc[24] = {
|
||||
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14,
|
||||
27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44
|
||||
};
|
||||
|
||||
// Keccak state permutation indices
|
||||
__device__ __constant__ int keccak_piln[24] = {
|
||||
10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4,
|
||||
15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1
|
||||
};
|
||||
|
||||
// Keccak-256 hash function
|
||||
__device__ void keccak256_transform(uint64_t* state) {
|
||||
uint64_t temp, C[5];
|
||||
int i, j;
|
||||
|
||||
for (int round = 0; round < KECCAK_ROUNDS; round++) {
|
||||
// Theta step
|
||||
for (i = 0; i < 5; i++) {
|
||||
C[i] = state[i] ^ state[i + 5] ^ state[i + 10] ^ state[i + 15] ^ state[i + 20];
|
||||
}
|
||||
for (i = 0; i < 5; i++) {
|
||||
temp = C[(i + 4) % 5] ^ ((C[(i + 1) % 5] << 1) | (C[(i + 1) % 5] >> 63));
|
||||
for (j = 0; j < 25; j += 5) {
|
||||
state[j + i] ^= temp;
|
||||
}
|
||||
}
|
||||
|
||||
// Rho and Pi steps
|
||||
temp = state[1];
|
||||
for (i = 0; i < 24; i++) {
|
||||
j = keccak_piln[i];
|
||||
C[0] = state[j];
|
||||
state[j] = ((temp << keccak_rotc[i]) | (temp >> (64 - keccak_rotc[i])));
|
||||
temp = C[0];
|
||||
}
|
||||
|
||||
// Chi step
|
||||
for (j = 0; j < 25; j += 5) {
|
||||
for (i = 0; i < 5; i++) {
|
||||
C[i] = state[j + i];
|
||||
}
|
||||
for (i = 0; i < 5; i++) {
|
||||
state[j + i] ^= (~C[(i + 1) % 5]) & C[(i + 2) % 5];
|
||||
}
|
||||
}
|
||||
|
||||
// Iota step
|
||||
state[0] ^= keccak_round_constants[round];
|
||||
}
|
||||
}
|
||||
|
||||
__device__ void keccak256_update(uint64_t* state, const uint8_t* data, size_t len) {
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
state[i/8] ^= ((uint64_t)data[i]) << (8 * (i % 8));
|
||||
}
|
||||
keccak256_transform(state);
|
||||
}
|
||||
|
||||
__device__ void keccak256_final(uint64_t* state, uint8_t* hash) {
|
||||
keccak256_transform(state);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
((uint64_t*)hash)[i] = state[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Main kernel for address generation and checking
|
||||
extern "C" __global__ void generate_and_check(
|
||||
uint8_t* private_keys,
|
||||
uint8_t* addresses,
|
||||
int* match_lengths,
|
||||
const uint8_t* target_prefix,
|
||||
int prefix_len,
|
||||
uint32_t seed
|
||||
) {
|
||||
int idx = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
if (idx >= BATCH_SIZE) return;
|
||||
|
||||
// Initialize random state
|
||||
curandState rng_state;
|
||||
curand_init(seed + idx, 0, 0, &rng_state);
|
||||
|
||||
// Generate random private key
|
||||
uint8_t private_key[32];
|
||||
for (int i = 0; i < 32; i++) {
|
||||
private_key[i] = curand(&rng_state) & 0xFF;
|
||||
}
|
||||
|
||||
// Store private key
|
||||
for (int i = 0; i < 32; i++) {
|
||||
private_keys[idx * 32 + i] = private_key[i];
|
||||
}
|
||||
|
||||
// Initialize Keccak state
|
||||
uint64_t keccak_state[25] = {0};
|
||||
|
||||
// Hash private key to get address
|
||||
keccak256_update(keccak_state, private_key, 32);
|
||||
uint8_t hash[32];
|
||||
keccak256_final(keccak_state, hash);
|
||||
|
||||
// Take last 20 bytes as address
|
||||
for (int i = 0; i < 20; i++) {
|
||||
addresses[idx * 20 + i] = hash[i + 12];
|
||||
}
|
||||
|
||||
// Convert address to hex and compare with target
|
||||
int match_count = 0;
|
||||
for (int i = 0; i < prefix_len && i < 20; i++) {
|
||||
uint8_t addr_byte = addresses[idx * 20 + i];
|
||||
uint8_t target_byte = target_prefix[i];
|
||||
|
||||
// Convert each byte to two hex characters
|
||||
char addr_hex[2];
|
||||
addr_hex[0] = (addr_byte >> 4) <= 9 ? (addr_byte >> 4) + '0' : (addr_byte >> 4) - 10 + 'a';
|
||||
addr_hex[1] = (addr_byte & 0x0F) <= 9 ? (addr_byte & 0x0F) + '0' : (addr_byte & 0x0F) - 10 + 'a';
|
||||
|
||||
char target_hex[2];
|
||||
target_hex[0] = (target_byte >> 4) <= 9 ? (target_byte >> 4) + '0' : (target_byte >> 4) - 10 + 'a';
|
||||
target_hex[1] = (target_byte & 0x0F) <= 9 ? (target_byte & 0x0F) + '0' : (target_byte & 0x0F) - 10 + 'a';
|
||||
|
||||
// Compare characters
|
||||
if (addr_hex[0] != target_hex[0]) {
|
||||
break; // First character doesn't match
|
||||
}
|
||||
match_count++;
|
||||
|
||||
if (addr_hex[1] != target_hex[1]) {
|
||||
break; // Second character doesn't match
|
||||
}
|
||||
match_count++;
|
||||
}
|
||||
|
||||
match_lengths[idx] = match_count;
|
||||
}
|
||||
"""
|
@ -13,6 +13,7 @@ from collections import deque
|
||||
import aiohttp
|
||||
import concurrent.futures
|
||||
from threading import Lock
|
||||
import json
|
||||
|
||||
cuda.init()
|
||||
|
||||
@ -28,6 +29,8 @@ RPC_URLS = [
|
||||
|
||||
# Add new configuration from .env
|
||||
CHECK_BALANCES = os.getenv("CHECK_BALANCES", "false").lower() == "true"
|
||||
if not CHECK_BALANCES:
|
||||
print("🚫 Balance checking is disabled.")
|
||||
BALANCE_BATCH_SIZE = int(os.getenv("BALANCE_BATCH_SIZE", "100"))
|
||||
SYNC_MODE = os.getenv("SYNC_MODE", "false").lower() == "true"
|
||||
BATCH_SIZE = int(os.getenv("BATCH_SIZE", "500")) # Number of addresses to check at once
|
||||
@ -41,6 +44,10 @@ last_balance_check = {"address": None, "balance": None, "rpc": None}
|
||||
pending_tasks = []
|
||||
MAX_PENDING_TASKS = 10 # Adjust based on your needs
|
||||
|
||||
# Add near the top with other globals
|
||||
FOUND_FILE = "found_addresses.txt"
|
||||
BEST_MATCHES_FILE = "best_matches.json"
|
||||
|
||||
|
||||
def get_next_web3():
|
||||
global rpc_index
|
||||
@ -111,8 +118,8 @@ def check_single_balance(address, private_key):
|
||||
print(f"Balance: {Web3.from_wei(balance, 'ether')} ETH")
|
||||
print(f"Private key: {private_key}")
|
||||
print(f"{'='*50}\n")
|
||||
with open("found.txt", "a") as f:
|
||||
f.write(f"{address} {private_key}\n")
|
||||
with open(FOUND_FILE, "a") as f:
|
||||
f.write(f"Address: {address}\nPrivate Key: {private_key}\nBalance: {Web3.from_wei(balance, 'ether')} ETH\n{'='*50}\n")
|
||||
return balance
|
||||
except Exception as e:
|
||||
if "429" in str(e): # Rate limit error
|
||||
@ -213,10 +220,28 @@ async def generate_vanity_address(prefix, num_attempts=0):
|
||||
"address": address,
|
||||
"similarity": similarity,
|
||||
"private_key": priv_key_hex,
|
||||
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S")
|
||||
}
|
||||
print(
|
||||
f"🎯 Best match so far: {best_match['address']} ({best_match['similarity']} chars)"
|
||||
)
|
||||
print(f"🎯 Best match so far: {best_match['address']} ({best_match['similarity']} chars)")
|
||||
|
||||
# Save to JSON file
|
||||
try:
|
||||
# Load existing matches
|
||||
matches = []
|
||||
try:
|
||||
with open(BEST_MATCHES_FILE, 'r') as f:
|
||||
matches = json.load(f)
|
||||
except (FileNotFoundError, json.JSONDecodeError):
|
||||
matches = []
|
||||
|
||||
# Add new match
|
||||
matches.append(best_match)
|
||||
|
||||
# Save updated matches
|
||||
with open(BEST_MATCHES_FILE, 'w') as f:
|
||||
json.dump(matches, f, indent=2)
|
||||
except Exception as e:
|
||||
print(f"❌ Error saving best match: {str(e)}")
|
||||
# Immediately check for balance if best match without waiting
|
||||
ethBalance = check_single_balance(address, priv_key_hex)
|
||||
print(f"💰 Balance: {ethBalance} ETH")
|
||||
@ -385,8 +410,8 @@ async def batch_check_balances(addresses, private_keys):
|
||||
print(f"Balance: {Web3.from_wei(balance, 'ether')} ETH")
|
||||
print(f"Private key: {private_key}")
|
||||
print(f"{'='*50}\n")
|
||||
with open("found.txt", "a") as f:
|
||||
f.write(f"{address} {private_key}\n")
|
||||
with open(FOUND_FILE, "a") as f:
|
||||
f.write(f"Address: {address}\nPrivate Key: {private_key}\nBalance: {Web3.from_wei(balance, 'ether')} ETH\n{'='*50}\n")
|
||||
|
||||
return results
|
||||
|
||||
@ -488,9 +513,12 @@ async def main():
|
||||
|
||||
if __name__ == "__main__":
|
||||
SUPPORTED_SIZES = []
|
||||
for url in RPC_URLS:
|
||||
SUPPORTED_SIZES.append(asyncio.run(determine_optimal_batch_size(url)))
|
||||
BALANCE_BATCH_SIZE = min(SUPPORTED_SIZES)
|
||||
print(f"🎯 Using safe batch size of {BALANCE_BATCH_SIZE} for all RPCs\n")
|
||||
if CHECK_BALANCES:
|
||||
for url in RPC_URLS:
|
||||
SUPPORTED_SIZES.append(asyncio.run(determine_optimal_batch_size(url)))
|
||||
BALANCE_BATCH_SIZE = min(SUPPORTED_SIZES)
|
||||
print(f"🎯 Using safe batch size of {BALANCE_BATCH_SIZE} for all RPCs\n")
|
||||
else:
|
||||
print("🚫 Balance checking is disabled.")
|
||||
|
||||
asyncio.run(main())
|
205
vanity_cuda.py
Normal file
205
vanity_cuda.py
Normal file
@ -0,0 +1,205 @@
|
||||
import pycuda.autoinit
|
||||
import pycuda.driver as cuda
|
||||
from pycuda.compiler import SourceModule
|
||||
import numpy as np
|
||||
import time
|
||||
import json
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from libs.cudacode import CUDA_CRYPTO_CODE
|
||||
|
||||
# Load environment variables
|
||||
load_dotenv()
|
||||
PREFIX = os.getenv("PREFIX", "dEAD000000000000000042069420694206942069").lower()
|
||||
BATCH_SIZE = 2**16 # 65536 addresses per batch
|
||||
|
||||
|
||||
class EthereumVanityMiner:
|
||||
def __init__(self):
|
||||
# Initialize CUDA
|
||||
cuda.init()
|
||||
self.device = cuda.Device(0)
|
||||
self.context = self.device.make_context()
|
||||
|
||||
# Compile CUDA module
|
||||
self.mod = SourceModule(CUDA_CRYPTO_CODE, no_extern_c=True)
|
||||
self.kernel = self.mod.get_function("generate_and_check")
|
||||
|
||||
# Prepare memory buffers
|
||||
self.gpu_private_keys = cuda.mem_alloc(BATCH_SIZE * 32)
|
||||
self.gpu_addresses = cuda.mem_alloc(BATCH_SIZE * 20)
|
||||
self.gpu_match_lengths = cuda.mem_alloc(BATCH_SIZE * 4)
|
||||
|
||||
# Prepare target prefix
|
||||
prefix = PREFIX[2:] if PREFIX.startswith("0x") else PREFIX
|
||||
# Debug print
|
||||
print(f"Converting prefix: {prefix}")
|
||||
|
||||
# Convert each pair of hex chars to a byte
|
||||
self.prefix_bytes = bytearray()
|
||||
for i in range(0, len(prefix), 2):
|
||||
hex_pair = prefix[i:i+2]
|
||||
byte_val = int(hex_pair, 16)
|
||||
self.prefix_bytes.append(byte_val)
|
||||
|
||||
# Debug print
|
||||
print(f"Prefix bytes: {[hex(b) for b in self.prefix_bytes]}")
|
||||
|
||||
self.gpu_target = cuda.mem_alloc(len(self.prefix_bytes))
|
||||
cuda.memcpy_htod(self.gpu_target, self.prefix_bytes)
|
||||
|
||||
# Host buffers
|
||||
self.host_match_lengths = np.zeros(BATCH_SIZE, dtype=np.int32)
|
||||
self.host_private_key = np.zeros(32, dtype=np.uint8)
|
||||
self.host_address = np.zeros(20, dtype=np.uint8)
|
||||
|
||||
def cleanup(self):
|
||||
"""Clean up GPU resources"""
|
||||
try:
|
||||
self.gpu_private_keys.free()
|
||||
self.gpu_addresses.free()
|
||||
self.gpu_match_lengths.free()
|
||||
self.gpu_target.free()
|
||||
finally:
|
||||
self.context.pop()
|
||||
self.context.detach()
|
||||
|
||||
def save_match(
|
||||
self, address_hex, private_key_hex, match_length, raw_address, raw_private_key
|
||||
):
|
||||
"""Save match to JSON file"""
|
||||
try:
|
||||
matches = []
|
||||
if os.path.exists("cuda_matches.json"):
|
||||
with open("cuda_matches.json", "r") as f:
|
||||
matches = json.load(f)
|
||||
|
||||
match_data = {
|
||||
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
|
||||
"address": f"0x{address_hex}",
|
||||
"private_key": private_key_hex,
|
||||
"match_length": int(match_length),
|
||||
"raw_address": raw_address,
|
||||
"raw_private_key": raw_private_key,
|
||||
}
|
||||
matches.append(match_data)
|
||||
|
||||
with open("cuda_matches.json", "w") as f:
|
||||
json.dump(matches, f, indent=2)
|
||||
except Exception as e:
|
||||
print(f"\nWarning: Failed to save match to file: {e}")
|
||||
|
||||
def check_batch(self, seed):
|
||||
"""Run one batch of address generation and checking"""
|
||||
block = (256, 1, 1)
|
||||
grid = ((BATCH_SIZE + block[0] - 1) // block[0], 1)
|
||||
|
||||
self.kernel(
|
||||
self.gpu_private_keys,
|
||||
self.gpu_addresses,
|
||||
self.gpu_match_lengths,
|
||||
self.gpu_target,
|
||||
np.int32(len(self.prefix_bytes)),
|
||||
np.uint32(seed),
|
||||
block=block,
|
||||
grid=grid
|
||||
)
|
||||
|
||||
# Get results
|
||||
cuda.memcpy_dtoh(self.host_match_lengths, self.gpu_match_lengths)
|
||||
best_idx = np.argmax(self.host_match_lengths)
|
||||
match_length = self.host_match_lengths[best_idx]
|
||||
|
||||
if match_length > 0:
|
||||
temp_private_key = np.zeros(32, dtype=np.uint8)
|
||||
temp_address = np.zeros(20, dtype=np.uint8)
|
||||
|
||||
cuda.memcpy_dtoh(temp_private_key, self.gpu_private_keys)
|
||||
cuda.memcpy_dtoh(temp_address, self.gpu_addresses)
|
||||
|
||||
address_hex = ''.join(format(x, '02x') for x in temp_address)
|
||||
private_key_hex = ''.join(format(x, '02x') for x in temp_private_key)
|
||||
|
||||
# Verify the match
|
||||
target = PREFIX[2:] if PREFIX.startswith('0x') else PREFIX
|
||||
actual_match = 0
|
||||
for i, (t, a) in enumerate(zip(target, address_hex)):
|
||||
if t.lower() != a.lower():
|
||||
break
|
||||
actual_match += 1
|
||||
|
||||
if actual_match > 0:
|
||||
return {
|
||||
'address': address_hex,
|
||||
'private_key': private_key_hex,
|
||||
'match_length': actual_match,
|
||||
'raw_address': temp_address.tobytes().hex(),
|
||||
'raw_private_key': temp_private_key.tobytes().hex()
|
||||
}
|
||||
return None
|
||||
|
||||
def mine(self, target_score=None):
|
||||
"""Main mining loop"""
|
||||
try:
|
||||
best_match = {"match_length": 0}
|
||||
start_time = time.time()
|
||||
last_status_time = start_time
|
||||
addresses_checked = 0
|
||||
|
||||
while True:
|
||||
seed = np.random.randint(0, 2**32, dtype=np.uint32)
|
||||
result = self.check_batch(seed)
|
||||
|
||||
addresses_checked += BATCH_SIZE
|
||||
current_time = time.time()
|
||||
|
||||
# Print status every 5 seconds
|
||||
if current_time - last_status_time >= 5:
|
||||
elapsed_time = current_time - start_time
|
||||
rate = addresses_checked / elapsed_time
|
||||
print(
|
||||
f"\rChecked {addresses_checked:,} addresses ({rate:,.0f}/s) - Best match: {best_match['match_length']} chars",
|
||||
end="",
|
||||
)
|
||||
last_status_time = current_time
|
||||
|
||||
if result and result["match_length"] > best_match["match_length"]:
|
||||
best_match = result
|
||||
print(f"\nNew best match ({result['match_length']} chars):")
|
||||
print(f"Address: 0x{result['address']}")
|
||||
print(f"Private key: {result['private_key']}")
|
||||
|
||||
self.save_match(
|
||||
result["address"],
|
||||
result["private_key"],
|
||||
result["match_length"],
|
||||
result["raw_address"],
|
||||
result["raw_private_key"],
|
||||
)
|
||||
|
||||
if target_score and result["match_length"] >= target_score:
|
||||
return result
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("\nMining interrupted by user")
|
||||
return best_match
|
||||
finally:
|
||||
self.cleanup()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
miner = EthereumVanityMiner()
|
||||
print(f"Mining with {cuda.Device.count()} GPU(s)")
|
||||
print(f"Target prefix: {PREFIX}")
|
||||
print(f"Batch size: {BATCH_SIZE}")
|
||||
|
||||
result = miner.mine(target_score=len(PREFIX))
|
||||
|
||||
if result:
|
||||
print("\nFinal result:")
|
||||
print(f"Address: 0x{result['address']}")
|
||||
print(f"Private key: {result['private_key']}")
|
||||
print(f"Match length: {result['match_length']}")
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
Loading…
x
Reference in New Issue
Block a user