@@ -6,29 +6,21 @@ import "./IRNG.sol";
6
6
/// @title RNG with fallback mechanism
7
7
/// @notice Uses multiple RNG implementations with automatic fallback if default RNG does not respond passed a timeout.
8
8
contract RNGWithFallback is IRNG {
9
- uint256 public constant DEFAULT_RNG = 0 ;
10
-
11
9
// ************************************* //
12
10
// * Storage * //
13
11
// ************************************* //
14
12
13
+ IRNG public immutable rng; // RNG address.
15
14
address public governor; // Governor address
16
15
address public consumer; // Consumer address
17
- IRNG[] public rngs; // List of RNG implementations
18
16
uint256 public fallbackTimeoutSeconds; // Time in seconds to wait before falling back to next RNG
19
17
uint256 public requestTimestamp; // Timestamp of the current request
20
- uint256 public currentRngIndex; // Index of the current RNG
21
- bool public isRequesting; // Whether a request is in progress
22
18
23
19
// ************************************* //
24
20
// * Events * //
25
21
// ************************************* //
26
22
27
- event RNGDefaultChanged (address indexed _newDefaultRng );
28
- event RNGFallback (uint256 _fromIndex , uint256 _toIndex );
29
- event RNGFailure ();
30
- event RNGFallbackAdded (address indexed _rng );
31
- event RNGFallbackRemoved (address indexed _rng );
23
+ event RNGFallback ();
32
24
event FallbackTimeoutChanged (uint256 _newTimeout );
33
25
34
26
// ************************************* //
@@ -38,14 +30,14 @@ contract RNGWithFallback is IRNG {
38
30
/// @param _governor Governor address
39
31
/// @param _consumer Consumer address
40
32
/// @param _fallbackTimeoutSeconds Time in seconds to wait before falling back to next RNG
41
- /// @param _defaultRng The default RNG
42
- constructor (address _governor , address _consumer , uint256 _fallbackTimeoutSeconds , IRNG _defaultRng ) {
43
- require (address (_defaultRng ) != address (0 ), "Invalid default RNG " );
33
+ /// @param _rng The RNG address (e.g. Chainlink)
34
+ constructor (address _governor , address _consumer , uint256 _fallbackTimeoutSeconds , IRNG _rng ) {
35
+ require (address (_rng ) != address (0 ), "Invalid default RNG " );
44
36
45
37
governor = _governor;
46
38
consumer = _consumer;
47
39
fallbackTimeoutSeconds = _fallbackTimeoutSeconds;
48
- rngs. push (_defaultRng) ;
40
+ rng = _rng ;
49
41
}
50
42
51
43
// ************************************* //
@@ -66,44 +58,25 @@ contract RNGWithFallback is IRNG {
66
58
// * State Modifiers * //
67
59
// ************************************* //
68
60
69
- /// @dev Request a random number from the default RNG
61
+ /// @dev Request a random number from the RNG
70
62
function requestRandomness () external override onlyByConsumer {
71
- require (! isRequesting, "Request already in progress " );
72
- _requestRandomness (DEFAULT_RNG);
73
- }
74
-
75
- function _requestRandomness (uint256 _rngIndex ) internal {
76
- isRequesting = true ;
77
63
requestTimestamp = block .timestamp ;
78
- currentRngIndex = _rngIndex;
79
- rngs[_rngIndex].requestRandomness ();
64
+ rng.requestRandomness ();
80
65
}
81
66
82
67
/// @dev Receive the random number with fallback logic
83
68
/// @return randomNumber Random Number
84
69
function receiveRandomness () external override onlyByConsumer returns (uint256 randomNumber ) {
85
- // Try to get random number from current RNG
86
- randomNumber = rngs[currentRngIndex] .receiveRandomness ();
70
+ // Try to get random number from the RNG contract
71
+ randomNumber = rng .receiveRandomness ();
87
72
88
73
// If we got a valid number, clear the request
89
74
if (randomNumber != 0 ) {
90
- isRequesting = false ;
91
75
return randomNumber;
92
- }
93
-
94
- // If the timeout is exceeded, try next RNG
95
- if (block .timestamp > requestTimestamp + fallbackTimeoutSeconds) {
96
- uint256 nextIndex = currentRngIndex + 1 ;
97
-
98
- // If we have another RNG to try, switch to it and request again
99
- if (nextIndex < rngs.length ) {
100
- emit RNGFallback (currentRngIndex, nextIndex);
101
- currentRngIndex = nextIndex;
102
- _requestRandomness (nextIndex);
103
- } else {
104
- // No more RNGs to try
105
- emit RNGFailure ();
106
- }
76
+ } else if (block .timestamp > requestTimestamp + fallbackTimeoutSeconds) {
77
+ // If the timeout is exceeded, try the fallback
78
+ randomNumber = uint256 (blockhash (block .number - 1 ));
79
+ emit RNGFallback ();
107
80
}
108
81
return randomNumber;
109
82
}
@@ -124,61 +97,10 @@ contract RNGWithFallback is IRNG {
124
97
consumer = _consumer;
125
98
}
126
99
127
- /// @dev Change the default RNG
128
- /// @param _newDefaultRng Address of the new default RNG
129
- function changeDefaultRng (IRNG _newDefaultRng ) external onlyByGovernor {
130
- require (address (_newDefaultRng) != address (0 ), "Invalid RNG " );
131
- rngs[DEFAULT_RNG] = _newDefaultRng;
132
- emit RNGDefaultChanged (address (_newDefaultRng));
133
-
134
- // Take over any pending request
135
- _requestRandomness (DEFAULT_RNG);
136
- }
137
-
138
- /// @dev Add a new RNG fallback
139
- /// @param _newFallbackRng Address of the new RNG fallback
140
- function addRngFallback (IRNG _newFallbackRng ) external onlyByGovernor {
141
- require (address (_newFallbackRng) != address (0 ), "Invalid RNG " );
142
- rngs.push (_newFallbackRng);
143
- emit RNGFallbackAdded (address (_newFallbackRng));
144
- }
145
-
146
- /// @dev Remove an RNG fallback
147
- function removeLastRngFallback () external onlyByGovernor {
148
- require (rngs.length > 1 , "No fallback RNG " );
149
-
150
- // If the removed RNG is the current one, reset the fallback index
151
- if (currentRngIndex > rngs.length - 2 ) {
152
- currentRngIndex = DEFAULT_RNG;
153
- }
154
-
155
- IRNG removedRng = rngs[rngs.length - 1 ];
156
- rngs.pop ();
157
- emit RNGFallbackRemoved (address (removedRng));
158
- }
159
-
160
100
/// @dev Change the fallback timeout
161
101
/// @param _fallbackTimeoutSeconds New timeout in seconds
162
102
function changeFallbackTimeout (uint256 _fallbackTimeoutSeconds ) external onlyByGovernor {
163
103
fallbackTimeoutSeconds = _fallbackTimeoutSeconds;
164
104
emit FallbackTimeoutChanged (_fallbackTimeoutSeconds);
165
105
}
166
-
167
- /// @dev Emergency reset the RNG.
168
- /// Useful for the governor to ensure that re-requesting a random number will not be blocked by a previous request.
169
- function emergencyReset () external onlyByGovernor {
170
- isRequesting = false ;
171
- requestTimestamp = 0 ;
172
- currentRngIndex = DEFAULT_RNG;
173
- }
174
-
175
- // ************************************* //
176
- // * View Functions * //
177
- // ************************************* //
178
-
179
- /// @dev Get the number of RNGs
180
- /// @return Number of RNGs
181
- function getRNGsCount () external view returns (uint256 ) {
182
- return rngs.length ;
183
- }
184
106
}
0 commit comments