/
RandomBeacon.sol
394 lines (343 loc) · 18.2 KB
/
RandomBeacon.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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
// SPDX-License-Identifier: MIT
/*
▓▓▌ ▓▓ ▐▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▄
▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓ ▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓ ▐▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓
▓▓▓▓▓▓▄▄▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▄▄▄▄ ▓▓▓▓▓▓▄▄▄▄ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▌ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▀▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓▀▀▀▀ ▓▓▓▓▓▓▀▀▀▀ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▀
▓▓▓▓▓▓ ▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌
▓▓▓▓▓▓▓▓▓▓ █▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓
Trust math, not hardware.
*/
pragma solidity ^0.8.6;
import "./libraries/DKG.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
/// @title Keep Random Beacon
/// @notice Keep Random Beacon contract. It lets anyone request a new
/// relay entry and validates the new relay entry provided by the
/// network. This contract is in charge of all Random Beacon maintenance
/// activities such as group lifecycle or slashing.
/// @dev Should be owned by the governance contract controlling Random Beacon
/// parameters.
contract RandomBeacon is Ownable {
using DKG for DKG.Data;
// Constant parameters
/// @notice Seed value used for the genesis group selection.
/// https://www.wolframalpha.com/input/?i=pi+to+78+digits
uint256 public constant GENESIS_SEED =
31415926535897932384626433832795028841971693993751058209749445923078164062862;
/// @notice Size of a group in the threshold relay.
uint256 public immutable GROUP_SIZE;
/// @notice The minimum number of signatures required to support DKG result.
uint256 public immutable SIGNATURE_THRESHOLD;
/// @notice Time in blocks after which DKG result is complete and ready to be
// published by clients.
uint256 public immutable TIME_DKG;
// Governable parameters
/// @notice Relay request fee in T. This fee needs to be provided by the
/// account or contract requesting for a new relay entry.
uint256 public relayRequestFee;
/// @notice The number of blocks it takes for a group member to become
/// eligible to submit the relay entry. At first, there is only one
/// member in the group eligible to submit the relay entry. Then,
/// after `relayEntrySubmissionEligibilityDelay` blocks, another
/// group member becomes eligible so that there are two group
/// members eligible to submit the relay entry at that moment. After
/// another `relayEntrySubmissionEligibilityDelay` blocks, yet one
/// group member becomes eligible so that there are three group
/// members eligible to submit the relay entry at that moment. This
/// continues until all group members are eligible to submit the
/// relay entry or until the relay entry is submitted. If all
/// members became eligible to submit the relay entry and one more
/// `relayEntrySubmissionEligibilityDelay` passed without the relay
/// entry submitted, the group reaches soft timeout for submitting
/// the relay entry and the slashing starts.
uint256 public relayEntrySubmissionEligibilityDelay;
/// @notice Hard timeout in blocks for a group to submit the relay entry.
/// After all group members became eligible to submit the relay
/// entry and one more `relayEntrySubmissionEligibilityDelay` blocks
/// passed without relay entry submitted, all group members start
/// getting slashed. The slashing amount increases linearly until
/// the group submits the relay entry or until
/// `relayEntryHardTimeout` is reached. When the hard timeout is
/// reached, each group member will get slashed for
/// `relayEntrySubmissionFailureSlashingAmount`.
uint256 public relayEntryHardTimeout;
/// @notice Relay entry callback gas limit. This is the gas limit with which
/// callback function provided in the relay request transaction is
/// executed. The callback is executed with a new relay entry value
/// in the same transaction the relay entry is submitted.
uint256 public callbackGasLimit;
/// @notice The frequency of new group creation. Groups are created with
/// a fixed frequency of relay requests.
uint256 public groupCreationFrequency;
/// @notice Group lifetime in seconds. When a group reached its lifetime, it
/// is no longer selected for new relay requests but may still be
/// responsible for submitting relay entry if relay request assigned
/// to that group is still pending.
uint256 public groupLifetime;
/// @notice The number of blocks for which a DKG result can be challenged.
/// Anyone can challenge DKG result for a certain number of blocks
/// before the result is fully accepted and the group registered in
/// the pool of active groups. If the challenge gets accepted, all
/// operators who signed the malicious result get slashed for
/// `maliciousDkgResultSlashingAmount` and the notifier gets
/// rewarded.
uint256 public dkgResultChallengePeriodLength;
/// @notice The number of blocks it takes for a group member to become
/// eligible to submit the DKG result. At first, there is only one
/// member in the group eligible to submit the DKG result. Then,
/// after `dkgResultSubmissionEligibilityDelay` blocks, another
/// group member becomes eligible so that there are two group
/// members eligible to submit the DKG result at that moment. After
/// another `dkgResultSubmissionEligibilityDelay` blocks, yet one
/// group member becomes eligible to submit the DKG result so that
/// there are three group members eligible to submit the DKG result
/// at that moment. This continues until all group members are
/// eligible to submit the DKG result or until the DKG result is
/// submitted. If all members became eligible to submit the DKG
/// result and one more `dkgResultSubmissionEligibilityDelay` passed
/// without the DKG result submitted, DKG is considered as timed out
/// and no DKG result for this group creation can be submitted
/// anymore.
uint256 public dkgResultSubmissionEligibilityDelay;
/// @notice Reward in T for submitting DKG result. The reward is paid to
/// a submitter of a valid DKG result when the DKG result challenge
/// period ends.
uint256 public dkgResultSubmissionReward;
/// @notice Reward in T for unlocking the sortition pool if DKG timed out.
/// When DKG result submission timed out, sortition pool is still
/// locked and someone needs to unlock it. Anyone can do it and earn
/// `sortitionPoolUnlockingReward`.
uint256 public sortitionPoolUnlockingReward;
/// @notice Slashing amount for not submitting relay entry. When
/// relay entry hard timeout is reached without the relay entry
/// submitted, each group member gets slashed for
/// `relayEntrySubmissionFailureSlashingAmount`. If the relay entry
/// gets submitted after the soft timeout (see
/// `relayEntrySubmissionEligibilityDelay` documentation), but
/// before the hard timeout, each group member gets slashed
/// proportionally to `relayEntrySubmissionFailureSlashingAmount`
/// and the time passed since the soft deadline.
uint256 public relayEntrySubmissionFailureSlashingAmount;
/// @notice Slashing amount for supporting malicious DKG result. Every
/// DKG result submitted can be challenged for the time of
/// `dkgResultChallengePeriodLength`. If the DKG result submitted
/// is challenged and proven to be malicious, each operator who
/// signed the malicious result is slashed for
/// `maliciousDkgResultSlashingAmount`.
uint256 public maliciousDkgResultSlashingAmount;
// Libraries data storages
// TODO: Can we really make it public along with the library functions?
DKG.Data public dkg;
event RelayEntryParametersUpdated(
uint256 relayRequestFee,
uint256 relayEntrySubmissionEligibilityDelay,
uint256 relayEntryHardTimeout,
uint256 callbackGasLimit
);
event GroupCreationParametersUpdated(
uint256 groupCreationFrequency,
uint256 groupLifetime,
uint256 dkgResultChallengePeriodLength,
uint256 dkgResultSubmissionEligibilityDelay
);
event RewardParametersUpdated(
uint256 dkgResultSubmissionReward,
uint256 sortitionPoolUnlockingReward
);
event SlashingParametersUpdated(
uint256 relayEntrySubmissionFailureSlashingAmount,
uint256 maliciousDkgResultSlashingAmount
);
event DkgStarted(
uint256 seed,
uint256 groupSize,
uint256 dkgResultSubmissionEligibilityDelay
); // TODO: Add all other needed paramters
event DkgTimedOut(uint256 indexed seed);
// FIXME: This is just for tests
uint256 internal currentRelayEntry = 420;
/// @dev Assigns initial values to parameters to make the beacon work
/// safely. These parameters are just proposed defaults and they might
/// be updated with `update*` functions after the contract deployment
/// and before transferring the ownership to the governance contract.
constructor(
uint256 groupSize,
uint256 signatureThreshold,
uint256 timeDkg
) {
relayRequestFee = 0;
relayEntrySubmissionEligibilityDelay = 10;
relayEntryHardTimeout = 5760; // ~24h assuming 15s block time
callbackGasLimit = 200000;
groupCreationFrequency = 10;
groupLifetime = 2 weeks;
dkgResultChallengePeriodLength = 1440; // ~6h assuming 15s block time
dkgResultSubmissionEligibilityDelay = 10;
dkgResultSubmissionReward = 0;
sortitionPoolUnlockingReward = 0;
relayEntrySubmissionFailureSlashingAmount = 1000e18;
maliciousDkgResultSlashingAmount = 50000e18;
GROUP_SIZE = groupSize;
SIGNATURE_THRESHOLD = signatureThreshold;
TIME_DKG = timeDkg;
}
/// @notice Updates the values of relay entry parameters.
/// @dev Can be called only by the contract owner, which should be the
/// random beacon governance contract. The caller is responsible for
/// validating parameters.
/// @param _relayRequestFee New relay request fee
/// @param _relayEntrySubmissionEligibilityDelay New relay entry submission
/// eligibility delay
/// @param _relayEntryHardTimeout New relay entry hard timeout
/// @param _callbackGasLimit New callback gas limit
function updateRelayEntryParameters(
uint256 _relayRequestFee,
uint256 _relayEntrySubmissionEligibilityDelay,
uint256 _relayEntryHardTimeout,
uint256 _callbackGasLimit
) external onlyOwner {
relayRequestFee = _relayRequestFee;
relayEntrySubmissionEligibilityDelay = _relayEntrySubmissionEligibilityDelay;
relayEntryHardTimeout = _relayEntryHardTimeout;
callbackGasLimit = _callbackGasLimit;
emit RelayEntryParametersUpdated(
relayRequestFee,
relayEntrySubmissionEligibilityDelay,
relayEntryHardTimeout,
callbackGasLimit
);
}
/// @notice Updates the values of group creation parameters.
/// @dev Can be called only by the contract owner, which should be the
/// random beacon governance contract. The caller is responsible for
/// validating parameters.
/// @param _groupCreationFrequency New group creation frequency
/// @param _groupLifetime New group lifetime
/// @param _dkgResultChallengePeriodLength New DKG result challenge period
/// length
/// @param _dkgResultSubmissionEligibilityDelay New DKG result submission
/// eligibility delay
function updateGroupCreationParameters(
uint256 _groupCreationFrequency,
uint256 _groupLifetime,
uint256 _dkgResultChallengePeriodLength,
uint256 _dkgResultSubmissionEligibilityDelay
) external onlyOwner {
groupCreationFrequency = _groupCreationFrequency;
groupLifetime = _groupLifetime;
dkgResultChallengePeriodLength = _dkgResultChallengePeriodLength;
dkgResultSubmissionEligibilityDelay = _dkgResultSubmissionEligibilityDelay;
emit GroupCreationParametersUpdated(
groupCreationFrequency,
groupLifetime,
dkgResultChallengePeriodLength,
dkgResultSubmissionEligibilityDelay
);
}
/// @notice Updates the values of reward parameters.
/// @dev Can be called only by the contract owner, which should be the
/// random beacon governance contract. The caller is responsible for
/// validating parameters.
/// @param _dkgResultSubmissionReward New DKG result submission reward
/// @param _sortitionPoolUnlockingReward New sortition pool unlocking reward
function updateRewardParameters(
uint256 _dkgResultSubmissionReward,
uint256 _sortitionPoolUnlockingReward
) external onlyOwner {
dkgResultSubmissionReward = _dkgResultSubmissionReward;
sortitionPoolUnlockingReward = _sortitionPoolUnlockingReward;
emit RewardParametersUpdated(
dkgResultSubmissionReward,
sortitionPoolUnlockingReward
);
}
/// @notice Updates the values of slashing parameters.
/// @dev Can be called only by the contract owner, which should be the
/// random beacon governance contract. The caller is responsible for
/// validating parameters.
/// @param _relayEntrySubmissionFailureSlashingAmount New relay entry
/// submission failure amount
/// @param _maliciousDkgResultSlashingAmount New malicious DKG result
/// slashing amount
function updateSlashingParameters(
uint256 _relayEntrySubmissionFailureSlashingAmount,
uint256 _maliciousDkgResultSlashingAmount
) external onlyOwner {
relayEntrySubmissionFailureSlashingAmount = _relayEntrySubmissionFailureSlashingAmount;
maliciousDkgResultSlashingAmount = _maliciousDkgResultSlashingAmount;
emit SlashingParametersUpdated(
relayEntrySubmissionFailureSlashingAmount,
maliciousDkgResultSlashingAmount
);
}
function createGroup(uint256 seed) internal {
// Sortition performed off-chain
dkg.start(
seed,
GROUP_SIZE,
SIGNATURE_THRESHOLD,
dkgResultSubmissionEligibilityDelay,
TIME_DKG
);
emit DkgStarted(seed, GROUP_SIZE, dkgResultSubmissionEligibilityDelay);
}
function genesis() external {
// require(groups.groupCount == 0, "not awaiting genesis");
createGroup(GENESIS_SEED);
}
function completeGroupCreation() internal {
dkg.finish();
// New groups should be created with a fixed frequency of relay requests
// TODO: Consider each group a separate contract instance deployed with proxy?
}
function notifyDkgTimeout() external {
dkg.notifyTimeout();
emit DkgTimedOut(dkg.seed);
}
function isDkgInProgress() external view returns (bool) {
return dkg.isInProgress();
}
/// @notice Submits result of DKG protocol. It is on-chain part of phase 14 of
/// the protocol.
/// @param submitterMemberIndex Claimed submitter candidate group member index
/// @param groupPubKey Generated candidate group public key
/// @param misbehaved Bytes array of misbehaved (disqualified or inactive)
/// group members indexes in ascending order; Indexes reflect positions of
/// members in the group as outputted by the group selection protocol.
/// @param signatures Concatenation of signatures from members supporting the
/// result.
/// @param signingMembersIndexes Indices of members corresponding to each
/// signature.
/// @param members List of selected group members.
function submitDkgResult(
uint256 submitterMemberIndex,
bytes memory groupPubKey,
bytes memory misbehaved,
bytes memory signatures,
uint256[] memory signingMembersIndexes,
address[] memory members
) external {
// TODO: Consider adding nonReentrant?
// validate DKG result
dkg.verify(
submitterMemberIndex,
groupPubKey,
misbehaved,
signatures,
signingMembersIndexes,
members
);
// emit DkgResultSubmitted
// if enough results
completeGroupCreation();
}
// function requestRelayEntry() external {
// if RELAY_ENTRY_COUNT >= groupCreationFrequency {
// createGroup();
// }
// }
}