-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCasper.py
More file actions
143 lines (114 loc) · 6.07 KB
/
Casper.py
File metadata and controls
143 lines (114 loc) · 6.07 KB
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
import math
class Casper:
def __init__(self, totalD, h, baseInterestFactor, basePenaltyFactor, baseDepositDependence, attackDuration,
exponentialTerm=0):
self.INITIAL_SCALE_FACTOR = 10000000000
self.validatorInitDeposits = [0, 0, ]
self.validatorPrevDeposits = [0, 0]
self.validatorDeposits = [0, 0]
# We consider two validators, one is attacked, other is not. -> 한명은 censorship 당해서 투표 안함 처리되고 한명은 투표한걸로 처리
#0 = attacker, 1 = victim
self.numValidators = 2
self.baseInterestFactor = baseInterestFactor
self.basePenaltyFactor = basePenaltyFactor
self.baseDepositDependence = baseDepositDependence
self.rewardFactor = self.baseInterestFactor / \
math.pow(totalD, baseDepositDependence)
self.depositScaleFactor = self.INITIAL_SCALE_FACTOR
self.prevDepositScaleFactor = self.depositScaleFactor
self.totalVoteUnscaled = 0
self.epoch = 0
# we assume that when we begin, the previous two epochs were justified
self.lastJustifiedEpoch = 0
self.lastFinalizedEpoch = -1
self.finalizationEpoch = 0
self.D = totalD
# h is the deposit fraction of the validator who is being 'censored'.
# During a censorship attack self validator represents the victims,
# during a minority fork those who are voting on the other chain
self.h = h
self.attackDuration = attackDuration
self.exponentialTerm = math.inf
if (exponentialTerm > 0):
self.exponentialTerm = exponentialTerm
self.initValidators(totalD, h)
def initValidators(self, D, h):
self.validatorDeposits[0] = D * (1 - h) / self.INITIAL_SCALE_FACTOR
self.validatorDeposits[1] = D * h / self.INITIAL_SCALE_FACTOR
for i in range(0, self.numValidators):
self.validatorPrevDeposits[i] = self.validatorDeposits[i]
self.validatorInitDeposits[i] = self.validatorDeposits[i]
def getTotalDepositsUnscaled(self, ):
result = 0
for i in range(0, self.numValidators):
result += self.validatorDeposits[i]
return result
def getESF(self, ):
return self.epoch - self.lastFinalizedEpoch
def getCollectiveReward(self, ):
# relevant for the first epoch, as we are assuming that we start in something close to steady-state
if (self.epoch == 1):
return self.rewardFactor / 2 # 왜 epoch = 1 이면 투표율 고려안하지??
votePercentage = self.totalVoteUnscaled / self.getTotalDepositsUnscaled()
if (self.getESF() > 2):
votePercentage = 0
return votePercentage * self.rewardFactor / 2
def getScaledDeposit(self, i):
# We consider the deposits _after_ the rescale. Since we process the whole epoch in a single call to processEpoch,
# self is equivalent to multiplying the base deposits at the start of the previous epoch with the current scale factor.
return self.validatorPrevDeposits[i] * self.depositScaleFactor
def getNextScaledDeposit(self, i):
return self.validatorDeposits[i] * self.depositScaleFactor
def getFinalizationEpoch(self, ):
if (self.getESF() == 1):
return self.finalizationEpoch
else:
return "not finalized"
def processEpoch(self, ):
self.epoch += 1
for i in range(0, self.numValidators):
self.validatorPrevDeposits[i] = self.validatorDeposits[i]
# update scale factor
self.prevDepositScaleFactor = self.depositScaleFactor
if (self.epoch > 1):
self.depositScaleFactor = self.depositScaleFactor * \
(1 + self.getCollectiveReward()) / (1 + self.rewardFactor)
# update reward factor
self.rewardFactor = self.baseInterestFactor / math.pow(self.getTotalDepositsUnscaled(
) * self.prevDepositScaleFactor, self.baseDepositDependence) + self.basePenaltyFactor * (self.getESF() - 2)
if (self.getESF() >= self.exponentialTerm):
self.rewardFactor += (math.exp(self.getESF() - self.exponentialTerm) - 1) * self.basePenaltyFactor
# update base deposits
self.totalVoteUnscaled = 0
for i in range(0, self.numValidators):
if ((i == 0) or (self.epoch > self.attackDuration)):
self.validatorDeposits[i] += self.validatorDeposits[i] * \
self.rewardFactor
self.totalVoteUnscaled += self.validatorDeposits[i]
# check for justification/finalization
if (
self.totalVoteUnscaled / self.getTotalDepositsUnscaled() > 2 / 3 and self.lastJustifiedEpoch < self.epoch):
if (self.lastJustifiedEpoch == self.epoch - 1):
if (self.epoch - self.lastFinalizedEpoch >= 3):
self.finalizationEpoch = self.epoch # just for tracing purposes
self.lastFinalizedEpoch = self.epoch - 1
self.lastJustifiedEpoch = self.epoch
def getDepositChange(self, idx):
return (self.getScaledDeposit(idx) / self.INITIAL_SCALE_FACTOR) / self.validatorInitDeposits[idx] - 1
# 아무데도 안쓰이는 함수
def processEpochs(self, n):
deps = []
z = self.numValidators - 1
for i in range(0, n):
self.processEpoch()
if (i % (math.ceil(n / 1000)) == 0):
depsDepn = math.pow(
self.numValidators * self.validatorInitDeposits[z] * self.INITIAL_SCALE_FACTOR,
self.baseDepositDependence)
interest = math.pow(
1 + self.f * self.baseInterestFactor / (2 * depsDepn), i)
naiveDep = self.validatorInitDeposits[z] * \
self.INITIAL_SCALE_FACTOR * interest
deps.append(i + ", " + self.getScaledDeposit(z) + " " +
naiveDep + " " + (self.getScaledDeposit(z) / naiveDep))
return deps