import hashlib
import random
import time
from typing import List, Dict
# ==============================
# Simulation Configuration
# ==============================
TOTAL_NONCES = 100_000 # Total number of nonces simulated
BLOQUE_SIZE = 5_000 # Size of each block (sequential nonces)
SIMULATIONS = 500 # Number of simulations to run
TARGET_PREFIX = "0000" # Full target (difficulty)
PREFIX_LENGTH = 3 # Length of the short prefix used as a signal
HEADER_LIST_SIZE = 10 # Number of headers to generate per simulation
# ===================================
# Class to store statistics, including a success flag.
# ===================================
class Statistics:
def __init__(self, name: str, checks: int = 0, time: float = 0.0, success: bool = False):
self.name = name
self.checks = checks
self.time = time
self.success = success
# ============================================
# Blockheader Generator (simple simulation)
# ============================================
def generate_blockheader() -> bytes:
return b''.join([
random.getrandbits(32).to_bytes(4, 'little'),
random.randbytes(32),
random.randbytes(32),
int(time.time()).to_bytes(4, 'big'),
bytes.fromhex("1d00ffff")
])
# ============================================
# Double SHA-256 (Bitcoin-style calculation)
# ============================================
def double_sha256(header: bytes, nonce: int) -> str:
nonce_bytes = nonce.to_bytes(4, 'little')
block = header + nonce_bytes
hash1 = hashlib.sha256(block).digest()
return hashlib.sha256(hash1).hexdigest()
# =====================================================
# Sequential Method (original mining, sequential order)
# =====================================================
def sequential_method(header: bytes, nonces: List[int]) -> Statistics:
stats = Statistics("Sequential")
start = time.perf_counter()
for nonce in nonces:
stats.checks += 1
h = double_sha256(header, nonce)
if h.startswith(TARGET_PREFIX):
stats.time = time.perf_counter() - start
stats.success = True
return stats
stats.time = time.perf_counter() - start
return stats
# =====================================================
# Prefix Method (optimized: skip remaining nonces in a block on short prefix)
# =====================================================
def prefix_method(header: bytes, nonces: List[int]) -> Statistics:
stats = Statistics("Prefix")
blocks = [nonces[i:i+BLOQUE_SIZE] for i in range(0, len(nonces), BLOQUE_SIZE)]
random.shuffle(blocks)
short_prefix = TARGET_PREFIX[:PREFIX_LENGTH]
start = time.perf_counter()
for block in blocks:
for nonce in block:
stats.checks += 1
h = double_sha256(header, nonce)
if h.startswith(TARGET_PREFIX):
stats.time = time.perf_counter() - start
stats.success = True
return stats
if h.startswith(short_prefix):
break
stats.time = time.perf_counter() - start
return stats
# =====================================
# Run a simulation using a common list of headers.
# =====================================
def run_simulation_with_header_list() -> Dict[str, Statistics]:
header_list = [generate_blockheader() for _ in range(HEADER_LIST_SIZE)]
nonces = list(range(TOTAL_NONCES))
seq_total_checks, seq_total_time, seq_success = 0, 0.0, False
for header in header_list:
stats = sequential_method(header, nonces)
seq_total_checks += stats.checks
seq_total_time += stats.time
if stats.success:
seq_success = True
break
pre_total_checks, pre_total_time, pre_success = 0, 0.0, False
for header in header_list:
stats = prefix_method(header, nonces)
pre_total_checks += stats.checks
pre_total_time += stats.time
if stats.success:
pre_success = True
break
return {
"sequential": Statistics("Sequential", seq_total_checks, seq_total_time, seq_success),
"prefix": Statistics("Prefix", pre_total_checks, pre_total_time, pre_success)
}
# =====================================
# Main function: runs all simulations and prints results.
# =====================================
def main():
print(f"""
=== Configuration ===
Total Nonces: {TOTAL_NONCES:,}
Block size: {BLOQUE_SIZE:,}
Complete Target: "{TARGET_PREFIX}"
Short Prefix: "{TARGET_PREFIX[:PREFIX_LENGTH]}"
Simulations: {SIMULATIONS}
Header List Size: {HEADER_LIST_SIZE}
""")
wins = {"sequential": 0, "prefix": 0}
total_checks = {"sequential": 0, "prefix": 0}
total_time = {"sequential": 0.0, "prefix": 0.0}
for i in range(SIMULATIONS):
result = run_simulation_with_header_list()
seq_stats = result["sequential"]
pre_stats = result["prefix"]
total_checks["sequential"] += seq_stats.checks
total_checks["prefix"] += pre_stats.checks
total_time["sequential"] += seq_stats.time
total_time["prefix"] += pre_stats.time
winner = "None"
if seq_stats.success and not pre_stats.success:
wins["sequential"] += 1
winner = "Sequential"
elif pre_stats.success and not seq_stats.success:
wins["prefix"] += 1
winner = "Prefix"
elif seq_stats.success and pre_stats.success:
if seq_stats.checks < pre_stats.checks:
wins["sequential"] += 1
winner = "Sequential"
elif pre_stats.checks < seq_stats.checks:
wins["prefix"] += 1
winner = "Prefix"
else:
winner = "Tie"
print(f"\nSimulation {i+1}:")
print(f" Sequential: Checks = {seq_stats.checks} | Time = {seq_stats.time:.4f}s | Success = {seq_stats.success}")
print(f" Prefix: Checks = {pre_stats.checks} | Time = {pre_stats.time:.4f}s | Success = {pre_stats.success}")
print(f" Winner: {winner}")
print("\n=== Final Results ===")
print(f"Sequential Wins: {wins['sequential']}/{SIMULATIONS}")
print(f"Prefix Wins: {wins['prefix']}/{SIMULATIONS}")
print("\nAverage Metrics:")
for method in ["sequential", "prefix"]:
avg_checks = total_checks[method] / max(wins[method], 1)
avg_time = total_time[method] / max(wins[method], 1)
print(f"\nMethod {method.capitalize()}:")
print(f" Average Checks: {avg_checks:,.0f}")
print(f" Average Time: {avg_time:.4f}s")
if __name__ == "__main__":
main()