-
Notifications
You must be signed in to change notification settings - Fork 36
/
blockchain.py
151 lines (114 loc) · 4.22 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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import time
import hashlib
class Block(object):
def __init__(self, index, proof, previous_hash, transactions, timestamp=None):
self.index = index
self.proof = proof
self.previous_hash = previous_hash
self.transactions = transactions
self.timestamp = timestamp or time.time()
@property
def get_block_hash(self):
block_string = "{}{}{}{}{}".format(self.index, self.proof, self.previous_hash, self.transactions, self.timestamp)
return hashlib.sha256(block_string.encode()).hexdigest()
def __repr__(self):
return "{} - {} - {} - {} - {}".format(self.index, self.proof, self.previous_hash, self.transactions, self.timestamp)
class BlockChain(object):
def __init__(self):
self.chain = []
self.current_node_transactions = []
self.nodes = set()
self.create_genesis_block()
@property
def get_serialized_chain(self):
return [vars(block) for block in self.chain]
def create_genesis_block(self):
self.create_new_block(proof=0, previous_hash=0)
def create_new_block(self, proof, previous_hash):
block = Block(
index=len(self.chain),
proof=proof,
previous_hash=previous_hash,
transactions=self.current_node_transactions
)
self.current_node_transactions = [] # Reset the transaction list
self.chain.append(block)
return block
@staticmethod
def is_valid_block(block, previous_block):
if previous_block.index + 1 != block.index:
return False
elif previous_block.get_block_hash != block.previous_hash:
return False
elif not BlockChain.is_valid_proof(block.proof, previous_block.proof):
return False
elif block.timestamp <= previous_block.timestamp:
return False
return True
def create_new_transaction(self, sender, recipient, amount):
self.current_node_transactions.append({
'sender': sender,
'recipient': recipient,
'amount': amount
})
return True
@staticmethod
def is_valid_transaction():
# Not Implemented
pass
@staticmethod
def create_proof_of_work(previous_proof):
"""
Generate "Proof Of Work"
A very simple `Proof of Work` Algorithm -
- Find a number such that, sum of the number and previous POW number is divisible by 7
"""
proof = previous_proof + 1
while not BlockChain.is_valid_proof(proof, previous_proof):
proof += 1
return proof
@staticmethod
def is_valid_proof(proof, previous_proof):
return (proof + previous_proof) % 7 == 0
@property
def get_last_block(self):
return self.chain[-1]
def is_valid_chain(self):
"""
Check if given blockchain is valid
"""
previous_block = self.chain[0]
current_index = 1
while current_index < len(self.chain):
block = self.chain[current_index]
if not self.is_valid_block(block, previous_block):
return False
previous_block = block
current_index += 1
return True
def mine_block(self, miner_address):
# Sender "0" means that this node has mined a new block
# For mining the Block(or finding the proof), we must be awarded with some amount(in our case this is 1)
self.create_new_transaction(
sender="0",
recipient=miner_address,
amount=1,
)
last_block = self.get_last_block
last_proof = last_block.proof
proof = self.create_proof_of_work(last_proof)
last_hash = last_block.get_block_hash
block = self.create_new_block(proof, last_hash)
return vars(block) # Return a native Dict type object
def create_node(self, address):
self.nodes.add(address)
return True
@staticmethod
def get_block_object_from_block_data(block_data):
return Block(
block_data['index'],
block_data['proof'],
block_data['previous_hash'],
block_data['transactions'],
timestamp=block_data['timestamp']
)