The function RapBattle::_battle
uses block.timestamp
and block.prevrandao
to generate random
number. This random
number is then used to determine the winner of the battle. But relying on the block.timestamp
and block.prevrandao
for randomness can be risky and the generated random
number can be predicted rather than random.
The RapBattle::_battle
function determines the winner of the battle based on random number and rapper skills of the participants.
But the generation of random
is based on block.timestamp, block.prevrandao, msg.sender
which is not recommended.
Relying on block.timestamp
for randomness is risky because the validator selected for a transaction has the power to hold or delay the transaction until a more favorable time or reject the transaction because the timestamp isn't favorable.
Timestamp manipulation has become less of an issue on Ethereum
, since the merge, but it isn't perfect. Other chains, such as Arbitrum
can be vulnerable to several seconds of slippage putting randomness based on block.timestamp
at risk.
block.prevrandao
replaced the block.difficulty
. This is a system to choose random validators. The security issues using this value for randomness are described in the EIP-4399 documentation: https://eips.ethereum.org/EIPS/eip-4399#predictability
Additionally, in the Solidity
documentation is written:
https://docs.soliditylang.org/en/latest/units-and-global-variables.html
The function RapBattle::_battle
uses block.timestamp
, block.prevrandao
and msg.sender
to generate a pseudo-random number for determining the winner of the battle. This is considered weak because miners have some control over the block.timestamp
and block.prevrandao
, which could potentially be exploited to manipulate the outcome of the battle. The block.timestamp
influences the keccak256
function, and subsequently the _battle
function, by being part of the seed that generates the pseudo-random number. In the _battle
function, the seed for the keccak256
function is created by packing block.timestamp
, block.prevrandao
and msg.sender
together using abi.encodePacked
.
To demonstrate the weak randomness in the _battle
function, we can write a test case that manipulates the block.timestamp
and block.prevrandao
using the vm.warp
and vm.prevrandao
functions in Foundry. The vm.warp
and vm.prevrandao
functions in Foundry give control over the simulated blockchain environment in the tests. These functions don't directly influence the calculation of the winner in the _battle
function, but they do allow to manipulate the values that are used in that calculation. Add the following test case in file OneShot.t.test.sol
and execute it with the Foundry command: forge test --match-test "testWeakRandomness" -vvvvv
.
The test function testWeakRandomness
demonstrates that in two battles with the same participants the generated random
number and respectively the winner are the same.
Manual Review, Foundry
You might consider using a dedicated randomness oracle such as Chainlink VRF. https://blog.chain.link/random-number-generation-solidity/
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.