@@ -13,9 +13,10 @@ contract RNGWithFallback is IRNG {
13
13
// ************************************* //
14
14
15
15
address public governor; // Governor address
16
+ address public consumer; // Consumer address
16
17
IRNG[] public rngs; // List of RNG implementations
17
- uint256 public fallbackTimeout ; // Number of blocks to wait before falling back to next RNG
18
- uint256 public requestBlock ; // Block number of the current request
18
+ uint256 public fallbackTimeoutSeconds ; // Time in seconds to wait before falling back to next RNG
19
+ uint256 public requestTimestamp ; // Timestamp of the current request
19
20
uint256 public currentRngIndex; // Index of the current RNG
20
21
bool public isRequesting; // Whether a request is in progress
21
22
@@ -25,6 +26,7 @@ contract RNGWithFallback is IRNG {
25
26
26
27
event RNGDefaultChanged (address indexed _newDefaultRng );
27
28
event RNGFallback (uint256 _fromIndex , uint256 _toIndex );
29
+ event RNGFailure ();
28
30
event RNGFallbackAdded (address indexed _rng );
29
31
event RNGFallbackRemoved (address indexed _rng );
30
32
event FallbackTimeoutChanged (uint256 _newTimeout );
@@ -34,14 +36,15 @@ contract RNGWithFallback is IRNG {
34
36
// ************************************* //
35
37
36
38
/// @param _governor Governor address
37
- /// @param _fallbackTimeout Number of blocks to wait before falling back to next RNG
39
+ /// @param _consumer Consumer address
40
+ /// @param _fallbackTimeoutSeconds Time in seconds to wait before falling back to next RNG
38
41
/// @param _defaultRng The default RNG
39
- constructor (address _governor , uint256 _fallbackTimeout , IRNG _defaultRng ) {
42
+ constructor (address _governor , address _consumer , uint256 _fallbackTimeoutSeconds , IRNG _defaultRng ) {
40
43
require (address (_defaultRng) != address (0 ), "Invalid default RNG " );
41
- require (_fallbackTimeout > 0 , "Invalid fallback timeout " );
42
44
43
45
governor = _governor;
44
- fallbackTimeout = _fallbackTimeout;
46
+ consumer = _consumer;
47
+ fallbackTimeoutSeconds = _fallbackTimeoutSeconds;
45
48
rngs.push (_defaultRng);
46
49
}
47
50
@@ -54,26 +57,31 @@ contract RNGWithFallback is IRNG {
54
57
_;
55
58
}
56
59
60
+ modifier onlyByConsumer () {
61
+ require (msg .sender == consumer, "Consumer only " );
62
+ _;
63
+ }
64
+
57
65
// ************************************* //
58
66
// * State Modifiers * //
59
67
// ************************************* //
60
68
61
69
/// @dev Request a random number from the default RNG
62
- function requestRandomness () external override {
70
+ function requestRandomness () external override onlyByConsumer {
63
71
require (! isRequesting, "Request already in progress " );
64
- _requestRandomness ();
72
+ _requestRandomness (DEFAULT_RNG );
65
73
}
66
74
67
- function _requestRandomness () internal {
75
+ function _requestRandomness (uint256 _rngIndex ) internal {
68
76
isRequesting = true ;
69
- requestBlock = block .number ;
70
- currentRngIndex = DEFAULT_RNG ;
71
- rngs[DEFAULT_RNG ].requestRandomness ();
77
+ requestTimestamp = block .timestamp ;
78
+ currentRngIndex = _rngIndex ;
79
+ rngs[_rngIndex ].requestRandomness ();
72
80
}
73
81
74
82
/// @dev Receive the random number with fallback logic
75
83
/// @return randomNumber Random Number
76
- function receiveRandomness () external override returns (uint256 randomNumber ) {
84
+ function receiveRandomness () external override onlyByConsumer returns (uint256 randomNumber ) {
77
85
// Try to get random number from current RNG
78
86
randomNumber = rngs[currentRngIndex].receiveRandomness ();
79
87
@@ -84,14 +92,17 @@ contract RNGWithFallback is IRNG {
84
92
}
85
93
86
94
// If the timeout is exceeded, try next RNG
87
- if (block .number > requestBlock + fallbackTimeout ) {
95
+ if (block .timestamp > requestTimestamp + fallbackTimeoutSeconds ) {
88
96
uint256 nextIndex = currentRngIndex + 1 ;
89
97
90
98
// If we have another RNG to try, switch to it and request again
91
99
if (nextIndex < rngs.length ) {
92
100
emit RNGFallback (currentRngIndex, nextIndex);
93
101
currentRngIndex = nextIndex;
94
- rngs[nextIndex].requestRandomness ();
102
+ _requestRandomness (nextIndex);
103
+ } else {
104
+ // No more RNGs to try
105
+ emit RNGFailure ();
95
106
}
96
107
}
97
108
return randomNumber;
@@ -104,10 +115,15 @@ contract RNGWithFallback is IRNG {
104
115
/// @dev Change the governor
105
116
/// @param _newGovernor Address of the new governor
106
117
function changeGovernor (address _newGovernor ) external onlyByGovernor {
107
- require (_newGovernor != address (0 ), "Invalid governor " );
108
118
governor = _newGovernor;
109
119
}
110
120
121
+ /// @dev Change the consumer
122
+ /// @param _consumer Address of the new consumer
123
+ function changeConsumer (address _consumer ) external onlyByGovernor {
124
+ consumer = _consumer;
125
+ }
126
+
111
127
/// @dev Change the default RNG
112
128
/// @param _newDefaultRng Address of the new default RNG
113
129
function changeDefaultRng (IRNG _newDefaultRng ) external onlyByGovernor {
@@ -116,7 +132,7 @@ contract RNGWithFallback is IRNG {
116
132
emit RNGDefaultChanged (address (_newDefaultRng));
117
133
118
134
// Take over any pending request
119
- _requestRandomness ();
135
+ _requestRandomness (DEFAULT_RNG );
120
136
}
121
137
122
138
/// @dev Add a new RNG fallback
@@ -142,17 +158,18 @@ contract RNGWithFallback is IRNG {
142
158
}
143
159
144
160
/// @dev Change the fallback timeout
145
- /// @param _newTimeout New timeout in blocks
146
- function changeFallbackTimeout (uint256 _newTimeout ) external onlyByGovernor {
147
- require (_newTimeout > 0 , "Invalid timeout " );
148
- fallbackTimeout = _newTimeout;
149
- emit FallbackTimeoutChanged (_newTimeout);
161
+ /// @param _fallbackTimeoutSeconds New timeout in seconds
162
+ function changeFallbackTimeout (uint256 _fallbackTimeoutSeconds ) external onlyByGovernor {
163
+ fallbackTimeoutSeconds = _fallbackTimeoutSeconds;
164
+ emit FallbackTimeoutChanged (_fallbackTimeoutSeconds);
150
165
}
151
166
152
- /// @dev Drop the pending request .
167
+ /// @dev Emergency reset the RNG .
153
168
/// Useful for the governor to ensure that re-requesting a random number will not be blocked by a previous request.
154
- function dropPendingRequest () external onlyByGovernor {
169
+ function emergencyReset () external onlyByGovernor {
155
170
isRequesting = false ;
171
+ requestTimestamp = 0 ;
172
+ currentRngIndex = DEFAULT_RNG;
156
173
}
157
174
158
175
// ************************************* //
0 commit comments