import hashlib
import json
from time import time
class Blockchain(object):
def __init__(self):
self.current_transactions = []
self.chain = []
# Create the genesis block
self.new_block(proof=100, previous_hash=1)
def new_block(self, proof, previous_hash=None):
"""
Create a new block into the blockchain
:param proof: <int> Proof generated by working proof algorithm
:param previous_hash: (Optional) <str> Of the previous block hash value
:return: <dict> New area block
"""
block = {
'index': len(self.chain) + 1,
'timestamp': time(),
'transactions': self.current_transactions,
'proof': proof,
'previous_hash': previous_hash or self.hash(self.chain[-1]),
}
# Reset current transaction
self.current_transactions = []
self.chain.append(block)
return block
def new_transaction(self, sender, recipient, amount):
"""
Create a new transaction to the next mining block
:param sender: <str> Address of sender
:param recipient: <str> The address of the recipient
:param amount: <int> amount of money
:return: <int> Hold the block index of this transaction
"""
self.current_transactions.append({
'sender': sender,
'recipient': recipient,
'amount': amount,
})
return self.last_block['index'] + 1
@property
def last_block(self):
return self.chain[-1]
@staticmethod
def hash(block):
"""
Generate... For a block SHA-256 value
:param block: <dict> Block
:return: <str>
"""
# We must make sure that this dictionary ( block ) It's sorted , Otherwise we will get inconsistent hashes
block_string = json.dumps(block, sort_keys=True).encode()
return hashlib.sha256(block_string).hexdigest()
def proof_of_work(self, last_proof):
"""
Simple Proof of Work Algorithm:
- Find a number p' such that hash(pp') contains leading 4 zeroes, where p is the previous p'
- p is the previous proof, and p' is the new proof
:param last_proof: <int>
:return: <int>
"""
proof = 0
while self.valid_proof(last_proof, proof) is False:
proof += 1
return proof
@staticmethod
def valid_proof(last_proof, proof):
"""
Validates the Proof: Does hash(last_proof, proof) contain 4 leading zeroes?
:param last_proof: <int> Previous Proof
:param proof: <int> Current Proof
:return: <bool> True if correct, False if not.
"""
guess = '{last_proof}{proof}'.format(last_proof=last_proof, proof=proof).encode()
guess_hash = hashlib.sha256(guess).hexdigest()
return guess_hash[:4] == "0000"
def chainIsValid(self):
"""
check hash proof
"""
for index in range(1, len(self.chain)):
currentBlock = self.chain[index]
previousBlock = self.chain[index-1]
previous_hash = currentBlock['previous_hash']
current_hash = self.hash(previousBlock)
previous_proof = previousBlock['proof']
current_proof = currentBlock['proof']
if (previous_hash != current_hash) and valid_proof(previous_proof, current_proof):
return False
else:
return True
if __name__=='__main__':
t = Blockchain()
t.new_transaction('a','b',1000)
previous_hash = t.hash(t.last_block)
last_proof = t.last_block['proof']
proof = t.proof_of_work(last_proof)
data = t.new_block(proof, previous_hash)
print(data)
print(t.chain)
t.new_transaction('a','c',80)
t.new_transaction('a','d',980)
previous_hash = t.hash(t.last_block)
last_proof = t.last_block['proof']
proof = t.proof_of_work(last_proof)
data = t.new_block(proof, previous_hash)
print(data)
print(t.chain)
t.new_transaction('a','e',280)
t.new_transaction('b','e',180)
previous_hash = t.hash(t.last_block)
last_proof = t.last_block['proof']
proof = t.proof_of_work(last_proof)
data = t.new_block(proof, previous_hash)
print(data)
print(t.chain)
t.new_transaction('d','e',810)
t.new_transaction('a','e',280)
previous_hash = t.hash(t.last_block)
last_proof = t.last_block['proof']
proof = t.proof_of_work(last_proof)
data = t.new_block(proof, previous_hash)
print(data)
print(t.chain)
t.new_transaction('b','a',2180)
t.new_transaction('c','d',1280)
previous_hash = t.hash(t.last_block)
last_proof = t.last_block['proof']
proof = t.proof_of_work(last_proof)
data = t.new_block(proof, previous_hash)
print(data)
print(t.chain)
print(t.chainIsValid())
for info in t.chain:
print(info['proof'])