-
Notifications
You must be signed in to change notification settings - Fork 0
/
blockchain.py
102 lines (83 loc) · 3.05 KB
/
blockchain.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import hashlib
import json
from time import time
class Block:
def __init__(self, index, transactions, timestamp, previous_hash):
self.index = index
self.transactions = transactions
self.timestamp = timestamp
self.previous_hash = previous_hash
self.nonce = 0
self.hash = self.compute_hash()
def compute_hash(self):
"""
A function that returns the hash of the block contents.
"""
block_string = json.dumps(self.__dict__, sort_keys=True)
return hashlib.sha256(block_string.encode()).hexdigest()
def mine_block(self, difficulty):
"""
A function that mines a new block.
"""
while self.compute_hash()[:difficulty] != '0' * difficulty:
self.nonce += 1
return self
class Blockchain:
def __init__(self):
self.difficulty = 2 # Adjust the difficulty to control mining speed.
self.unconfirmed_transactions = []
self.chain = [self.create_genesis_block()]
def create_genesis_block(self):
"""
A function to generate genesis block.
"""
return Block(0, [], time(), "0")
def add_block(self, block, proof):
"""
A function to add a new block to the chain.
"""
previous_hash = self.chain[-1].hash
if previous_hash != block.previous_hash:
return False
if not self.is_valid_proof(block, proof):
return False
self.chain.append(block)
return True
def is_valid_proof(self, block, block_hash):
"""
Check if block_hash is valid hash of block and satisfies
the difficulty criteria.
"""
return (block_hash.startswith('0' * self.difficulty) and
block_hash == block.compute_hash())
def proof_of_work(self, block):
"""
Function that tries different values of nonce to get a hash
that satisfies our difficulty criteria.
"""
block.nonce = 0
computed_hash = block.compute_hash()
while not computed_hash.startswith('0' * self.difficulty):
block.nonce += 1
computed_hash = block.compute_hash()
return computed_hash
def add_new_transaction(self, transaction):
self.unconfirmed_transactions.append(transaction)
def mine(self, difficulty):
"""
This function serves as an interface to add the pending
transactions to the blockchain by adding them to the block
and figuring out Proof Of Work.
"""
if not self.unconfirmed_transactions:
return False
last_block = self.chain[-1]
new_block = Block(index=last_block.index + 1,
transactions=self.unconfirmed_transactions,
timestamp=time(),
previous_hash=last_block.hash)
new_block.mine_block(difficulty)
proof = self.proof_of_work(new_block)
self.add_block(new_block, proof)
self.unconfirmed_transactions = []
return new_block.hash