Repository: unionlabs/union
File: lib/ethereum-verifier/src/verify.rs (Rust)

Code before:
    VerifyStorageAbsenceError, VerifyStorageProofError,
};

type MinSyncCommitteeParticipants<Ctx> =
    <<Ctx as LightClientContext>::ChainSpec as MIN_SYNC_COMMITTEE_PARTICIPANTS>::MIN_SYNC_COMMITTEE_PARTICIPANTS;

pub trait BlsVerify {
    fn fast_aggregate_verify<'pk>(
        &self,
        public_keys: impl IntoIterator<Item = &'pk BlsPublicKey>,
        msg: Vec<u8>,
        signature: BlsSignature,
    ) -> Result<(), Error>;
}

/// Verifies if the light client `update` is valid.
///
/// * `update`: The light client update we want to verify.
/// * `current_slot`: The slot number computed based on the current timestamp.
/// * `genesis_validators_root`: The latest `genesis_validators_root` that is saved by the light client.
/// * `bls_verifier`: BLS verification implementation.
///
/// ## Important Notes
/// * This verification does not assume that the updated header is greater (in terms of height) than the
/// light client state. When the updated header is in the next signature period, the light client uses
/// the next sync committee to verify the signature, than it saves the next sync committee as the current
/// sync committee. However, it's not mandatory for light clients to expect the next sync committee to be given
/// during these updates. So if it's not given, the light client still can validate updates until the next signature
/// period arrives. In a situation like this, the update can be any header within the same signature period. And
/// this function only allows a non-existent next sync committee to be set in that case. It doesn't allow a sync committee
/// to be changed or removed.
///
/// [See in consensus-spec](https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#validate_light_client_update)
pub fn validate_light_client_update<Ctx: LightClientContext, V: BlsVerify>(
    ctx: &Ctx,
    update: LightClientUpdate<Ctx::ChainSpec>,
    current_slot: u64,
    genesis_validators_root: H256,
    bls_verifier: V,
) -> Result<(), ValidateLightClientError> {
    // Verify sync committee has sufficient participants
    let sync_aggregate = &update.sync_aggregate;
    ensure(
        sync_aggregate.sync_committee_bits.num_set_bits()
            >= MinSyncCommitteeParticipants::<Ctx>::USIZE,
        Error::InsufficientSyncCommitteeParticipants(
            sync_aggregate.sync_committee_bits.num_set_bits(),
        ),
    )?;

    is_valid_light_client_header(ctx.fork_parameters(), &update.attested_header)?;

Review comment (suggestion):
```suggestion
/// the next sync committee to verify the signature, then it saves the next sync committee as the current
```

Code after:
    VerifyStorageAbsenceError, VerifyStorageProofError,
};

type MinSyncCommitteeParticipants<Ctx> =
    <<Ctx as LightClientContext>::ChainSpec as MIN_SYNC_COMMITTEE_PARTICIPANTS>::MIN_SYNC_COMMITTEE_PARTICIPANTS;

pub trait BlsVerify {
    fn fast_aggregate_verify<'pk>(
        &self,
        public_keys: impl IntoIterator<Item = &'pk BlsPublicKey>,
        msg: Vec<u8>,
        signature: BlsSignature,
    ) -> Result<(), Error>;
}

/// Verifies if the light client `update` is valid.
///
/// * `update`: The light client update we want to verify.
/// * `current_slot`: The slot number computed based on the current timestamp.
/// * `genesis_validators_root`: The latest `genesis_validators_root` that is saved by the light client.
/// * `bls_verifier`: BLS verification implementation.
///
/// ## Important Notes
/// * This verification does not assume that the updated header is greater (in terms of height) than the
/// light client state. When the updated header is in the next signature period, the light client uses
/// the next sync committee to verify the signature, then it saves the next sync committee as the current
/// sync committee. However, it's not mandatory for light clients to expect the next sync committee to be given
/// during these updates. So if it's not given, the light client still can validate updates until the next signature
/// period arrives. In a situation like this, the update can be any header within the same signature period. And
/// this function only allows a non-existent next sync committee to be set in that case. It doesn't allow a sync committee
/// to be changed or removed.
///
/// [See in consensus-spec](https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#validate_light_client_update)
pub fn validate_light_client_update<Ctx: LightClientContext, V: BlsVerify>(
    ctx: &Ctx,
    update: LightClientUpdate<Ctx::ChainSpec>,
    current_slot: u64,
    genesis_validators_root: H256,
    bls_verifier: V,
) -> Result<(), ValidateLightClientError> {
    // Verify sync committee has sufficient participants
    let sync_aggregate = &update.sync_aggregate;
    ensure(
        sync_aggregate.sync_committee_bits.num_set_bits()
            >= MinSyncCommitteeParticipants::<Ctx>::USIZE,
        Error::InsufficientSyncCommitteeParticipants(
            sync_aggregate.sync_committee_bits.num_set_bits(),
        ),
    )?;

    is_valid_light_client_header(ctx.fork_parameters(), &update.attested_header)?;