Home > Crypto > Python Blockchain Implementation: Dynamic Wallets, Multi-Process Mining, and Scalability Enhancements (Part 2)

Python Blockchain Implementation: Dynamic Wallets, Multi-Process Mining, and Scalability Enhancements (Part 2)

Executive Summary

Building on the foundational framework established in Part 1, this installment advances the system toward production viability by addressing key limitations: static wallet management and single-process execution. We introduce a dynamic wallet ecosystem supporting unlimited generation via BIP39 mnemonic phrases for secure recovery, alongside multi-script decoupling for concurrent operations. A dedicated miner process enables background block production, simulating distributed consensus without full P2P overhead.

Preceding these core upgrades, we implement targeted enhancements: double-spend prevention, CLI wallet selection, and periodic backups for operational resilience. The result is a scalable prototype capable of handling multiple users and miners, with persistence intact.

Key specifications:

  • Dynamic Wallets: On-demand generation with 12-word BIP39 mnemonics; restoration from seed.
  • Multi-Process Mining: Independent miner.py for continuous PoW; integrates with main chain.
  • Enhancements: Balance checks on txn submission, indexed wallet picker, auto-backup every 5 blocks.
  • Dependencies: Existing (ecdsa, base58) + new (mnemonic, bip32utils for BIP39/BIP32).

New components: 2 scripts (wallet_gen.py, miner.py), ~150 additional LOC. Total framework: ~450 LOC.

System Architecture Updates

The enhanced architecture maintains modularity while introducing process isolation:

Module/ScriptFunctionalityCore Components
wallet_gen.py (New)Bulk mnemonic-based wallet generation and exportBIP39 seed derivation, private key files
miner.py (New)Background mining daemonInterval-based mine_pending(), chain sync
blockchain.py (Updated)Extended persistence and validationadd_wallet(), double-spend checks, backups
main.py (Updated)Enhanced CLI with wallet indexingPicker for txns/mining, restore command
Existing ModulesUnchanged core logicBlock, PoW, txn, wallet, utils

Process model: main.py (orchestrator), miner.py (worker), wallet_gen.py (utility)—runnable concurrently via terminals or multiprocessing.

Implementation Details

Pre-Enhancements: Resilience and Integrity

  1. Double-Spend Prevention: Transaction submission validates sender balance against chain state.
  2. CLI Wallet Picker: Indexed selection from persisted array; supports “Wallet1” aliases.
  3. Auto-Backup: Chain snapshot every 5 blocks to chain_backup_N.json.

Dynamic Wallets with BIP39 Recovery

  • Mnemonic Generation: 128-bit entropy → 12 English words (BIP39 standard).
  • Derivation Path: Mnemonic → PBKDF2 seed → BIP32 master key → child private/public keys.
  • Output: Displays mnemonic (backup), private hex/WIF, public hex, address; exports private to file.
  • Restoration: restore_wallet.py re-derives from mnemonic, integrates with chain.

Multi-Process Mining

  • Daemon Design: miner.py loads chain, mines at fixed intervals (default 30s), auto-saves.
  • Concurrency: Runs parallel to main.py; shared JSON for state (file locking recommended for prod).
  • Error Handling: Syncs on startup; retries failed mines.

Source Code Listings

Updated blockchain.py (Enhancements)

from block import Block
from proof_of_work import proof_of_work
from transaction import Transaction
from utils import GENESIS_DATA, calculate_reward, DIFFICULTY, HALVING_INTERVAL
from wallet import Wallet
from ecdsa import SigningKey, SECP256k1
import json
import os  # For backups

class Blockchain:
    def __init__(self):
        self.difficulty = DIFFICULTY
        self.chain = [self._create_genesis_block()]
        self.pending_transactions = []

    # ... (existing _create_genesis_block, get_latest_block, mine_pending, is_valid_chain, get_balance, save_chain, load_chain)

    def add_transaction(self, txn):
        # ENHANCEMENT: Double-spend prevention
        sender_balance = self.get_balance(txn.from_addr)
        if txn.from_addr != "network" and sender_balance < txn.amount:
            raise ValueError(f"Insufficient balance: {sender_balance} < {txn.amount}")
        self.pending_transactions.append(txn)

    def add_wallet(self, wallet):
        # ENHANCEMENT: Dynamic wallet append
        all_wallets = self.load_wallets() + [wallet]
        self.save_wallets(all_wallets)

    def get_all_wallets(self):
        return self.load_wallets()

    def mine_pending(self, miner_wallet):
        # ... (existing logic)
        self.chain.append(new_block)
        self.pending_transactions = []
        if len(self.chain) % HALVING_INTERVAL == 0:
            print(f"Halving! New reward: {calculate_reward(len(self.chain))}")
        self.save_chain()
        # ENHANCEMENT: Auto-backup every 5 blocks
        if len(self.chain) % 5 == 0:
            backup_file = f'chain_backup_{len(self.chain)}.json'
            self.save_chain(backup_file)
            print(f"Backup: {backup_file}")
        print(f"Auto-saved after mining Block {new_block.index}")

    # ... (existing save/load_wallets)

New: wallet_gen.py – Dynamic Mnemonic Wallets

from mnemonic import Mnemonic  # pip install mnemonic
from bip32utils import BIP32Key  # pip install bip32utils
from ecdsa import SigningKey, SECP256k1
from blockchain import Blockchain
import sys
import hashlib
import base58

