berachain / beacon-kit

A modular framework for building EVM consensus clients ⛵️✨
https://berachain.com
Other
97 stars 62 forks source link

Predictable `PrevRandao` #778

Open sbudella-gco opened 3 months ago

sbudella-gco commented 3 months ago

Description

Beacon-kit adds support for randomness exposed on-chain as per EIP-4399: a smart contract could access the previous block's RANDAO mix from the block object's attribute block.prevrandao, which exposes the block's payload attributes member PrevRandao, as seen in engine/types/attributes.go:

type PayloadAttributes struct {
        // version is the version of the payload attributes.
        version uint32
        // Timestamp is the timestamp at which the block will be built at.
        Timestamp uint64 `json:"timestamp"             gencodec:"required"`
        // PrevRandao is the previous Randao value from the beacon chain as
        // per EIP-4399.
        PrevRandao [32]byte `json:"prevRandao"            gencodec:"required"`
...

The member is populated upon instantiation of the structure in function NewPayloadAttributes under engine/types/attributes.go, which is invoked by the local builder service when constructing the local payload in BuildLocalPayload, under beacon/builder/local/payload.go:

func (s *Service) getPayloadAttribute(
        ctx context.Context,
        slot primitives.Slot,
        timestamp uint64,
        prevHeadRoot [32]byte,
) (enginetypes.PayloadAttributer, error) {
        var (
                prevRandao [32]byte
                st         = s.BeaconState(ctx)
        )
[..]
        // Get the previous randao mix.
        prevRandao, err = st.GetRandaoMixAtIndex(
                uint64(slot) % s.BeaconCfg().EpochsPerHistoricalVector,
        )
        if err != nil {
                return nil, err
        }

        return enginetypes.NewPayloadAttributes(
                s.ActiveForkVersionForSlot(slot),
                timestamp,
                prevRandao,
[..]

GetRandaoMixAtIndex retrieves the RANDAO value which was generated and mixed by closely following the Ethereum Beacon specification: basically each block proposer contributes to the RANDAO pool by signing the current epoch value with its BLS key; the signature is then xored with the previously stored RANDAO value.

The purpose of the RANDAO in the Ethereum beacon specification is that of providing on-chain randomness which is then sourced for the seed used to select the block proposer at any given slot, and to compose the committee of validators that get the chance to vote on the proposals.

Beacon-kit's underlying consensus protocol Tendermint uses a completely different scheme for the selection of the block proposer, and there is no facility in the Cosmos SDK <-> CometBFT/Tendermint ABCI to either override or influence the selection from the application. This is the reason why the RANDAO machinery is used in Beacon-kit only for supporting EIP-4399.

Given that prevrandao is the RANDAO value of the previous block, this value is assumed as public, as it is the case in EIP-4399, which therefore suggests to contract developers to source the prevrandao from blocks in the future ("rolling the dice"), in order to benefit from this value without suffering any predictability attack (and biasability, up to a certain extent). The minimum number of epochs into the future is the MAX_SEED_LOOKAHEAD (four epochs), which is the duration during which any update of the validator set is delayed, in order to neutralize withdrawals and deposits from validators who intend to take over the randao.

This countermeasure seems to be absent in Beacon-kit: it is worth mentioning that Tendermint has "Single Slot Finality", meaning that each block is finalized and can't be the subject of reorganizations; this also implies that there is no concept of epoch, given that each block represents a checkpoint implicitly by either being elected or rejected. Therefore, Beacon-kit has no other choice than processing the logs originating from the Deposit/Withdrawal contract no older than one block back into the past. For details, see function PostBlockProcess under beacon/blockchain/process.go, where the logs are processed on the justified block, which is equal to the finalized block, due to the single slot finality:

[..]
        if err := s.sks.ProcessLogsInETH1Block(
                ctx,
                s.ForkchoiceStore(ctx).JustifiedPayloadBlockHash(),
        ); err != nil {
                s.Logger().Error("failed to process logs", "error", err)
                return err
        }
[..]

However, a dishonest validator does not need to go that far as to influence the RANDAO value (a process named "randomness grinding"), because the Tendermint proposer selection mechanism is completely deterministic, to the extent that the following property is guaranteed to hold:

Given a validator set V, and two honest validators p and q, for each
height h and each round r the following must hold:

proposer_p(h,r) = proposer_q(h,r)

In other words, it is always possible at any given block Height h (and round r) to know which validator will be selected. This means that a malicious actor could just kick out of the validator set as many validators as they wish in order to withold the value of the RANDAO up before the "dice rolling" block used by the contract. Deposits would only increase its voting power and hence speed up the process. This is particularly concerning in CometBFT networks, where validator sets are much smaller compared to the current Ethereum beacon chain's.

When designing on-chain randomness facilities, one must be aware that reaching consensus on randomness is, in most cases, not possible (which is why Tendermint has no on-chain randomness altogether).

itsdevbear commented 3 months ago

Noted and I agree, we just ignored this for the initial implementation and need to go back and revisit.

Would a delay in validator set changes that corresponds to introducing a seed look ahead resolve this?

sbudella-gco commented 3 months ago

I am not completely sure, because validators already in the set could still benefit from the deterministic selection.