-
Notifications
You must be signed in to change notification settings - Fork 52
/
slasher_withholding_exploit.py
43 lines (36 loc) · 1.36 KB
/
slasher_withholding_exploit.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
def fac(n): return 1 if n==0 else n * fac(n-1)
def choose(n,k): return fac(n) / fac(k) / fac(n-k)
def prob(n,k,p): return choose(n,k) * p ** k * (1-p) ** (n-k)
def prob_lt(n,k,p): return sum([prob(n,i,p) for i in range(p)])
SIGS = 30
ACTUALSIGS = 10
POWRETURN = 0.03
POSRETURN = 0.01
# Expected number of signatures on a block
def ev(pos):
return SIGS * pos
# Chance you have at least k sigs
def at_least_k(pos, k):
return sum([prob(SIGS, i, pos) for i in range(k, SIGS + 1)])
# Expected number of signatures on a block filtering all <k
def ev_atleast_k(pos, k):
total, subprob = 0, 0
for i in range(k, SIGS + 1):
p = prob(SIGS, i, pos)
subprob += p
total += i * p
return total / subprob
def normal_mining_return(pow, pos):
return pow * POWRETURN + ev(pos) * POSRETURN / ACTUALSIGS
def attack_mining_return(pow, pos, k):
powtotal, postotal, subprob = 0, 0, 0
# Case 1: mined PoW block, PoS at least k instances
case_1_prob = pow * at_least_k(pos, k)
subprob += case_1_prob
postotal += case_1_prob * ev_atleast_k(pos, k) * POSRETURN / ACTUALSIGS
powtotal += case_1_prob * POWRETURN
# Case 2: mined PoW block, PoS less than k: discard
# Case 3: others mined PoW block
subprob += (1 - pow)
postotal += (1 - pow) * ev(pos) * POSRETURN / ACTUALSIGS
return powtotal / subprob + postotal / subprob