Skip to content

Commit 937fb97

Browse files
unknownunknown1jaybuidl
authored andcommitted
feat(RNG): fallback contract update
1 parent 63ecf4a commit 937fb97

File tree

3 files changed

+19
-97
lines changed

3 files changed

+19
-97
lines changed

contracts/src/rng/BlockhashRNG.sol

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ contract BlockHashRNG is IRNG {
7777
/// @dev Return the random number. If it has not been saved and is still computable compute it.
7878
/// @return randomNumber The random number or 0 if it is not ready or has not been requested.
7979
function receiveRandomness() external override onlyByConsumer returns (uint256 randomNumber) {
80-
if (requestTimestamp == 0) return 0; // No request made
80+
if (requestTimestamp == 0) return 0; // No requests were made yet.
8181

8282
uint256 expectedTimestamp = requestTimestamp + lookaheadTime;
8383

@@ -107,14 +107,14 @@ contract BlockHashRNG is IRNG {
107107
/// @dev Check if randomness is ready to be received.
108108
/// @return ready True if randomness can be received.
109109
function isRandomnessReady() external view returns (bool ready) {
110-
if (requestTimestamp == 0) return false;
110+
if (requestTimestamp == 0) return false; // No requests were made yet.
111111
return block.timestamp >= requestTimestamp + lookaheadTime;
112112
}
113113

114114
/// @dev Get the timestamp when randomness will be ready.
115115
/// @return readyTimestamp The timestamp when randomness will be available.
116116
function getRandomnessReadyTimestamp() external view returns (uint256 readyTimestamp) {
117-
if (requestTimestamp == 0) return 0;
117+
if (requestTimestamp == 0) return 0; // No requests were made yet.
118118
return requestTimestamp + lookaheadTime;
119119
}
120120
}

contracts/src/rng/RNGWithFallback.sol

Lines changed: 14 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
88
contract 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
}

contracts/test/foundry/KlerosCore.t.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ contract KlerosCoreTest is Test {
9494
maxDrawingTime = 24;
9595
hiddenVotes = false;
9696

97-
rngLookahead = 600;
97+
rngLookahead = 30;
9898
rng = new BlockHashRNG(msg.sender, address(sortitionModule), rngLookahead);
9999

100100
UUPSProxy proxyCore = new UUPSProxy(address(coreLogic), "");
@@ -1471,7 +1471,7 @@ contract KlerosCoreTest is Test {
14711471
arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
14721472
vm.warp(block.timestamp + minStakingTime);
14731473
sortitionModule.passPhase(); // Generating
1474-
vm.roll(block.number + rngLookahead + 1);
1474+
vm.warp(block.timestamp + rngLookahead);
14751475
sortitionModule.passPhase(); // Drawing phase
14761476

14771477
core.draw(disputeID, DEFAULT_NB_OF_JURORS); // No one is staked so check that the empty addresses are not drawn.

0 commit comments

Comments
 (0)