From a476a6d05c09c2a2d7c7fb3b62969f9f8a52c5f2 Mon Sep 17 00:00:00 2001 From: fearlseefe <505380967@qq.com> Date: Thu, 11 Apr 2024 15:42:17 +0800 Subject: [PATCH] feat: add test for verify update --- portalnetwork/beacon/light_client.go | 45 +++++++++------ portalnetwork/beacon/light_client_test.go | 68 +++++++++++++++++++++++ portalnetwork/beacon/types.go | 2 + 3 files changed, 98 insertions(+), 17 deletions(-) diff --git a/portalnetwork/beacon/light_client.go b/portalnetwork/beacon/light_client.go index 30d3e30530..b4005cc224 100644 --- a/portalnetwork/beacon/light_client.go +++ b/portalnetwork/beacon/light_client.go @@ -16,7 +16,6 @@ import ( blsu "github.com/protolambda/bls12-381-util" "github.com/protolambda/ztyp/tree" "github.com/protolambda/ztyp/view" - "github.com/prysmaticlabs/go-bitfield" ) var ( @@ -161,11 +160,14 @@ func (c *ConsensusLightClient) isValidCheckpoint(blockHashSlot common.Slot) bool } func (c *ConsensusLightClient) VerifyGenericUpdate(update *GenericUpdate) error { - bits := bitfield.Bitlist(update.SyncAggregate.SyncCommitteeBits).Count() + bits := c.getBits(update.SyncAggregate.SyncCommitteeBits) if bits == 0 { return ErrInsufficientParticipation } - updateFinalizedSlot := update.FinalizedHeader.Slot + updateFinalizedSlot := common.Slot(0) + if update.FinalizedHeader != nil { + updateFinalizedSlot = update.FinalizedHeader.Slot + } validTime := uint64(c.expectedCurrentSlot()) >= uint64(update.SignatureSlot) && update.SignatureSlot > update.AttestedHeader.Slot && update.AttestedHeader.Slot >= updateFinalizedSlot if !validTime { return ErrInvalidTimestamp @@ -209,7 +211,7 @@ func (c *ConsensusLightClient) VerifyGenericUpdate(update *GenericUpdate) error syncCommittee = c.Store.NextSyncCommittee } - pks := GetParticipatingKeys(*syncCommittee, update.SyncAggregate.SyncCommitteeBits) + pks := c.getParticipatingKeys(*syncCommittee, update.SyncAggregate.SyncCommitteeBits) isValidSig, err := c.VerifySyncCommitteeSignature(pks, *update.AttestedHeader, update.SyncAggregate.SyncCommitteeSignature, update.SignatureSlot) if err != nil { @@ -237,7 +239,7 @@ func (c *ConsensusLightClient) VerifyOptimisticUpdate(update *capella.LightClien } func (c *ConsensusLightClient) ApplyGenericUpdate(update *GenericUpdate) { - commiteeBits := bitfield.Bitlist(update.SyncAggregate.SyncCommitteeBits).Count() + commiteeBits := c.getBits(update.SyncAggregate.SyncCommitteeBits) if c.Store.CurrentMaxActiveParticipants < view.Uint64View(commiteeBits) { c.Store.CurrentMaxActiveParticipants = view.Uint64View(commiteeBits) @@ -374,7 +376,7 @@ func (c *ConsensusLightClient) hasFinalityUpdate(update *GenericUpdate) bool { } func (c *ConsensusLightClient) logFinalityUpdate(update *GenericUpdate) { - count := bitfield.Bitlist(update.SyncAggregate.SyncCommitteeBits).Count() + count := c.getBits(update.SyncAggregate.SyncCommitteeBits) participation := float32(count) / 512 * 100 decimals := 0 if participation == 100.0 { @@ -404,6 +406,26 @@ func (c *ConsensusLightClient) age(slot common.Slot) (time.Duration, error) { return time.Since(time.Unix(int64(expectTime), 0)), nil } +func (c *ConsensusLightClient) getBits(sync altair.SyncCommitteeBits) uint64 { + res := 0 + for i := 0; i < int(c.Config.Spec.SYNC_COMMITTEE_SIZE); i++ { + if sync.GetBit(uint64(i)) { + res++ + } + } + return uint64(res) +} + +func (c *ConsensusLightClient) getParticipatingKeys(committee common.SyncCommittee, syncBits altair.SyncCommitteeBits) []common.BLSPubkey { + res := make([]common.BLSPubkey, 0) + for i := 0; i < int(c.Config.Spec.SYNC_COMMITTEE_SIZE); i++ { + if syncBits.GetBit(uint64(i)) { + res = append(res, committee.Pubkeys[i]) + } + } + return res +} + func FromLightClientUpdate(update *capella.LightClientUpdate) *GenericUpdate { return &GenericUpdate{ AttestedHeader: &update.AttestedHeader.Beacon, @@ -458,14 +480,3 @@ func IsNextCommitteeProofValid(attestedHeader common.BeaconBlockHeader, nextComm root := attestedHeader.StateRoot return merkle.VerifyMerkleBranch(leaf, nextCommitteeBranch[:], 5, 23, root) } - -func GetParticipatingKeys(committee common.SyncCommittee, syncBits altair.SyncCommitteeBits) []common.BLSPubkey { - bits := bitfield.Bitlist(syncBits) - res := make([]common.BLSPubkey, 0, bits.Count()) - for i := 0; i < int(bits.Len()); i++ { - if bits.BitAt(uint64(i)) { - res = append(res, committee.Pubkeys[i]) - } - } - return res -} diff --git a/portalnetwork/beacon/light_client_test.go b/portalnetwork/beacon/light_client_test.go index 689e4a5528..b0e6049890 100644 --- a/portalnetwork/beacon/light_client_test.go +++ b/portalnetwork/beacon/light_client_test.go @@ -11,6 +11,7 @@ import ( "github.com/protolambda/zrnt/eth2/beacon/capella" "github.com/protolambda/zrnt/eth2/beacon/common" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) var _ ConsensusAPI = (*MockConsensusAPI)(nil) @@ -93,3 +94,70 @@ func TestVerifyCheckpointAgeInvalid(t *testing.T) { _, err := getClient(true, t) assert.ErrorContains(t, err, "checkpoint is too old") } + +func TestVerifyUpdate(t *testing.T) { + client, err := getClient(false, t) + require.NoError(t, err) + + period := CalcSyncPeriod(uint64(client.Store.FinalizedHeader.Slot)) + updates, err := client.API.GetUpdates(period, MaxRequestLightClientUpdates) + require.NoError(t, err) + // normal + err = client.VerifyUpdate(updates[0]) + require.NoError(t, err) + // ErrInvalidNextSyncCommitteeProof + updates[0].NextSyncCommittee.Pubkeys[0] = common.BLSPubkey{} + err = client.VerifyUpdate(updates[0]) + require.Equal(t, ErrInvalidNextSyncCommitteeProof, err) + // ErrInvalidFinalityProof + updates, err = client.API.GetUpdates(period, MaxRequestLightClientUpdates) + require.NoError(t, err) + updates[0].FinalizedHeader.Beacon = common.BeaconBlockHeader{} + err = client.VerifyUpdate(updates[0]) + require.Equal(t, ErrInvalidFinalityProof, err) + + // ErrInvalidSignature + updates, err = client.API.GetUpdates(period, MaxRequestLightClientUpdates) + require.NoError(t, err) + updates[0].SyncAggregate.SyncCommitteeSignature[1] = 0xFE + err = client.VerifyUpdate(updates[0]) + require.Error(t, err) +} + +func TestVerifyFinalityUpdate(t *testing.T) { + client, err := getClient(false, t) + require.NoError(t, err) + + update, err := client.API.GetFinalityData() + require.NoError(t, err) + + // normal + err = client.VerifyFinalityUpdate(update) + require.NoError(t, err) + + update.FinalizedHeader.Beacon = common.BeaconBlockHeader{} + err = client.VerifyFinalityUpdate(update) + require.Equal(t, ErrInvalidFinalityProof, err) + // ErrInvalidSignature + update, err = client.API.GetFinalityData() + require.NoError(t, err) + update.SyncAggregate.SyncCommitteeSignature[1] = 0xFE + err = client.VerifyFinalityUpdate(update) + require.Error(t, err) +} + +func TestVerifyOptimisticUpdate(t *testing.T) { + client, err := getClient(false, t) + require.NoError(t, err) + + update, err := client.API.GetOptimisticData() + require.NoError(t, err) + + // normal + err = client.VerifyOptimisticUpdate(update) + require.NoError(t, err) + + update.SyncAggregate.SyncCommitteeSignature = common.BLSSignature{} + err = client.VerifyOptimisticUpdate(update) + require.Error(t, err) +} diff --git a/portalnetwork/beacon/types.go b/portalnetwork/beacon/types.go index e3ddd777c8..1eb7c7bad9 100644 --- a/portalnetwork/beacon/types.go +++ b/portalnetwork/beacon/types.go @@ -10,6 +10,8 @@ import ( tree "github.com/protolambda/ztyp/tree" ) +const MaxRequestLightClientUpdates = 128 + var ( Bellatrix common.ForkDigest = [4]byte{0x0, 0x0, 0x0, 0x0} Capella common.ForkDigest = [4]byte{0xbb, 0xa4, 0xda, 0x96}