-
Notifications
You must be signed in to change notification settings - Fork 0
/
blockchain.py
160 lines (154 loc) · 7.35 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
152
153
154
155
156
157
158
159
160
import hashlib
import json
import time
from flask.json import jsonify
import requests
from flask.globals import request
import random
import socket
# Blockchain class which has all attributes of the blockchain network
class Blockchain(object):
def __init__(self):
# get self address for node
self.address = socket.gethostbyname(socket.gethostname())
# chain is array of blocks. It has index,timestamp,transactions,proof,previous_hash
self.chain = []
# it is all nodes in the network. When you change the network it would be changed also
self.nodes = []
# transactions are used for sending and receiving money. Every block record transactions.
# For ex. if you want to check balance of your wallet , you need to query all of your questions and get the result.
self.transactions = []
# it is stated for election records.
self.elections = []
# Create genesis(first) block.
self.new_block(previous_hash=0)
# when elect state true all transaction are stopped and chain create new block.
self.elect_state = False
# election finishes when deadline occured
# it must be epoch time.
self.election_deadline = 0
# this function adds new blocks to the chain
def new_block(self,previous_hash):
# sealing last block. After sealing new empty new block will be added to block and this block cannot be tampered.
block = {
# index of the block
"index": len(self.chain) + 1,
# creating time as epoch time.
"timestamp": time.time() ,
# all transactions of the last block.
"transactions": self.transactions,
# hash of the previous block. If you change anything on any block all hashes will be change. So it is the proof of consistency
"previous_hash": previous_hash
}
# reset transactions because last block sealed and you need o create new block
self.transactions = []
# add new empty block to chain
self.chain.append(block)
self.new_transaction(sender=0,receiver=self.address,amount=1)
return block
# this function creates new transaction
def new_transaction(self,sender,receiver,amount):
#add a new transaction to current block.
self.transactions.append({
# sender wallet code
"sender": sender,
# receiver wallet code
"receiver": receiver,
# amount
"amount": amount,
})
print("Transaction is going to be synchronized:"+str({"sender": sender, "receiver": receiver,"amount": amount }))
# sync with all nodes
for node in self.nodes:
sync_data = {"sender":sender,"receiver":receiver,"amount":amount}
r = requests.post("http://"+node+":5000/sync/transaction", data = sync_data ,timeout=1)
if r.status_code == 200:
print("Transaction has been synchronized with that node:"+node)
# return last block index(id) of the blockchain
return self.chain[-1]['index'] + 1
# hash the all block
def hash(self,block):
block_string = json.dumps(block,sort_keys=True).encode()
return hashlib.sha256(block_string).hexdigest()
# just add node to nodes array
def register_node(self, address):
self.nodes.append(address)
# control new nodes chain(think like a database) if it is valid
def valid_node(self,chain):
# control every single block previous_hash in the block chain.
control_block = chain[0]
for block in chain:
if block["previous_hash"] != self.hash(control_block):
return False
return True
# Consensus Algorithm. For now it longest one would be winner and the longest one would be authorative
def resolve_conflicts(self):
# get neighbours from nodes array
neighbours = self.nodes
new_chain = None
# We're only looking for chains longer than ours
max_length = len(self.chain)
# control every node
for node in neighbours:
response = requests.get( node+"/chain" )
# if node responded with code 200 look at the length and chain
if response.status_code == 200:
# get neighbour's chain length and chains.
length = response.json()['length']
chain = response.json()['chain']
# If neighbours node is longer than ours we consider it authoritive node and replicate information from the neighbour.
if self.valid_node(chain) and length > max_length:
new_chain = chain
max_length = len(new_chain)
if new_chain:
self.chain = new_chain
return True
return False
# when transactions has been done , blockchain's state set to election state.
# Every node elect a node randomly and stream it to the blockchain network.
def elect_state_sender(self):
vote = random.randint(0,len(self.nodes)-1)
election_record = {"vote":vote,"node":self.address}
# send every node to my vote
for node in self.nodes:
r = requests.post("http://"+node+":5000/election/vote", data = election_record,timeout=1)
if r.status_code == 200:
print("Stream has been sent to node:"+node)
else:
print("Stream could not sent to node:"+node)
def leader_control(self):
max = 0
leader = self.nodes[0]
for node in self.nodes:
if self.nodes.count(node) > max:
max = self.nodes.count(node)
leader = node
elif self.nodes.count(node) == max:
# if vote counts are equal , select min of two nodes.
leader = min(leader,node)
return leader
# this functions control if this node is leader or not.
# If leader is ownself , send stream to network
def declare_leader_control(self):
while 1:
if round(time.time()) < self.election_deadline :
print("Chain Network is in elect state. Waiting for leader control.")
time.sleep(5)
else:
self.elect_state = False
if self.address == self.leader_control():
for node in self.nodes:
mine_data = {"leader":self.address,"receiver":self.address}
r = requests.post("http://"+node+":5000/mine", json = mine_data,timeout=1)
if r.status_code == 200:
print("Stream has been sent to node:"+node)
else:
print("Stream could not sent to node:"+node)
print("The node is no more in elect state.")
break
# this function synchronizes transactions of other nodes
def sync_transaction(self,sender,receiver,amount):
transaction = {"sender": sender,"receiver": receiver,"amount": amount}
self.transactions.append(transaction) if transaction not in self.transactions else self.transactions
print("Transaction is synchronized:"+str(transaction))
return True