/
SlasherUtil.sol
93 lines (83 loc) · 2.99 KB
/
SlasherUtil.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
pragma solidity ^0.5.3;
import "openzeppelin-solidity/contracts/math/SafeMath.sol";
import "openzeppelin-solidity/contracts/ownership/Ownable.sol";
import "../common/Initializable.sol";
import "../common/UsingRegistry.sol";
import "../common/UsingPrecompiles.sol";
contract SlasherUtil is Ownable, Initializable, UsingRegistry, UsingPrecompiles {
using SafeMath for uint256;
struct SlashingIncentives {
// Value of LockedGold to slash from the account.
uint256 penalty;
// Value of LockedGold to send to the observer.
uint256 reward;
}
SlashingIncentives public slashingIncentives;
event SlashingIncentivesSet(uint256 penalty, uint256 reward);
/**
* @notice Sets slashing incentives.
* @param penalty Penalty for the slashed signer.
* @param reward Reward that the observer gets.
*/
function setSlashingIncentives(uint256 penalty, uint256 reward) public onlyOwner {
require(penalty > reward, "Penalty has to be larger than reward");
slashingIncentives.penalty = penalty;
slashingIncentives.reward = reward;
emit SlashingIncentivesSet(penalty, reward);
}
/**
* @notice Returns the group to be slashed.
* @param validator Validator that was slashed.
* @param blockNumber Block number associated with slashing.
* @param groupMembershipHistoryIndex Index used for history lookup.
* @return Group to be slashed.
*/
function groupMembershipAtBlock(
address validator,
uint256 blockNumber,
uint256 groupMembershipHistoryIndex
) internal view returns (address) {
uint256 epoch = getEpochNumberOfBlock(blockNumber);
require(epoch != 0, "Cannot slash on epoch 0");
// Use `epoch-1` because the elections were on that epoch
return
getValidators().groupMembershipInEpoch(validator, epoch.sub(1), groupMembershipHistoryIndex);
}
function performSlashing(
address validator,
address recipient,
uint256 startBlock,
uint256 groupMembershipHistoryIndex,
address[] memory validatorElectionLessers,
address[] memory validatorElectionGreaters,
uint256[] memory validatorElectionIndices,
address[] memory groupElectionLessers,
address[] memory groupElectionGreaters,
uint256[] memory groupElectionIndices
) internal {
ILockedGold lockedGold = getLockedGold();
lockedGold.slash(
validator,
slashingIncentives.penalty,
recipient,
slashingIncentives.reward,
validatorElectionLessers,
validatorElectionGreaters,
validatorElectionIndices
);
address group = groupMembershipAtBlock(validator, startBlock, groupMembershipHistoryIndex);
if (group == address(0)) return; // Should never be true
lockedGold.slash(
group,
slashingIncentives.penalty,
recipient,
slashingIncentives.reward,
groupElectionLessers,
groupElectionGreaters,
groupElectionIndices
);
IValidators validators = getValidators();
validators.forceDeaffiliateIfValidator(validator);
validators.halveSlashingMultiplier(group);
}
}