The block.prevdao
is completely biasable by the proposer
As seen in the excerpt below, the block randao is the hash of all the transactions in the last block. While on-chain dApps should not rely on block.prevrandao
, if any on-chain dApp does rely on block.prevrandao
, an opportunistic proposer could brute-force a favorable randao
value to extract value out of on-chain dApps that use it as source of randomness.
// startBuild triggers the building of a new execution payload on top of the current execution head.
// It returns the EngineAPI response which contains a status and payload ID.
func (k *Keeper) startBuild(ctx context.Context, appHash common.Hash, timestamp time.Time) (engine.ForkChoiceResponse, error) {
...
attrs := &engine.PayloadAttributes{
Timestamp: ts,
Random: head.Hash(), // We use head block hash as randao.
SuggestedFeeRecipient: k.feeRecProvider.LocalFeeRecipient(),
Withdrawals: []*etypes.Withdrawal{}, // Withdrawals not supported yet.
BeaconRoot: &appHash,
}
...
return resp, nil
}