-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpeers_check.py
144 lines (144 loc) · 5.19 KB
/
peers_check.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
"""We regularly check on peers to see if they have mined new blocks.
This file explains how we initiate interactions with our peers.
"""
import time, networking, tools, blockchain, custom, random, sys
def cmd(peer, x):
return networking.send_command(peer, x)
def bounds(length, peers_block_count):
if peers_block_count - length > custom.download_many:
end = length + custom.download_many - 1
else:
end = peers_block_count
return [max(length - 2, 0), end+1]
def download_blocks(peer, DB, peers_block_count, length):
b=[max(0, length-10), min(peers_block_count['length'], length+custom.download_many)]
#tools.log('asked for: ' +str(b))
blocks = cmd(peer, {'type': 'rangeRequest',
'range': b})
if type(blocks)!=list:
#tools.log('unable to download blocks that time')
return -1
if not isinstance(blocks, list):
return []
for i in range(20): # Only delete a max of 20 blocks, otherwise a
# peer might trick us into deleting everything over and over.
if tools.fork_check(blocks, DB):
blockchain.delete_block(DB)
for block in blocks:
DB['suggested_blocks'].put([block, peer])
return 0
def ask_for_txs(peer, DB):
txs = cmd(peer, {'type': 'txs'})
if not isinstance(txs, list):
return -1
for tx in txs:
DB['suggested_txs'].put(tx)
pushers = [x for x in DB['txs'] if x not in txs]
for push in pushers:
cmd(peer, {'type': 'pushtx', 'tx': push})
return 0
def give_block(peer, DB, block_count_peer):
#cmd(peer, {'type': 'pushblock',
# 'block': tools.db_get(block_count_l + 1,
# DB)})
blocks=[]
#b=bounds(block_count_peer+1, DB['length'])
b=[max(block_count_peer+1, 0), min(DB['length'], block_count_peer+custom.download_many)]
for i in range(b[0], b[1]+1):
blocks.append(tools.db_get(i, DB))
cmd(peer, {'type': 'pushblock',
'blocks': blocks})
return 0
def peer_check(peer, DB):
block_count = cmd(peer, {'type': 'blockCount'})
if not isinstance(block_count, dict):
return
if 'error' in block_count.keys():
return
length = DB['length']
size = max(len(DB['diffLength']), len(block_count['diffLength']))
us = tools.buffer_(DB['diffLength'], size)
them = tools.buffer_(block_count['diffLength'], size)
if them < us:
return give_block(peer, DB, block_count['length'])
if us == them:
try:
return ask_for_txs(peer, DB)
except:
tools.log('ask for tx error')
try:
return download_blocks(peer, DB, block_count, length)
except:
tools.log('could not download blocks')
def exponential_random(weights):
def grab(r, weights, counter=0):
if len(weights)==0: return counter
if r<weights[0]: return counter
else: return grab(r-weights[0], weights[1:], counter+1)
#tools.log('weights: ' +str(weights))
weights=map(lambda x: 1.0/x, weights)
tot=sum(weights)
r=random.random()*tot
return grab(r, weights)
def main(peers, DB):
# Check on the peers to see if they know about more blocks than we do.
#DB['peers_ranked']=[]
for peer in peers:
p=tools.db_get('peers_ranked')
p.append([peer, 5])
tools.db_put('peers_ranked', p)
try:
while True:
if tools.db_get('stop'): return
if len(peers)>0:
main_once(peers, DB)
while not DB['reward_peers_queue'].empty():
q=DB['reward_peers_queue'].get()
p=q['peer']
d=q['do']
pr=tools.db_get('peers_ranked')
i=0
j='empty'
for p in pr:
if p[0]==peer:
j=i
i+=1
if j!='empty':
if d=='reward':
#listen more to people who give us good blocks.
pr[j][1]*=0.1
elif d=='punish':
#listen less to people who give us bad blocks.
pr[j][1]*=0.8
pr[j][1]+=0.2*60
tools.db_put('peers_ranked', pr)
else:
#maybe this peer should be added to our list of peers?
pass
except:
tools.log('main peers check: ' +str(sys.exc_info()))
def main_once(peers, DB):
#DB['peers_ranked']=sorted(DB['peers_ranked'], key=lambda r: r[1])
pr=tools.db_get('peers_ranked')
pr=sorted(pr, key=lambda r: r[1])
if DB['suggested_blocks'].empty():
time.sleep(10)
i=0
while not DB['suggested_blocks'].empty():
i+=1
time.sleep(0.1)
if i%100==0:
DB['heart_queue'].put('peers check')
#tools.log('suggested_blocks emptied at : ' +str(time.time()))
DB['heart_queue'].put('peers check')
i=exponential_random(map(lambda x: x[1], pr))
t1=time.time()
r=peer_check(pr[i][0], DB)
t2=time.time()
pr[i][1]*=0.8
if r==0:
pr[i][1]+=0.2*(t2-t1)
else:
pr[i][1]+=0.2*30
tools.db_put('peers_ranked', pr)
DB['heart_queue'].put('peers check')