diff --git a/beacon-chain/blockchain/BUILD.bazel b/beacon-chain/blockchain/BUILD.bazel index 107275b8055b..4f175057cbd3 100644 --- a/beacon-chain/blockchain/BUILD.bazel +++ b/beacon-chain/blockchain/BUILD.bazel @@ -28,6 +28,7 @@ go_library( "receive_blob.go", "receive_block.go", "receive_execution_payload_envelope.go", + "receive_payload_attestation_message.go", "service.go", "tracked_proposer.go", "weak_subjectivity_checks.go", diff --git a/beacon-chain/blockchain/error.go b/beacon-chain/blockchain/error.go index 87ed0d2416db..abb218be45de 100644 --- a/beacon-chain/blockchain/error.go +++ b/beacon-chain/blockchain/error.go @@ -30,6 +30,9 @@ var ( ErrNotCheckpoint = errors.New("not a checkpoint in forkchoice") // ErrNilHead is returned when no head is present in the blockchain service. ErrNilHead = errors.New("nil head") + // errInvalidValidatorIndex is returned when a validator index is + // invalid or unexpected + errInvalidValidatorIndex = errors.New("invalid validator index") ) var errMaxBlobsExceeded = errors.New("Expected commitments in block exceeds MAX_BLOBS_PER_BLOCK") diff --git a/beacon-chain/blockchain/receive_block.go b/beacon-chain/blockchain/receive_block.go index 5c1884709a0a..d4c8deaf9cad 100644 --- a/beacon-chain/blockchain/receive_block.go +++ b/beacon-chain/blockchain/receive_block.go @@ -46,6 +46,12 @@ type BlockReceiver interface { BlockBeingSynced([32]byte) bool } +// PayloadAttestationReceiver defines methods of the chain service for receiving +// and processing new payload attestations and payload attestation messages +type PayloadAttestationReceiver interface { + ReceivePayloadAttestationMessage(ctx context.Context, a *ethpb.PayloadAttestationMessage) error +} + // BlobReceiver interface defines the methods of chain service for receiving new // blobs type BlobReceiver interface { diff --git a/beacon-chain/blockchain/receive_payload_attestation_message.go b/beacon-chain/blockchain/receive_payload_attestation_message.go new file mode 100644 index 000000000000..4aa5c6d9648a --- /dev/null +++ b/beacon-chain/blockchain/receive_payload_attestation_message.go @@ -0,0 +1,33 @@ +package blockchain + +import ( + "context" + "slices" + + "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers" + "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" + eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" +) + +func (s *Service) ReceivePayloadAttestationMessage(ctx context.Context, a *eth.PayloadAttestationMessage) error { + if err := helpers.ValidateNilPayloadAttestationMessage(a); err != nil { + return err + } + root := [32]byte(a.Data.BeaconBlockRoot) + st, err := s.HeadState(ctx) + if err != nil { + return err + } + ptc, err := helpers.GetPayloadTimelinessCommittee(ctx, st, a.Data.Slot) + if err != nil { + return err + } + idx := slices.Index(ptc, a.ValidatorIndex) + if idx == -1 { + return errInvalidValidatorIndex + } + if s.cfg.PayloadAttestationCache.Seen(root, uint64(primitives.ValidatorIndex(idx))) { + return nil + } + return s.cfg.PayloadAttestationCache.Add(a, uint64(idx)) +} diff --git a/beacon-chain/blockchain/testing/mock.go b/beacon-chain/blockchain/testing/mock.go index 64c69931cad5..098c4ff20e7a 100644 --- a/beacon-chain/blockchain/testing/mock.go +++ b/beacon-chain/blockchain/testing/mock.go @@ -639,3 +639,8 @@ func (c *ChainService) TargetRootForEpoch(_ [32]byte, _ primitives.Epoch) ([32]b func (c *ChainService) HashInForkchoice([32]byte) bool { return false } + +// ReceivePayloadAttestationMessage mocks the same method in the chain service +func (c *ChainService) ReceivePayloadAttestationMessage(_ context.Context, _ *ethpb.PayloadAttestationMessage) error { + return nil +} diff --git a/beacon-chain/sync/payload_attestations.go b/beacon-chain/sync/payload_attestations.go index cfb121b12e1f..c7d65b4f383a 100644 --- a/beacon-chain/sync/payload_attestations.go +++ b/beacon-chain/sync/payload_attestations.go @@ -2,15 +2,12 @@ package sync import ( "context" - "slices" pubsub "github.com/libp2p/go-libp2p-pubsub" "github.com/libp2p/go-libp2p/core/peer" "github.com/pkg/errors" - "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers" "github.com/prysmaticlabs/prysm/v5/beacon-chain/verification" payloadattestation "github.com/prysmaticlabs/prysm/v5/consensus-types/epbs/payload-attestation" - "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v5/monitoring/tracing" eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" "go.opencensus.io/trace" @@ -18,7 +15,6 @@ import ( ) var ( - errInvalidValidatorIndex = errors.New("invalid validator index") errAlreadySeenPayloadAttestation = errors.New("payload attestation already seen for validator index") ) @@ -91,25 +87,5 @@ func (s *Service) payloadAttestationSubscriber(ctx context.Context, msg proto.Me if !ok { return errWrongMessage } - if err := helpers.ValidateNilPayloadAttestationMessage(a); err != nil { - return err - } - root := [32]byte(a.Data.BeaconBlockRoot) - st, err := s.cfg.chain.HeadState(ctx) - if err != nil { - return err - } - ptc, err := helpers.GetPayloadTimelinessCommittee(ctx, st, a.Data.Slot) - if err != nil { - return err - } - idx := slices.Index(ptc, a.ValidatorIndex) - if idx == -1 { - return errInvalidValidatorIndex - } - if s.payloadAttestationCache.Seen(root, uint64(primitives.ValidatorIndex(idx))) { - return nil - } - - return s.payloadAttestationCache.Add(a, uint64(idx)) + return s.cfg.chain.ReceivePayloadAttestationMessage(ctx, a) } diff --git a/beacon-chain/sync/service.go b/beacon-chain/sync/service.go index c7cced1f5078..1696435cc7c2 100644 --- a/beacon-chain/sync/service.go +++ b/beacon-chain/sync/service.go @@ -103,6 +103,7 @@ type config struct { // This defines the interface for interacting with block chain service type blockchainService interface { blockchain.BlockReceiver + blockchain.PayloadAttestationReceiver blockchain.BlobReceiver blockchain.HeadFetcher blockchain.FinalizationFetcher