From 2bc91d20f9fa8274cf7516ab21b219d5e06ee1cd Mon Sep 17 00:00:00 2001 From: terencechain Date: Sat, 22 Jul 2023 00:37:27 -0700 Subject: [PATCH] feat: EIP7045 increase max att inclusion slot (#12565) --- beacon-chain/core/altair/attestation.go | 4 +- beacon-chain/core/altair/attestation_test.go | 32 +++++++++++++++- beacon-chain/core/blocks/attestation.go | 20 ++++++---- beacon-chain/core/blocks/attestation_test.go | 38 +++++++++++++++++++ beacon-chain/core/helpers/attestation.go | 28 ++++++++++++-- beacon-chain/core/helpers/attestation_test.go | 38 +++++++++++++++++++ 6 files changed, 145 insertions(+), 15 deletions(-) diff --git a/beacon-chain/core/altair/attestation.go b/beacon-chain/core/altair/attestation.go index a6366147c..e9afd2c5a 100644 --- a/beacon-chain/core/altair/attestation.go +++ b/beacon-chain/core/altair/attestation.go @@ -289,13 +289,13 @@ func AttestationParticipationFlagIndices(beaconState state.BeaconState, data *et sourceFlagIndex := cfg.TimelySourceFlagIndex targetFlagIndex := cfg.TimelyTargetFlagIndex headFlagIndex := cfg.TimelyHeadFlagIndex - slotsPerEpoch := cfg.SlotsPerEpoch sqtRootSlots := cfg.SqrRootSlotsPerEpoch if matchedSrc && delay <= sqtRootSlots { participatedFlags[sourceFlagIndex] = true } matchedSrcTgt := matchedSrc && matchedTgt - if matchedSrcTgt && delay <= slotsPerEpoch { + // Before Deneb no attestation should pass validation without having delay <= slotsPerEpoch. + if matchedSrcTgt { participatedFlags[targetFlagIndex] = true } matchedSrcTgtHead := matchedHead && matchedSrcTgt diff --git a/beacon-chain/core/altair/attestation_test.go b/beacon-chain/core/altair/attestation_test.go index 98ad7efe2..aa0fde4b5 100644 --- a/beacon-chain/core/altair/attestation_test.go +++ b/beacon-chain/core/altair/attestation_test.go @@ -630,6 +630,9 @@ func TestAttestationParticipationFlagIndices(t *testing.T) { targetFlagIndex := cfg.TimelyTargetFlagIndex headFlagIndex := cfg.TimelyHeadFlagIndex + denebState, _ := util.DeterministicGenesisStateDeneb(t, params.BeaconConfig().MaxValidatorsPerCommittee) + require.NoError(t, denebState.SetSlot(1)) + tests := []struct { name string inputState state.BeaconState @@ -678,6 +681,34 @@ func TestAttestationParticipationFlagIndices(t *testing.T) { targetFlagIndex: true, }, }, + { + name: "participated source and target with delay", + inputState: func() state.BeaconState { + return beaconState + }(), + inputData: ðpb.AttestationData{ + Source: ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}, + Target: ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}, + }, + inputDelay: params.BeaconConfig().SlotsPerEpoch + 1, + participationIndices: map[uint8]bool{ + targetFlagIndex: true, + }, + }, + { + name: "participated source and target with delay in deneb", + inputState: func() state.BeaconState { + return denebState + }(), + inputData: ðpb.AttestationData{ + Source: ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}, + Target: ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}, + }, + inputDelay: params.BeaconConfig().SlotsPerEpoch + 1, + participationIndices: map[uint8]bool{ + targetFlagIndex: true, + }, + }, { name: "participated source and target and head", inputState: func() state.BeaconState { @@ -696,7 +727,6 @@ func TestAttestationParticipationFlagIndices(t *testing.T) { }, }, } - for _, test := range tests { flagIndices, err := altair.AttestationParticipationFlagIndices(test.inputState, test.inputData, test.inputDelay) require.NoError(t, err) diff --git a/beacon-chain/core/blocks/attestation.go b/beacon-chain/core/blocks/attestation.go index 83c4d90c6..07ef0f680 100644 --- a/beacon-chain/core/blocks/attestation.go +++ b/beacon-chain/core/blocks/attestation.go @@ -16,6 +16,7 @@ import ( "github.com/prysmaticlabs/prysm/v4/crypto/bls" ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1" "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1/attestation" + "github.com/prysmaticlabs/prysm/v4/runtime/version" "go.opencensus.io/trace" ) @@ -81,7 +82,6 @@ func VerifyAttestationNoVerifySignature( s := att.Data.Slot minInclusionCheck := s+params.BeaconConfig().MinAttestationInclusionDelay <= beaconState.Slot() - epochInclusionCheck := beaconState.Slot() <= s+params.BeaconConfig().SlotsPerEpoch if !minInclusionCheck { return fmt.Errorf( "attestation slot %d + inclusion delay %d > state slot %d", @@ -90,13 +90,17 @@ func VerifyAttestationNoVerifySignature( beaconState.Slot(), ) } - if !epochInclusionCheck { - return fmt.Errorf( - "state slot %d > attestation slot %d + SLOTS_PER_EPOCH %d", - beaconState.Slot(), - s, - params.BeaconConfig().SlotsPerEpoch, - ) + + if beaconState.Version() < version.Deneb { + epochInclusionCheck := beaconState.Slot() <= s+params.BeaconConfig().SlotsPerEpoch + if !epochInclusionCheck { + return fmt.Errorf( + "state slot %d > attestation slot %d + SLOTS_PER_EPOCH %d", + beaconState.Slot(), + s, + params.BeaconConfig().SlotsPerEpoch, + ) + } } activeValidatorCount, err := helpers.ActiveValidatorCount(ctx, beaconState, att.Data.Target.Epoch) if err != nil { diff --git a/beacon-chain/core/blocks/attestation_test.go b/beacon-chain/core/blocks/attestation_test.go index d61fc01ab..29fe2dbd9 100644 --- a/beacon-chain/core/blocks/attestation_test.go +++ b/beacon-chain/core/blocks/attestation_test.go @@ -127,6 +127,44 @@ func TestProcessAttestationsNoVerify_OK(t *testing.T) { assert.NoError(t, err) } +func TestProcessAttestationsNoVerify_OlderThanSlotsPerEpoch(t *testing.T) { + aggBits := bitfield.NewBitlist(3) + aggBits.SetBitAt(1, true) + att := ðpb.Attestation{ + Data: ðpb.AttestationData{ + Source: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)}, + Target: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)}, + }, + AggregationBits: aggBits, + } + ctx := context.Background() + + t.Run("attestation older than slots per epoch", func(t *testing.T) { + beaconState, _ := util.DeterministicGenesisState(t, 100) + + err := beaconState.SetSlot(beaconState.Slot() + params.BeaconConfig().SlotsPerEpoch + 1) + require.NoError(t, err) + ckp := beaconState.CurrentJustifiedCheckpoint() + copy(ckp.Root, "hello-world") + require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(ckp)) + require.NoError(t, beaconState.AppendCurrentEpochAttestations(ðpb.PendingAttestation{})) + + require.ErrorContains(t, "state slot 33 > attestation slot 0 + SLOTS_PER_EPOCH 32", blocks.VerifyAttestationNoVerifySignature(ctx, beaconState, att)) + }) + + t.Run("attestation older than slots per epoch in deneb", func(t *testing.T) { + beaconState, _ := util.DeterministicGenesisStateDeneb(t, 100) + + err := beaconState.SetSlot(beaconState.Slot() + params.BeaconConfig().SlotsPerEpoch + 1) + require.NoError(t, err) + ckp := beaconState.CurrentJustifiedCheckpoint() + copy(ckp.Root, "hello-world") + require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(ckp)) + + require.NoError(t, blocks.VerifyAttestationNoVerifySignature(ctx, beaconState, att)) + }) +} + func TestVerifyAttestationNoVerifySignature_OK(t *testing.T) { // Attestation with an empty signature diff --git a/beacon-chain/core/helpers/attestation.go b/beacon-chain/core/helpers/attestation.go index 8a409c89c..b3246c28b 100644 --- a/beacon-chain/core/helpers/attestation.go +++ b/beacon-chain/core/helpers/attestation.go @@ -12,6 +12,7 @@ import ( ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1" prysmTime "github.com/prysmaticlabs/prysm/v4/time" "github.com/prysmaticlabs/prysm/v4/time/slots" + log "github.com/sirupsen/logrus" ) var ( @@ -166,14 +167,33 @@ func ValidateAttestationTime(attSlot primitives.Slot, genesisTime time.Time, clo lowerBoundsSlot, currentSlot, ) - if attTime.Before(lowerBounds) { - attReceivedTooLateCount.Inc() - return errors.Join(ErrTooLate, attError) - } if attTime.After(upperBounds) { attReceivedTooEarlyCount.Inc() return attError } + + attEpoch := slots.ToEpoch(attSlot) + if attEpoch < params.BeaconConfig().DenebForkEpoch { + if attTime.Before(lowerBounds) { + attReceivedTooLateCount.Inc() + return errors.Join(ErrTooLate, attError) + } + return nil + } + + // EIP-7045: Starting in Deneb, allow any attestations from the current or previous epoch. + + currentEpoch := slots.ToEpoch(currentSlot) + prevEpoch, err := currentEpoch.SafeSub(1) + if err != nil { + log.WithError(err).Debug("Ignoring underflow for a deneb attestation inclusion check in epoch 0") + prevEpoch = 0 + } + attSlotEpoch := slots.ToEpoch(attSlot) + if attSlotEpoch != currentEpoch && attSlotEpoch != prevEpoch { + return fmt.Errorf("attestation slot %d not within current epoch %d or previous epoch %d", attSlot, currentEpoch, prevEpoch) + } + return nil } diff --git a/beacon-chain/core/helpers/attestation_test.go b/beacon-chain/core/helpers/attestation_test.go index 38173f0f8..3e1b117d9 100644 --- a/beacon-chain/core/helpers/attestation_test.go +++ b/beacon-chain/core/helpers/attestation_test.go @@ -85,6 +85,11 @@ func TestAttestation_ComputeSubnetForAttestation(t *testing.T) { } func Test_ValidateAttestationTime(t *testing.T) { + cfg := params.BeaconConfig().Copy() + cfg.DenebForkEpoch = 5 + params.OverrideBeaconConfig(cfg) + params.SetupTestConfigCleanup(t) + if params.BeaconNetworkConfig().MaximumGossipClockDisparity < 200*time.Millisecond { t.Fatal("This test expects the maximum clock disparity to be at least 200ms") } @@ -155,6 +160,39 @@ func Test_ValidateAttestationTime(t *testing.T) { ).Add(200 * time.Millisecond), }, }, + { + name: "attestation.slot < current_slot-ATTESTATION_PROPAGATION_SLOT_RANGE in deneb", + args: args{ + attSlot: 300 - params.BeaconNetworkConfig().AttestationPropagationSlotRange - 1, + genesisTime: prysmTime.Now().Add(-300 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second), + }, + }, + { + name: "attestation.slot = current_slot-ATTESTATION_PROPAGATION_SLOT_RANGE in deneb", + args: args{ + attSlot: 300 - params.BeaconNetworkConfig().AttestationPropagationSlotRange, + genesisTime: prysmTime.Now().Add(-300 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second), + }, + }, + { + name: "attestation.slot = current_slot-ATTESTATION_PROPAGATION_SLOT_RANGE, received 200ms late in deneb", + args: args{ + attSlot: 300 - params.BeaconNetworkConfig().AttestationPropagationSlotRange, + genesisTime: prysmTime.Now().Add( + -300 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second, + ).Add(200 * time.Millisecond), + }, + }, + { + name: "attestation.slot != current epoch or previous epoch in deneb", + args: args{ + attSlot: 300 - params.BeaconNetworkConfig().AttestationPropagationSlotRange, + genesisTime: prysmTime.Now().Add( + -500 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second, + ).Add(200 * time.Millisecond), + }, + wantedErr: "attestation slot 268 not within current epoch 15 or previous epoch 14", + }, { name: "attestation.slot is well beyond current slot", args: args{