POW 共识算法实现
This commit is contained in:
parent
3979bfd2ac
commit
00fcf3962c
115
POW/blockChain.py
Normal file
115
POW/blockChain.py
Normal file
@ -0,0 +1,115 @@
|
||||
import hashlib
|
||||
import requests
|
||||
import json
|
||||
from hashlib import sha256
|
||||
from time import time
|
||||
from urllib.parse import urlparse
|
||||
|
||||
|
||||
class Blockchain(object):
|
||||
def __init__(self):
|
||||
self.chain = [{'index': 0,
|
||||
'timestamp': time(),
|
||||
'transactions': 0,
|
||||
'proof': 0,
|
||||
'previous_hash': 0}]
|
||||
self.current_transactions = []
|
||||
self.nodes = set()
|
||||
|
||||
# create a new node based on url
|
||||
def register_node(self, address):
|
||||
parsed_url = urlparse(address)
|
||||
self.nodes.add(parsed_url.netloc)
|
||||
|
||||
# create a new block and add it to the chain.
|
||||
def new_block(self, proof, previous_hash):
|
||||
block = {
|
||||
'index': len(self.chain) + 1,
|
||||
'timestamp': time(),
|
||||
'transactions': self.current_transactions,
|
||||
'proof': proof,
|
||||
'previous_hash': previous_hash or self.hash(self.chain[-1])
|
||||
}
|
||||
|
||||
self.current_transactions = []
|
||||
|
||||
self.chain.append(block)
|
||||
return block
|
||||
|
||||
# add a new transaction to the list of transactions.
|
||||
def new_transaction(self, sender, recipient, amount):
|
||||
self.current_transactions.append({
|
||||
'sender': sender,
|
||||
'recipient': recipient,
|
||||
'amount': amount
|
||||
})
|
||||
|
||||
return self.last_block['index'] + 1
|
||||
|
||||
# PoW algo that increments proof value until valid_proof returns true.
|
||||
def proof_of_work(self, last_proof):
|
||||
proof = 0
|
||||
while self.valid_proof(last_proof, proof) is False:
|
||||
proof += 1
|
||||
|
||||
return proof
|
||||
|
||||
# verify the current chain has not already been solved
|
||||
def valid_chain(self, chain):
|
||||
last_block = chain[0]
|
||||
current_index = 1
|
||||
|
||||
while current_index < len(chain):
|
||||
block = chain[current_index]
|
||||
if block['previous_hash'] != self.hash(last_block):
|
||||
return False
|
||||
|
||||
# verify values in the chain are correct
|
||||
if not self.valid_proof(last_block['proof'], block['proof']):
|
||||
return False
|
||||
|
||||
last_block = block
|
||||
current_index += 1
|
||||
return True
|
||||
|
||||
# consensus algo to prevent conflicts when multiple nodes are in a network
|
||||
def resolve_conflicts(self):
|
||||
neighbors = self.nodes
|
||||
new_chain = None
|
||||
max_length = len(self.chain)
|
||||
|
||||
# check each node to find the longest chain
|
||||
for node in neighbors:
|
||||
response = requests.get(f'http://{node}/chain')
|
||||
|
||||
if response.status_code == 200:
|
||||
length = response.json()['length']
|
||||
chain = response.json()['chain']
|
||||
|
||||
if length > max_length and self.valid_chain(chain):
|
||||
max_length = length
|
||||
new_chain = chain
|
||||
if new_chain:
|
||||
self.chain = new_chain
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
# checks if the hash has 4 leading zeros. returns boolean.
|
||||
@staticmethod
|
||||
def valid_proof(last_proof, proof):
|
||||
guess = f'{last_proof}{proof}'.encode()
|
||||
guess_hash = hashlib.sha256(guess).hexdigest()
|
||||
# the addition of leading zeros can make a massive difference to the time required to find a solution.
|
||||
return guess_hash[:4] == "0000"
|
||||
|
||||
# hashes a block
|
||||
@staticmethod
|
||||
def hash(block):
|
||||
block_string = json.dumps(block, sort_keys=True).encode()
|
||||
return sha256(block_string).hexdigest()
|
||||
|
||||
# returns the last block of the chain
|
||||
@property
|
||||
def last_block(self):
|
||||
return self.chain[-1]
|
Loading…
Reference in New Issue
Block a user