76 lines
2.2 KiB
Python
76 lines
2.2 KiB
Python
import asyncio
|
|
import logging
|
|
import multiprocessing
|
|
from datetime import datetime
|
|
|
|
from helpers import hash_block
|
|
from tasks import we_should_still_be_mining
|
|
|
|
|
|
log = logging.getLogger('root.mining')
|
|
|
|
|
|
def proof_of_work(current_block, difficulty, event):
|
|
"""
|
|
Simple Proof of Work Algorithm
|
|
|
|
:param current_block: The partially complete block currently being mined
|
|
:param difficulty: The minimum number of leading zeros
|
|
"""
|
|
|
|
# String of 64 f's replaced with 3 leading zeros (if the difficulty is 3): 000fff...f
|
|
target = str.ljust("0" * difficulty, 64, "f")
|
|
|
|
guess_hash = hash_block(current_block)
|
|
|
|
while guess_hash > target:
|
|
# Check if we should still be mining
|
|
# if not event.is_set():
|
|
# raise Exception("STOP MINING")
|
|
current_block['timestamp'] = datetime.utcnow()
|
|
current_block['proof'] += 1
|
|
guess_hash = hash_block(current_block)
|
|
|
|
current_block['hash'] = guess_hash
|
|
return current_block
|
|
|
|
|
|
def miner(pipe, event):
|
|
while True:
|
|
task = pipe.recv()
|
|
log.debug(f"Received new mining task with difficulty {task['difficulty']}")
|
|
|
|
if task:
|
|
found_block = proof_of_work(task['block'], task['difficulty'], event)
|
|
pipe.send({'found_block': found_block})
|
|
|
|
|
|
async def mining_controller(app):
|
|
pipe, remote_pipe = multiprocessing.Pipe()
|
|
event = multiprocessing.Event()
|
|
|
|
# Spawn a new process consisting of the miner() function
|
|
# and send the right end of the pipe to it
|
|
process = multiprocessing.Process(target=miner, args=(remote_pipe, event))
|
|
process.start()
|
|
|
|
pipe.send({'block': app.blockchain.build_block(), 'difficulty': 5})
|
|
|
|
while True:
|
|
event.set()
|
|
|
|
# We'll check the pipe every 100 ms
|
|
await asyncio.sleep(0.1)
|
|
|
|
# Check if we should still be mining
|
|
if not we_should_still_be_mining():
|
|
event.clear()
|
|
|
|
if pipe.poll():
|
|
result = pipe.recv()
|
|
found_block = result['found_block']
|
|
|
|
app.blockchain.save_block(found_block)
|
|
log.info(f"Mined Block {found_block['height']} containing {len(found_block['transactions'])} transactions")
|
|
pipe.send({'block': app.blockchain.build_block(), 'difficulty': 5})
|