-
Notifications
You must be signed in to change notification settings - Fork 0
/
blockchain.py
121 lines (93 loc) · 3.72 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
import datetime
import hashlib
import json
from urllib.parse import urlparse
import requests
# Create a blockchain class
class Blockchain:
def __init__(self):
self.__LEADING_ZEROS = '0000'
self.__chain = []
self.__transactions = []
# Creates genesis block
self.add_block(proof=1, timestamp=str(
datetime.datetime.now()), previous_hash='0')
self.__nodes = set()
def get_chain(self):
return self.__chain
def get_nodes(self):
return self.__nodes
def add_block(self, proof, timestamp, previous_hash):
block = {'index': len(self.__chain) + 1,
'timestamp': timestamp,
'proof': proof,
'previous_hash': previous_hash,
'transactions': self.__transactions
}
self.__transactions = []
self.__chain.append(block)
return block
def get_last_block(self):
return self.__chain[-1]
def proof_of_work(self, previous_proof):
timestamp = datetime.datetime.now()
new_proof = 1
while True:
hash_operation = hashlib.sha256(
str(new_proof**2 - previous_proof**2).encode() + str(timestamp).encode()).hexdigest()
if hash_operation[:len(self.__LEADING_ZEROS)] == self.__LEADING_ZEROS:
return new_proof, str(timestamp)
new_proof += 1
# Check if one second has elapsed
current_time = datetime.datetime.now()
if current_time - timestamp >= datetime.timedelta(seconds=1):
timestamp = current_time
new_proof = 1
# Hashes block with all properties of block object(index, timestamp, proof, previous_hash etc.)
def hash(self, block):
encoded_block = json.dumps(block, sort_keys=True).encode()
return hashlib.sha256(encoded_block).hexdigest()
def is_chain_valid(self, chain):
previous_block = chain[0]
current_block_index = 1
while current_block_index < len(chain):
current_block = chain[current_block_index]
if current_block['previous_hash'] != self.hash(previous_block):
return False
previous_proof = previous_block['proof']
current_proof = current_block['proof']
timestamp = current_block['timestamp']
hash_operation = hashlib.sha256(
str(current_proof**2 - previous_proof**2).encode() + str(timestamp).encode()).hexdigest()
if(hash_operation[:len(self.__LEADING_ZEROS)] != self.__LEADING_ZEROS):
return False
previous_block = current_block
current_block_index += 1
return True
def add_transaction(self, sender, receiver, amount):
self.__transactions.append({
'sender': sender,
'receiver': receiver,
'amount': amount
}
)
last_block = self.get_last_block()
return last_block['index'] + 1
def add_node(self, address):
parsed_url = urlparse(address)
self.__nodes.add(parsed_url.netloc)
def replace_chain(self):
longest_chain = None
max_length = len(self.__chain)
for node in self.__nodes:
response = requests.get(f'http://{node}/get-chain')
if response.status_code == 200:
chain_length = response.json()['chain_length']
chain = response.json()['chain']
if chain_length > max_length and self.is_chain_valid(chain):
max_length = chain_length
longest_chain = chain
if longest_chain:
self.__chain = longest_chain
return True
return False