-
Notifications
You must be signed in to change notification settings - Fork 10
/
Maintenance.sol
201 lines (181 loc) · 6.35 KB
/
Maintenance.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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import "../interfaces/IMaintenance.sol";
import "../interfaces/IRoninValidatorSet.sol";
import "../interfaces/IStaking.sol";
import "../extensions/collections/HasValidatorContract.sol";
import "../libraries/Math.sol";
contract Maintenance is IMaintenance, HasValidatorContract, Initializable {
using Math for uint256;
/// @dev Mapping from consensus address => maintenance schedule
mapping(address => Schedule) internal _schedule;
/// @dev The min block period to maintenance
uint256 public minMaintenanceBlockPeriod;
/// @dev The max block period to maintenance
uint256 public maxMaintenanceBlockPeriod;
/// @dev The min blocks from the current block to the start block
uint256 public minOffset;
/// @dev The max number of scheduled maintenances
uint256 public maxSchedules;
constructor() {
_disableInitializers();
}
/**
* @dev Initializes the contract storage.
*/
function initialize(
address __validatorContract,
uint256 _minMaintenanceBlockPeriod,
uint256 _maxMaintenanceBlockPeriod,
uint256 _minOffset,
uint256 _maxSchedules
) external initializer {
_setValidatorContract(__validatorContract);
_setMaintenanceConfig(_minMaintenanceBlockPeriod, _maxMaintenanceBlockPeriod, _minOffset, _maxSchedules);
}
/**
* @inheritdoc IMaintenance
*/
function setMaintenanceConfig(
uint256 _minMaintenanceBlockPeriod,
uint256 _maxMaintenanceBlockPeriod,
uint256 _minOffset,
uint256 _maxSchedules
) external onlyAdmin {
_setMaintenanceConfig(_minMaintenanceBlockPeriod, _maxMaintenanceBlockPeriod, _minOffset, _maxSchedules);
}
/**
* @inheritdoc IMaintenance
*/
function schedule(
address _consensusAddr,
uint256 _startedAtBlock,
uint256 _endedAtBlock
) external override {
IRoninValidatorSet _validator = _validatorContract;
require(_validator.isBlockProducer(_consensusAddr), "Maintenance: consensus address must be a block producer");
require(
_validator.isCandidateAdmin(_consensusAddr, msg.sender),
"Maintenance: method caller must be a candidate admin"
);
require(!scheduled(_consensusAddr), "Maintenance: already scheduled");
require(totalSchedules() < maxSchedules, "Maintenance: exceeds total of schedules");
require(block.number + minOffset <= _startedAtBlock, "Maintenance: invalid offset size");
require(_startedAtBlock < _endedAtBlock, "Maintenance: start block must be less than end block");
uint256 _blockPeriod = _endedAtBlock - _startedAtBlock;
require(
_blockPeriod.inRange(minMaintenanceBlockPeriod, maxMaintenanceBlockPeriod),
"Maintenance: invalid maintenance block period"
);
require(_validator.epochEndingAt(_startedAtBlock - 1), "Maintenance: start block is not at the start of an epoch");
require(_validator.epochEndingAt(_endedAtBlock), "Maintenance: end block is not at the end of an epoch");
Schedule storage _sSchedule = _schedule[_consensusAddr];
_sSchedule.from = _startedAtBlock;
_sSchedule.to = _endedAtBlock;
_sSchedule.lastUpdatedBlock = block.number;
emit MaintenanceScheduled(_consensusAddr, _sSchedule);
}
/**
* @inheritdoc IMaintenance
*/
function getSchedule(address _consensusAddr) external view returns (Schedule memory) {
return _schedule[_consensusAddr];
}
/**
* @inheritdoc IMaintenance
*/
function bulkMaintaining(address[] calldata _addrList, uint256 _block)
external
view
override
returns (bool[] memory _resList)
{
_resList = new bool[](_addrList.length);
for (uint _i = 0; _i < _addrList.length; _i++) {
_resList[_i] = maintaining(_addrList[_i], _block);
}
}
/**
* @inheritdoc IMaintenance
*/
function bulkMaintainingInBlockRange(
address[] calldata _addrList,
uint256 _fromBlock,
uint256 _toBlock
) external view override returns (bool[] memory _resList) {
_resList = new bool[](_addrList.length);
for (uint _i = 0; _i < _addrList.length; _i++) {
_resList[_i] = _maintainingInBlockRange(_addrList[_i], _fromBlock, _toBlock);
}
}
/**
* @inheritdoc IMaintenance
*/
function totalSchedules() public view override returns (uint256 _count) {
address[] memory _validators = _validatorContract.getValidators();
for (uint _i = 0; _i < _validators.length; _i++) {
if (scheduled(_validators[_i])) {
_count++;
}
}
}
/**
* @inheritdoc IMaintenance
*/
function maintaining(address _consensusAddr, uint256 _block) public view returns (bool) {
Schedule storage _s = _schedule[_consensusAddr];
return _s.from <= _block && _block <= _s.to;
}
/**
* @inheritdoc IMaintenance
*/
function maintainingInBlockRange(
address _consensusAddr,
uint256 _fromBlock,
uint256 _toBlock
) public view override returns (bool) {
return _maintainingInBlockRange(_consensusAddr, _fromBlock, _toBlock);
}
/**
* @inheritdoc IMaintenance
*/
function scheduled(address _consensusAddr) public view override returns (bool) {
return block.number <= _schedule[_consensusAddr].to;
}
/**
* @dev Sets the min block period and max block period to maintenance.
*
* Requirements:
* - The max period is larger than the min period.
*
* Emits the event `MaintenanceConfigUpdated`.
*
*/
function _setMaintenanceConfig(
uint256 _minMaintenanceBlockPeriod,
uint256 _maxMaintenanceBlockPeriod,
uint256 _minOffset,
uint256 _maxSchedules
) internal {
require(_minMaintenanceBlockPeriod < _maxMaintenanceBlockPeriod, "Maintenance: invalid block periods");
minMaintenanceBlockPeriod = _minMaintenanceBlockPeriod;
maxMaintenanceBlockPeriod = _maxMaintenanceBlockPeriod;
minOffset = _minOffset;
maxSchedules = _maxSchedules;
emit MaintenanceConfigUpdated(_minMaintenanceBlockPeriod, _maxMaintenanceBlockPeriod, _minOffset, _maxSchedules);
}
/**
* @dev Check if the validator was maintaining in the current period.
*
* Note: This method should be called at the end of the period.
*/
function _maintainingInBlockRange(
address _consensusAddr,
uint256 _fromBlock,
uint256 _toBlock
) private view returns (bool) {
Schedule storage _s = _schedule[_consensusAddr];
return Math.twoRangeOverlap(_fromBlock, _toBlock, _s.from, _s.to);
}
}