124 lines
5.2 KiB
Python
124 lines
5.2 KiB
Python
import random
|
|
import sys
|
|
|
|
def test_strat(strat, hashpower, gamma, reward, fees, uncle_rewards=1, uncle_coeff=0, max_uncles=2, 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
|
|
# Total blocks included from attacker
|
|
me_totblocks = 0
|
|
# Total blocks included from others
|
|
them_totblocks = 0
|
|
# Uncles included from attacker
|
|
me_totuncles = 0
|
|
# Uncles included from others
|
|
them_totuncles = 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 - (reward if me_blocks and them_blocks else 0)
|
|
me_fees += time_elapsed * fees
|
|
divisor += me_blocks - (1 if me_blocks and them_blocks else 0)
|
|
me_totblocks += me_blocks
|
|
# Add uncles
|
|
while me_blocks < 7 and them_blocks > 0:
|
|
r = min(them_blocks, max_uncles) * (0.875 - 0.125 * me_blocks) * uncle_rewards
|
|
them_totuncles += min(them_blocks, max_uncles)
|
|
divisor += min(them_blocks, max_uncles) * uncle_coeff
|
|
them_reward = them_reward + r
|
|
them_blocks -= min(them_blocks, max_uncles)
|
|
me_blocks += 1
|
|
# Adopt
|
|
else:
|
|
them_reward += them_blocks * reward - (reward if me_blocks and them_blocks else 0)
|
|
them_fees += time_elapsed * fees
|
|
divisor += them_blocks - (1 if me_blocks and them_blocks else 0)
|
|
them_totblocks += them_blocks
|
|
# Add uncles
|
|
while them_blocks < 7 and me_blocks > 0:
|
|
r = min(me_blocks, max_uncles) * (0.875 - 0.125 * them_blocks) * uncle_rewards
|
|
me_totuncles += min(me_blocks, max_uncles)
|
|
divisor += min(me_blocks, max_uncles) * uncle_coeff
|
|
me_reward = me_reward + r
|
|
me_blocks -= min(me_blocks, max_uncles)
|
|
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 - (reward if me_blocks and them_blocks else 0)
|
|
me_totblocks += me_blocks
|
|
divisor += me_blocks - (1 if me_blocks and them_blocks else 0)
|
|
time_elapsed = 0
|
|
# Add uncles
|
|
while me_blocks < 7 and them_blocks > 0:
|
|
r = min(them_blocks, max_uncles) * (0.875 - 0.125 * me_blocks) * uncle_rewards
|
|
them_totuncles += min(them_blocks, max_uncles)
|
|
divisor += min(them_blocks, max_uncles) * uncle_coeff
|
|
them_reward = them_reward + r
|
|
them_blocks -= min(them_blocks, max_uncles)
|
|
me_blocks += 1
|
|
me_blocks = 0
|
|
them_blocks = 0
|
|
# print 'rat', (me_totblocks + me_totuncles) / (me_totblocks + me_totuncles + them_totblocks + them_totuncles * 1.0)
|
|
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, "max_uncles": 2}
|
|
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"], dic["max_uncles"], 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))
|