@@ -6,29 +6,21 @@ import "./IRNG.sol";
66/// @title RNG with fallback mechanism
77/// @notice Uses multiple RNG implementations with automatic fallback if default RNG does not respond passed a timeout.
88contract RNGWithFallback is IRNG {
9- uint256 public constant DEFAULT_RNG = 0 ;
10-
119 // ************************************* //
1210 // * Storage * //
1311 // ************************************* //
1412
13+ IRNG public immutable rng; // RNG address.
1514 address public governor; // Governor address
1615 address public consumer; // Consumer address
17- IRNG[] public rngs; // List of RNG implementations
1816 uint256 public fallbackTimeoutSeconds; // Time in seconds to wait before falling back to next RNG
1917 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
2218
2319 // ************************************* //
2420 // * Events * //
2521 // ************************************* //
2622
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 ();
3224 event FallbackTimeoutChanged (uint256 _newTimeout );
3325
3426 // ************************************* //
@@ -38,14 +30,14 @@ contract RNGWithFallback is IRNG {
3830 /// @param _governor Governor address
3931 /// @param _consumer Consumer address
4032 /// @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 " );
4436
4537 governor = _governor;
4638 consumer = _consumer;
4739 fallbackTimeoutSeconds = _fallbackTimeoutSeconds;
48- rngs. push (_defaultRng) ;
40+ rng = _rng ;
4941 }
5042
5143 // ************************************* //
@@ -66,44 +58,25 @@ contract RNGWithFallback is IRNG {
6658 // * State Modifiers * //
6759 // ************************************* //
6860
69- /// @dev Request a random number from the default RNG
61+ /// @dev Request a random number from the RNG
7062 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 ;
7763 requestTimestamp = block .timestamp ;
78- currentRngIndex = _rngIndex;
79- rngs[_rngIndex].requestRandomness ();
64+ rng.requestRandomness ();
8065 }
8166
8267 /// @dev Receive the random number with fallback logic
8368 /// @return randomNumber Random Number
8469 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 ();
8772
8873 // If we got a valid number, clear the request
8974 if (randomNumber != 0 ) {
90- isRequesting = false ;
9175 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 ();
10780 }
10881 return randomNumber;
10982 }
@@ -124,61 +97,10 @@ contract RNGWithFallback is IRNG {
12497 consumer = _consumer;
12598 }
12699
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-
160100 /// @dev Change the fallback timeout
161101 /// @param _fallbackTimeoutSeconds New timeout in seconds
162102 function changeFallbackTimeout (uint256 _fallbackTimeoutSeconds ) external onlyByGovernor {
163103 fallbackTimeoutSeconds = _fallbackTimeoutSeconds;
164104 emit FallbackTimeoutChanged (_fallbackTimeoutSeconds);
165105 }
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- }
184106}
0 commit comments