-
Notifications
You must be signed in to change notification settings - Fork 52
/
selfish_mining_strats.py
104 lines (100 loc) · 4.08 KB
/
selfish_mining_strats.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
import random
import sys
def test_strat(strat, hashpower, gamma, reward, fees, uncle_rewards=1, uncle_coeff=0, rounds=25000):
# Block reward for attacker
me_reward = 0
# Block reward for others
them_reward = 0
# Fees for the attacker
me_fees = 0
# Fees for others
them_fees = 0
# Blocks in current private chain
me_blocks = 0
# Blocks in current public chain
them_blocks = 0
# Time elapsed since last chain merging
time_elapsed = 0
# Divisor for block rewards (diff adjustment)
divisor = 0
# Simulate the system
for i in range(rounds):
# Attacker makes a block
if random.random() < hashpower:
me_blocks += 1
last_is_me = 1
# Honest nodes make a block
else:
them_blocks += 1
last_is_me = 0
time_elapsed += random.expovariate(1)
# "Adopt" or "override"
if me_blocks >= len(strat) or them_blocks >= len(strat[me_blocks]) or strat[me_blocks][them_blocks] == 1:
# Override
if me_blocks > them_blocks or (me_blocks == them_blocks and random.random() < gamma):
me_reward += me_blocks * reward
me_fees += time_elapsed * fees
divisor += me_blocks
# Add uncles
while me_blocks < 7 and them_blocks > 0:
r = min(them_blocks, 2) * (0.875 - 0.125 * me_blocks) * uncle_rewards
divisor += min(them_blocks, 2) * uncle_coeff
them_reward = them_reward + r
them_blocks, me_blocks = them_blocks - 2, me_blocks + 1
# Adopt
else:
them_reward += them_blocks * reward
them_fees += time_elapsed * fees
divisor += them_blocks
# Add uncles
while them_blocks < 7 and me_blocks > 0:
r = min(me_blocks, 2) * (0.875 - 0.125 * them_blocks) * uncle_rewards
divisor += min(me_blocks, 2) * uncle_coeff
me_reward = me_reward + r
me_blocks, them_blocks = me_blocks - 2, them_blocks + 1
me_blocks = 0
them_blocks = 0
time_elapsed = 0
# Match
elif strat[me_blocks][them_blocks] == 2 and not last_is_me:
if random.random() < gamma:
me_reward += me_blocks * reward + time_elapsed * fees
divisor += me_blocks
me_blocks = 0
them_blocks = 0
time_elapsed = 0
# Add uncles
while me_blocks < 7 and them_blocks > 0:
r = min(them_blocks, 2) * (0.875 - 0.125 * me_blocks)
divisor += min(them_blocks, 2) * uncle_coeff
them_reward = them_reward + r
them_blocks, me_blocks = them_blocks - 2, me_blocks + 1
return me_reward / divisor + me_fees / rounds, them_reward / divisor + them_fees / rounds
# A 20x20 array meaning "what to do if I made i blocks and the network
# made j blocks?". 1 = publish, 0 = do nothing.
def gen_selfish_mining_strat():
o = [([0] * 20) for i in range(20)]
for me in range(20):
for them in range(20):
# Adopt
if them == 1 and me == 0:
o[me][them] = 1
if them == me + 1:
o[me][them] = 1
# Overtake
if me >= 2 and me == them + 1:
o[me][them] = 1
# Match
if me >= 1 and me == them:
o[me][them] = 2
return o
dic = {"rewards": 1, "fees": 0, "gamma": 0.5, "uncle_coeff": 0, "uncle_rewards": 0}
for a in sys.argv[1:]:
param, val = a[:a.index('=')], a[a.index('=')+1:]
dic[param] = float(val)
print dic
s = gen_selfish_mining_strat()
for i in range(1, 50):
x, y = test_strat(s, i * 0.01, dic["gamma"], dic["rewards"], dic["fees"], dic["uncle_rewards"], dic["uncle_coeff"], rounds=200000)
print '%d%% hashpower, %f%% of rewards, (%f attacker, %f honest)' % \
(i, x * 100.0 / (x + y), x * 100.0 / i, y * 100.0 / (100-i))