校园项目自定义Bitcoin矿工:候选区块创建与提交方法及代码优化咨询
Hey there! Let's break down your questions step by step—building a Bitcoin miner for a campus project is a fantastic learning deep dive, so props for taking this on. I'll cover both creating/submitting candidate blocks and some solid code optimizations to make your miner more efficient.
Bitcoin blocks have a strict structure that your code needs to replicate before you can mine and submit one. Here's what you're missing:
Step 1: Understand the Full Block Structure
A valid Bitcoin block includes these core fields:
- Version: A number indicating the block protocol version (e.g.,
0x20000000for modern Bitcoin) - Previous Block Hash: The hash of the prior block in the chain (you have this already)
- Merkle Root: A single hash that summarizes all transactions in the block (critical—your current code just concatenates transactions, which isn't how Bitcoin does it)
- Timestamp: Unix timestamp when the block is created
- Difficulty Target: The required number of leading zeros (you're using
prefix_zeros, which is a simplified version) - Nonce: The number you're brute-forcing to get a valid hash
Step 2: Build the Block Header
To create a candidate block:
- Collect & Structure Transactions: Use your
transactiongetterto gather transactions, then format them into a list of strings (or objects) instead of a hardcoded string. For a campus project, you can skip full signature validation but should ensure each transaction follows a consistent format. - Compute the Merkle Root: Take all transaction hashes, pair them up, hash each pair, and repeat until you have one final hash (the Merkle root). This lets nodes quickly verify transactions without downloading the entire set.
- Fill the Header: Combine all the fields above into a single string/byte stream. This is what you'll hash with the nonce to find a valid block.
Step 3: Submit the Block
In the real Bitcoin network, you'd broadcast the valid block to connected nodes, which then verify it and add it to their chain. For your project:
- Create a simple "simulated node" function that checks if the block header hash meets the difficulty target, validates the Merkle root matches the transactions, and adds it to a local chain.
- You don't need to connect to the real Bitcoin network—focus on simulating the validation and chain storage logic for your project.
Your current code works, but here are some tweaks to make it faster and more aligned with real Bitcoin logic:
1. Optimize Hash Calculation
Your SHA256 function encodes text every time, which is inefficient. Instead, precompute the static part of the header and work with bytes where possible:
from hashlib import sha256 import time MAX_NONCE = 100000000000 def SHA256(data): if isinstance(data, str): data = data.encode("ascii") return sha256(data).hexdigest() # Precompute static header parts to avoid redundant string concatenation def mine(block_number, merkle_root, previous_hash, prefix_zeros): prefix_str = '0' * prefix_zeros static_header = f"{block_number}{merkle_root}{previous_hash}" for nonce in range(MAX_NONCE): text = f"{static_header}{nonce}" new_hash = SHA256(text) if new_hash.startswith(prefix_str): print(f"Yay! Successfully mined with nonce value: {nonce}") return new_hash, nonce raise Exception(f"Tried {MAX_NONCE} times and failed to find a valid nonce")
2. Add Proper Merkle Root Calculation
Replace your hardcoded transaction string with a Merkle root (this is how Bitcoin actually summarizes transactions):
def compute_merkle_root(transactions): if not transactions: return SHA256("") # Hash each individual transaction first hashes = [SHA256(tx) for tx in transactions] # Iteratively combine hashes until one remains while len(hashes) > 1: # Handle odd number of hashes by duplicating the last one if len(hashes) % 2 != 0: hashes.append(hashes[-1]) new_hashes = [] for i in range(0, len(hashes), 2): combined = hashes[i] + hashes[i+1] new_hashes.append(SHA256(combined)) hashes = new_hashes return hashes[0]
3. Parallelize Nonce Brute-Forcing
Brute-forcing nonces is CPU-intensive—use multi-processing to split the work across your machine's cores:
from multiprocessing import Pool def mine_worker(args): block_number, merkle_root, previous_hash, prefix_zeros, nonce_range = args prefix_str = '0' * prefix_zeros static_header = f"{block_number}{merkle_root}{previous_hash}" for nonce in nonce_range: text = f"{static_header}{nonce}" new_hash = SHA256(text) if new_hash.startswith(prefix_str): return (new_hash, nonce) return None def mine_parallel(block_number, merkle_root, previous_hash, prefix_zeros, num_processes=4): chunk_size = MAX_NONCE // num_processes nonce_ranges = [] for i in range(num_processes): start = i * chunk_size end = start + chunk_size if i != num_processes-1 else MAX_NONCE nonce_ranges.append((block_number, merkle_root, previous_hash, prefix_zeros, range(start, end))) with Pool(num_processes) as pool: results = pool.map(mine_worker, nonce_ranges) for result in results: if result is not None: print(f"Yay! Successfully mined with nonce value: {result[1]}") return result raise Exception(f"Tried {MAX_NONCE} times and failed to find a valid nonce")
4. Clean Up Transaction Handling
Avoid relying on global variables from transactiongetter—pass transactions explicitly for better readability:
from transactiongetter import inp, inpbit, out, outbit if __name__ == '__main__': # Structure transactions into a list instead of a hardcoded string transactions = [f"{tx_in} -> {tx_out} -> {tx_inbit}" for tx_in, tx_out, tx_inbit in zip(inp, out, inpbit)] merkle_root = compute_merkle_root(transactions) difficulty = 5 # Higher number = more difficulty start = time.time() print("Start mining...") # Use either mine() or mine_parallel() here new_hash, nonce = mine(5, merkle_root, '0000000xa036944e29568d0cff17edbe038f81208fecf9a66be9a2b8321c6ec7', difficulty) total_time = time.time() - start print(f"End mining. Mining took: {total_time:.2f} seconds") print(f"Block hash: {new_hash}") print(f"Nonce: {nonce}")
For your campus project, focus on simulating the core logic rather than connecting to the real Bitcoin network—full node integration is way more complex. Start with a local chain, add block validation, and expand features like difficulty adjustment if you have extra time.
内容的提问来源于stack exchange,提问作者Frantisek Mach




