-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPunish.sol
138 lines (115 loc) · 3.98 KB
/
Punish.sol
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
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import "./Params.sol";
import "./Validators.sol";
contract Punish is Params {
uint256 public punishThreshold;
uint256 public removeThreshold;
uint256 public decreaseRate;
struct PunishRecord {
uint256 missedBlocksCounter;
uint256 index;
bool exist;
}
Validators validators;
mapping(address => PunishRecord) punishRecords;
address[] public punishValidators;
mapping(uint256 => bool) punished;
mapping(uint256 => bool) decreased;
event LogDecreaseMissedBlocksCounter();
event LogPunishValidator(address indexed val, uint256 time);
modifier onlyNotPunished() {
require(!punished[block.number], "Already punished");
_;
}
modifier onlyNotDecreased() {
require(!decreased[block.number], "Already decreased");
_;
}
function initialize() external onlyNotInitialized {
validators = Validators(ValidatorContractAddr);
punishThreshold = 48;
removeThreshold = 96;
decreaseRate = 48;
initialized = true;
}
function punish(address val)
external
onlyMiner
onlyInitialized
onlyNotPunished
{
punished[block.number] = true;
if (!punishRecords[val].exist) {
punishRecords[val].index = punishValidators.length;
punishValidators.push(val);
punishRecords[val].exist = true;
}
punishRecords[val].missedBlocksCounter++;
if (punishRecords[val].missedBlocksCounter % removeThreshold == 0) {
validators.removeValidator(val);
// reset validator's missed blocks counter
punishRecords[val].missedBlocksCounter = 0;
} else if (
punishRecords[val].missedBlocksCounter % punishThreshold == 0
) {
validators.removeValidatorIncoming(val);
}
emit LogPunishValidator(val, block.timestamp);
}
function decreaseMissedBlocksCounter(uint256 epoch)
external
onlyMiner
onlyNotDecreased
onlyInitialized
onlyBlockEpoch(epoch)
{
decreased[block.number] = true;
if (punishValidators.length == 0) {
return;
}
for (uint256 i = 0; i < punishValidators.length; i++) {
if (
punishRecords[punishValidators[i]].missedBlocksCounter >
removeThreshold / decreaseRate
) {
punishRecords[punishValidators[i]].missedBlocksCounter =
punishRecords[punishValidators[i]].missedBlocksCounter -
removeThreshold /
decreaseRate;
} else {
punishRecords[punishValidators[i]].missedBlocksCounter = 0;
}
}
emit LogDecreaseMissedBlocksCounter();
}
// clean validator's punish record if one restake in
function cleanPunishRecord(address val)
public
onlyInitialized
onlyValidatorsContract
returns (bool)
{
if (punishRecords[val].missedBlocksCounter != 0) {
punishRecords[val].missedBlocksCounter = 0;
}
// remove it out of array if exist
if (punishRecords[val].exist && punishValidators.length > 0) {
if (punishRecords[val].index != punishValidators.length - 1) {
address uval = punishValidators[punishValidators.length - 1];
punishValidators[punishRecords[val].index] = uval;
punishRecords[uval].index = punishRecords[val].index;
}
punishValidators.pop();
punishRecords[val].index = 0;
punishRecords[val].exist = false;
}
return true;
}
function getPunishValidatorsLen() public view returns (uint256) {
return punishValidators.length;
}
function getPunishRecord(address val) public view returns (uint256) {
return punishRecords[val].missedBlocksCounter;
}
}