diff --git a/README.md b/README.md index 4bc0f83..7c23a17 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,9 @@ Options: iteration. [default: 24] --is-case-sensitive BOOLEAN Whether the search should be case sensitive or not. [default: True] + --notify BOOLEAN Notify flag when found pubkey. + --telegram-bot-token TEXT Telegram bot token. + --telegram-chat-id TEXT Telegram chat ID. --help Show this message and exit. ``` @@ -72,12 +75,10 @@ $ python3 main.py search-pubkey --starts-with SoL # run $ solana-keygen pubkey SoLxxxxxxxxxxx.json # you should install solana cli to verify it ``` - ## FAQs See [FAQs.md](./FAQs.md). - ## Donations If you find this project helpful, please consider making a donation: diff --git a/core/cli.py b/core/cli.py index 414a635..a81487f 100644 --- a/core/cli.py +++ b/core/cli.py @@ -1,5 +1,6 @@ import logging import multiprocessing +import platform as plf import sys from multiprocessing.pool import Pool from typing import List, Optional, Tuple @@ -8,12 +9,14 @@ import pyopencl as cl from core.config import DEFAULT_ITERATION_BITS, HostSetting -from core.opencl.manager import ( - get_all_gpu_devices, - get_chosen_devices, +from core.opencl.manager import get_all_gpu_devices, get_chosen_devices +from core.searcher import multi_gpu_init, parse_result +from core.utils.crypto import save_keypair +from core.utils.helpers import ( + check_character, + load_kernel_source, + send_telegram_message, ) -from core.searcher import multi_gpu_init, save_result -from core.utils.helpers import check_character, load_kernel_source logging.basicConfig(level="INFO", format="[%(levelname)s %(asctime)s] %(message)s") @@ -58,6 +61,13 @@ def cli(): @click.option( "--is-case-sensitive", type=bool, default=True, help="Case sensitive search flag." ) +@click.option( + "--notify/--no-notify", + default=False, + help="Notify flag when found pubkey.", +) +@click.option("--telegram-bot-token", type=str, help="Telegram bot token.") +@click.option("--telegram-chat-id", type=str, help="Telegram chat ID.") def search_pubkey( starts_with, ends_with, @@ -66,10 +76,21 @@ def search_pubkey( select_device, iteration_bits, is_case_sensitive, + notify, + telegram_bot_token, + telegram_chat_id, ): """Search for Solana vanity pubkeys.""" if not starts_with and not ends_with: - click.echo("Please provide at least one of --starts-with or --ends-with.") + logging.error("Please provide at least one of --starts-with or --ends-with.\n") + ctx = click.get_current_context() + click.echo(ctx.get_help()) + sys.exit(1) + + if notify and (not telegram_bot_token or not telegram_chat_id): + logging.error( + "Please provide both telegram bot token and chat id when using --notify.\n" + ) ctx = click.get_current_context() click.echo(ctx.get_help()) sys.exit(1) @@ -86,13 +107,26 @@ def search_pubkey( gpu_counts = len(get_all_gpu_devices()) logging.info( - "Searching Solana pubkey with starts_with=(%s), ends_with=%s, is_case_sensitive=%s", + "Searching Solana pubkey with starts_with=(%s), ends_with=%s, is_case_sensitive=%s, notify=%s", ", ".join(repr(s) for s in starts_with), repr(ends_with), is_case_sensitive, + notify, ) logging.info(f"Using {gpu_counts} OpenCL device(s)") + host_name = plf.node() + if notify: + send_telegram_message( + telegram_bot_token, + telegram_chat_id, + "Starting to search: starts with \\({}\\), ends with {} at __{}__".format( + ", ".join(repr(s) for s in starts_with), + repr(ends_with), + host_name, + ), + ) + result_count = 0 with multiprocessing.Manager() as manager: with Pool(processes=gpu_counts) as pool: @@ -116,7 +150,18 @@ def search_pubkey( for x in range(gpu_counts) ], ) - result_count += save_result(results, output_dir) + keypairs = parse_result(results) + result_count += len(keypairs) + + for keypair in keypairs: + pubkey = save_keypair(keypair, output_dir) + + if notify: + send_telegram_message( + telegram_bot_token, + telegram_chat_id, + f"Found pubkey: `{pubkey}` at __{host_name}__", + ) @cli.command(context_settings={"show_default": True}) diff --git a/core/searcher.py b/core/searcher.py index 34c3121..16bf035 100644 --- a/core/searcher.py +++ b/core/searcher.py @@ -6,10 +6,7 @@ import pyopencl as cl from core.config import HostSetting -from core.opencl.manager import ( - get_all_gpu_devices, - get_selected_gpu_devices, -) +from core.opencl.manager import get_all_gpu_devices, get_selected_gpu_devices class Searcher: @@ -123,14 +120,14 @@ def multi_gpu_init( return [0] -def save_result(outputs: List, output_dir: str) -> int: - from core.utils.crypto import save_keypair +def parse_result(results: List) -> List[bytes]: + keypairs: List[bytes] = [] - result_count = 0 - for output in outputs: - if not output[0]: + for result in results: + if not result[0]: continue - result_count += 1 - pv_bytes = bytes(output[1:]) - save_keypair(pv_bytes, output_dir) - return result_count + + pv_bytes = bytes(result[1:]) + keypairs.append(pv_bytes) + + return keypairs diff --git a/core/utils/helpers.py b/core/utils/helpers.py index 84fa6e2..db5bbcc 100644 --- a/core/utils/helpers.py +++ b/core/utils/helpers.py @@ -4,6 +4,7 @@ from typing import Tuple import pyopencl as cl +import requests from base58 import b58decode @@ -68,3 +69,16 @@ def load_kernel_source( if cl.get_cl_header_version()[0] != 1 and platform.system() != "Windows": source_str = source_str.replace("#define __generic\n", "") return source_str + + +def send_telegram_message(bot_token: str, chat_id: str, message: str) -> None: + """ + Send a message to a Telegram chat. + """ + try: + requests.post( + f"https://api.telegram.org/bot{bot_token}/sendMessage", + data={"chat_id": chat_id, "text": message, "parse_mode": "MarkdownV2"}, + ) + except Exception: + pass diff --git a/requirements.txt b/requirements.txt index 7a9e590..2c876de 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,4 +2,5 @@ click>=8.1.0 pyopencl base58 PyNaCl -numpy==1.26.4 \ No newline at end of file +numpy==1.26.4 +requests \ No newline at end of file