diff --git a/contracts/standard/rng/BeaconRNG.sol b/contracts/standard/rng/BeaconRNG.sol index e286e337..95eb9036 100644 --- a/contracts/standard/rng/BeaconRNG.sol +++ b/contracts/standard/rng/BeaconRNG.sol @@ -1,6 +1,6 @@ /** - * @authors: [@shalzz] - * @reviewers: [@jaybuidl] + * @authors: [@shalzz, @unknownunknown1] + * @reviewers: [@jaybuidl*, @geaxed*] * @auditors: [] * @bounties: [] * @deployments: [] @@ -13,26 +13,48 @@ import "./RNG.sol"; /** * @title Random Number Generator using beacon chain random opcode */ -contract BeaconRNG is RNG { +contract BeaconRNG { + + uint public constant LOOKAHEAD = 132; // Number of blocks that has to pass before obtaining the random number. 4 epochs + 4 slots, according to EIP-4399. + uint public constant ERROR = 32; // Number of blocks after which the lookahead gets reset, so eligible blocks after lookahead don't go long distance, to avoid a possiblity for manipulation. - /** - * @dev Since we don't really need to incentivise requesting the beacon chain randomness, - * this is a stub implementation required for backwards compatibility with the - * RNG interface. - * @notice All the ETH sent here will be lost forever. - * @param _block Block the random number is linked to. + RNG public blockhashRNG; // Address of blockhashRNG to fall back on. + + /** @dev Constructor. + * @param _blockhashRNG The blockhash RNG deployed contract address. */ - function contribute(uint _block) public payable {} + constructor(RNG _blockhashRNG) public { + blockhashRNG = _blockhashRNG; + } + /** + * @dev Request a random number. It is not used by this contract and only exists for backward compatibility. + */ + function requestRN(uint /*_block*/) public pure {} - /** @dev Return the random number from the PoS randomness beacon. - * @param _block Block the random number is linked to. - * @return RN Random Number. If the PoS upgrade defined by EIP-3675 - * has not yet executed 0 instead. + /** + * @dev Get an uncorrelated random number. + * @param _block Block the random number is linked to. + * @return RN Random Number. If the number is not ready or has not been required 0 instead. */ - function getRN(uint _block) public returns (uint RN) { - if (block.difficulty <= 2**64) - return 0; - return block.difficulty; + function getUncorrelatedRN(uint _block) public returns (uint) { + // Pre-Merge. + if (block.difficulty <= 2**64) { + uint baseRN = blockhashRNG.getRN(_block); + if (baseRN == 0) { + return 0; + } else { + return uint(keccak256(abi.encodePacked(msg.sender, baseRN))); + } + // Post-Merge. + } else { + if (block.number > _block && (block.number - _block) % (LOOKAHEAD + ERROR) > LOOKAHEAD) { + // Eligible block number should exceed LOOKAHEAD but shouldn't be higher than LOOKAHEAD + ERROR. + // In case of the latter LOOKAHEAD gets reset. + return uint(keccak256(abi.encodePacked(msg.sender, block.difficulty))); + } else { + return 0; + } + } } } diff --git a/contracts/standard/rng/BeaconRNGFallback.sol b/contracts/standard/rng/BeaconRNGFallback.sol deleted file mode 100644 index 54c5f9df..00000000 --- a/contracts/standard/rng/BeaconRNGFallback.sol +++ /dev/null @@ -1,76 +0,0 @@ - /** - * @authors: [@shalzz, @unknownunknown1] - * @reviewers: [@jaybuidl, @geaxed*] - * @auditors: [] - * @bounties: [] - * @deployments: [] - */ - -pragma solidity ^0.4.15; - -import "./RNG.sol"; - -/** - * @title Random Number Generator using beacon chain random opcode - */ -contract BeaconRNGFallBack is RNG { - - RNG public beaconRNG; - RNG public blockhashRNG; - - uint public constant LOOKAHEAD = 132; // Number of blocks that has to pass before obtaining the random number. 4 epochs + 4 slots, according to EIP-4399. - - /** @dev Constructor. - * @param _beaconRNG The beacon chain RNG deployed contract address - * @param _blockhashRNG The blockhash RNG deployed contract address - */ - constructor(RNG _beaconRNG, RNG _blockhashRNG) public { - beaconRNG = _beaconRNG; - blockhashRNG = _blockhashRNG; - } - - /** - * @dev Since we don't really need to incentivize requesting the beacon chain randomness, - * this is a stub implementation required for backwards compatibility with the - * RNG interface. - * @notice All the ETH sent here will be lost forever. - * @param _block Block the random number is linked to. - */ - function contribute(uint _block) public payable {} - - /** - * @dev Request a random number. - * @dev Since the beacon chain randomness is not related to a block - * we can call ahead its getRN function to check if the PoS merge has happened or not. - * - * @param _block Block linked to the request. - */ - function requestRN(uint _block) public payable { - uint RN = beaconRNG.getRN(_block); - - if (RN == 0) { - blockhashRNG.contribute(_block); - } else { - beaconRNG.contribute(_block); - } - } - - /** - * @dev Get the random number. - * @param _block Block the random number is linked to. - * @return RN Random Number. If the number is not ready or has not been required 0 instead. - */ - function getRN(uint _block) public returns (uint RN) { - RN = beaconRNG.getRN(_block); - - // if beacon chain randomness is zero - // fallback to blockhash RNG - if (RN == 0) { - RN = blockhashRNG.getRN(_block); - } else if (block.number < _block + LOOKAHEAD) { - // Beacon chain returns the random number, but sufficient number of blocks hasn't been mined yet. - // In this case signal to the court that RN isn't ready. - RN = 0; - } - } -}