-
Notifications
You must be signed in to change notification settings - Fork 0
/
receiver.py
87 lines (74 loc) · 3.71 KB
/
receiver.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
import socket, sys
import config
import json
from block import *
import logging
from block_type import *
logger = logging.getLogger()
class Rec():
def __init__(self, user_id, blockchain, peers_list, client, sender):
self.client = client
self.peers_list = peers_list
self.user_id = user_id
self.blockchain = blockchain
self.patchRequests = {}
self.sender = sender
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
#self.sock.settimeout(2)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
self.sock.bind(('', config.UDP_PORT))
def get_message(self):
try:
data, address = self.sock.recvfrom(1024) # buffer size is 1024 bytes TODO : make this bigger?
obj = json.loads(data)
except :
e = sys.exc_info()[0]
logger.info(e)
return
if "user_id" in obj :
if obj["block_type"] == BlockType.heartbeat:
#logger.info("%s - Recieved HEARTBEAT: %s" % (self.user_id, data))
if obj["proposed_block"]:
# TODO : put this into block class
pb = obj["proposed_block"]
block = Block(pb["block_type"], pb["user_id"], pb["prior_hash"], pb["payload"])
self.peers_list.add_peer(obj["user_id"], obj["prior_hash"], block)
else: # this is the vanilla heartbeat case
self.peers_list.add_peer(obj["user_id"], obj["prior_hash"])
if obj["block_type"] == BlockType.message and obj["user_id"] != self.user_id :
# TODO : Don't over write if you're waiting for a message to get accepted
if self.blockchain.proposal_allowed():
logger.info("%s - Received MESSAGE: %s" % (self.user_id, data))
last_hash = None
if not self.blockchain.is_empty():
last_hash = self.blockchain.peek().hash()
if not last_hash or last_hash == obj["prior_hash"] or obj["prior_hash"] == "":
block = Block(BlockType.message, obj["user_id"], obj["prior_hash"], obj["payload"])
self.blockchain.propose_block(block)
if obj["block_type"] == BlockType.requestHistory:
# Someone is requesting the history so be a nice person and send it
self.sender.send_history(obj["payload"]["hash"])
if obj["block_type"] == BlockType.sendHistory:
# Some nice person sent a history of the blockchain
block = Block(BlockType.message, obj["user_id"], obj["prior_hash"], obj["payload"])
if block.hash() in self.patchRequests:
del self.patchRequests[block.hash()]
self.blockchain.patch(block)
self.run_consensus()
self.client.update()
self.repair()
def run_consensus(self):
self.peers_list.purge_peers()
(last_hash, block) = self.peers_list.get_consensus()
self.blockchain.verify_last_hash(last_hash)
if block:
# Always accept the group consensus
self.blockchain.accept_proposed_block(block)
def repair(self):
for nsync in self.blockchain.get_all_nsyncs():
_hash = nsync.hash()
self.patchRequests[_hash] = self.patchRequests[_hash] + 1 if _hash in self.patchRequests else 1
# Limit number of times you can request a block
if self.patchRequests[_hash] < 5 and nsync.blocksRequested < nsync.maxRequests:
self.sender.request_history(_hash)