def generate_wallets(n=1):
    mnemo = Mnemonic("english")
    bc = Blockchain()
    new_wallets = []
    for i in range(n):
        mnemonic = mnemo.generate(strength=128)
        print(f"\nWallet {i+1} Mnemonic: {mnemonic}")
        seed = mnemo.to_seed(mnemonic)
        master_key = BIP32Key.fromEntropy(seed)
        private_key_hex = master_key.PrivateKey().hex()
        w = Wallet()
        w.private_key = SigningKey.from_string(bytes.fromhex(private_key_hex), curve=SECP256k1)
        w.public_key = w.private_key.get_verifying_key()
        w.address = w.generate_address()
        print(f"Private Key (hex): {private_key_hex}")
        print(f"Public Key (hex): {w.public_key.to_string().hex()}")
        print(f"Address: {w.address}")
        print("WARNING: Secure mnemonic/private key.")
        with open(f"private_{w.address[:8]}.key", 'w') as f:
            f.write(private_key_hex)
        new_wallets.append(w)
    all_wallets = bc.load_wallets() + new_wallets
    bc.save_wallets(all_wallets)
    print(f"Generated {n} wallets (total: {len(all_wallets)}).")

if __name__ == "__main__":
    n = int(sys.argv[1]) if len(sys.argv) > 1 else 5
    generate_wallets(n)

New: miner.py – Multi-Process Mining Daemon

import time
from blockchain import Blockchain

def run_miner(miner_address, interval=30):
    bc = Blockchain()
    bc.load_chain()
    miner_wallet = Wallet()
    miner_wallet.address = miner_address
    print(f"Miner daemon started for {miner_address}. Interval: {interval}s")
    block_count = len(bc.chain)
    while True:
        bc.mine_pending(miner_wallet)
        print(f"Mined Block {len(bc.chain)} | Balance: {bc.get_balance(miner_address)}")
        time.sleep(interval)

if __name__ == "__main__":
    address = input("Miner address: ").strip()
    run_miner(address)

Updated main.py (CLI Picker)

# ... (existing imports and __init__)

# In while loop:
elif cmd == "txn":
    try:
        wallets = bc.get_all_wallets()
        print("Wallets:")
        for i, w in enumerate(wallets):
            print(f"{i}: {w.address} (Bal: {bc.get_balance(w.address)})")
        from_i = int(input("From index: "))
        to_i = int(input("To index: "))
        amount = float(input("Amount: "))
        new_tx = Transaction(wallets[from_i].address, wallets[to_i].address, amount)
        new_tx.sign_tx(wallets[from_i])
        bc.add_transaction(new_tx)
        print("Added to pending!")
    except (ValueError, IndexError) as e:
        print(f"Error: {e}")

elif cmd == "mined":
    wallets = bc.get_all_wallets()
    print("Wallets:")
    for i, w in enumerate(wallets):
        print(f"{i}: {w.address}")
    miner_i = int(input("Miner index: "))
    bc.mine_pending(wallets[miner_i])
    print(f"Mined! Length: {len(bc.chain)}")

restore_wallet.py (New: Recovery Tool)

from mnemonic import Mnemonic
from bip32utils import BIP32Key
from ecdsa import SigningKey, SECP256k1
import sys

def restore_wallet(mnemonic_phrase):
    mnemo = Mnemonic("english")
    if not mnemo.check(mnemonic_phrase):
        raise ValueError("Invalid mnemonic")
    seed = mnemo.to_seed(mnemonic_phrase)
    master_key = BIP32Key.fromEntropy(seed)
    private_key_hex = master_key.PrivateKey().hex()
    w = Wallet()
    w.private_key = SigningKey.from_string(bytes.fromhex(private_key_hex), curve=SECP256k1)
    w.public_key = w.private_key.get_verifying_key()
    w.address = w.generate_address()
    print(f"Restored: Address {w.address}, Private: {private_key_hex}")
    return w

if __name__ == "__main__":
    phrase = ' '.join(sys.argv[1:])
    if not phrase:
        phrase = input("Mnemonic: ")
    try:
        restore_wallet(phrase)
    except ValueError as e:
        print(f"Error: {e}")

Updated requirements.txt

ecdsa==0.18.0
base58==2.1
mnemonic==0.20
bip32utils==0.3.0.post1

Deployment and Validation Procedures

  1. Initialization:
  • Update files from Part 1.
  • Add new scripts.
  • pip install -r requirements.txt.
  1. Execution:
  • python main.py: Enhanced CLI.
  • Terminal 1: python main.py.
  • Terminal 2: python wallet_gen.py 5 (5 new wallets).
  • Terminal 3: python miner.py (enter address) → Background mining.
  1. Validation Tests:
  • Dynamic Wallets: Generate 3, list in CLI—total 5, balances 0.
  • Mining Process: Miner runs 2 blocks—main CLI shows length +2.
  • Recovery: python restore_wallet.py "abandon abandon ..." → Matches generated address.
  • Double-Spend: Txn > balance → ValueError.
  • Backup: Mine 5 blocks → chain_backup_5.json created.

Sample Execution Outputs

Wallet Generation (python wallet_gen.py 1)

“`
Wallet 1 Mnemonic: abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about

Private Key (hex): e9873d79c6d87

Leave a Comment