From 3bf00b0e0fa9b543292d17e2c93da423c37ab819 Mon Sep 17 00:00:00 2001 From: terence Date: Thu, 29 Aug 2024 09:34:32 -0700 Subject: [PATCH] Prysm rpc: Submit payload attestation data (#14381) --- .../receive_payload_attestation_message.go | 2 +- beacon-chain/blockchain/testing/mock.go | 83 ++++++++++--------- beacon-chain/node/node.go | 1 + beacon-chain/rpc/eth/events/BUILD.bazel | 2 +- .../rpc/prysm/v1alpha1/validator/BUILD.bazel | 1 + .../prysm/v1alpha1/validator/ptc_attester.go | 19 ++++- .../v1alpha1/validator/ptc_attester_test.go | 41 +++++++++ .../rpc/prysm/v1alpha1/validator/server.go | 73 ++++++++-------- beacon-chain/rpc/service.go | 74 +++++++++-------- consensus-types/blocks/BUILD.bazel | 2 +- 10 files changed, 180 insertions(+), 118 deletions(-) create mode 100644 beacon-chain/rpc/prysm/v1alpha1/validator/ptc_attester_test.go diff --git a/beacon-chain/blockchain/receive_payload_attestation_message.go b/beacon-chain/blockchain/receive_payload_attestation_message.go index 4aa5c6d9648a..daf00b451126 100644 --- a/beacon-chain/blockchain/receive_payload_attestation_message.go +++ b/beacon-chain/blockchain/receive_payload_attestation_message.go @@ -14,7 +14,7 @@ func (s *Service) ReceivePayloadAttestationMessage(ctx context.Context, a *eth.P return err } root := [32]byte(a.Data.BeaconBlockRoot) - st, err := s.HeadState(ctx) + st, err := s.HeadStateReadOnly(ctx) if err != nil { return err } diff --git a/beacon-chain/blockchain/testing/mock.go b/beacon-chain/blockchain/testing/mock.go index 098c4ff20e7a..8e14700f2edd 100644 --- a/beacon-chain/blockchain/testing/mock.go +++ b/beacon-chain/blockchain/testing/mock.go @@ -37,46 +37,47 @@ var ErrNilState = errors.New("nil state") // ChainService defines the mock interface for testing type ChainService struct { - NotFinalized bool - Optimistic bool - ValidAttestation bool - ValidatorsRoot [32]byte - PublicKey [fieldparams.BLSPubkeyLength]byte - FinalizedCheckPoint *ethpb.Checkpoint - CurrentJustifiedCheckPoint *ethpb.Checkpoint - PreviousJustifiedCheckPoint *ethpb.Checkpoint - Slot *primitives.Slot // Pointer because 0 is a useful value, so checking against it can be incorrect. - Balance *precompute.Balance - CanonicalRoots map[[32]byte]bool - Fork *ethpb.Fork - ETH1Data *ethpb.Eth1Data - InitSyncBlockRoots map[[32]byte]bool - DB db.Database - State state.BeaconState - Block interfaces.ReadOnlySignedBeaconBlock - ExecutionPayloadEnvelope interfaces.ROExecutionPayloadEnvelope - VerifyBlkDescendantErr error - stateNotifier statefeed.Notifier - BlocksReceived []interfaces.ReadOnlySignedBeaconBlock - SyncCommitteeIndices []primitives.CommitteeIndex - blockNotifier blockfeed.Notifier - opNotifier opfeed.Notifier - Root []byte - SyncCommitteeDomain []byte - SyncSelectionProofDomain []byte - SyncContributionProofDomain []byte - SyncCommitteePubkeys [][]byte - Genesis time.Time - ForkChoiceStore forkchoice.ForkChoicer - ReceiveBlockMockErr error - ReceiveEnvelopeMockErr error - OptimisticCheckRootReceived [32]byte - FinalizedRoots map[[32]byte]bool - OptimisticRoots map[[32]byte]bool - BlockSlot primitives.Slot - SyncingRoot [32]byte - Blobs []blocks.VerifiedROBlob - TargetRoot [32]byte + NotFinalized bool + Optimistic bool + ValidAttestation bool + ValidatorsRoot [32]byte + PublicKey [fieldparams.BLSPubkeyLength]byte + FinalizedCheckPoint *ethpb.Checkpoint + CurrentJustifiedCheckPoint *ethpb.Checkpoint + PreviousJustifiedCheckPoint *ethpb.Checkpoint + Slot *primitives.Slot // Pointer because 0 is a useful value, so checking against it can be incorrect. + Balance *precompute.Balance + CanonicalRoots map[[32]byte]bool + Fork *ethpb.Fork + ETH1Data *ethpb.Eth1Data + InitSyncBlockRoots map[[32]byte]bool + DB db.Database + State state.BeaconState + Block interfaces.ReadOnlySignedBeaconBlock + ExecutionPayloadEnvelope interfaces.ROExecutionPayloadEnvelope + VerifyBlkDescendantErr error + stateNotifier statefeed.Notifier + BlocksReceived []interfaces.ReadOnlySignedBeaconBlock + SyncCommitteeIndices []primitives.CommitteeIndex + blockNotifier blockfeed.Notifier + opNotifier opfeed.Notifier + Root []byte + SyncCommitteeDomain []byte + SyncSelectionProofDomain []byte + SyncContributionProofDomain []byte + SyncCommitteePubkeys [][]byte + Genesis time.Time + ForkChoiceStore forkchoice.ForkChoicer + ReceiveBlockMockErr error + ReceiveEnvelopeMockErr error + OptimisticCheckRootReceived [32]byte + FinalizedRoots map[[32]byte]bool + OptimisticRoots map[[32]byte]bool + BlockSlot primitives.Slot + SyncingRoot [32]byte + Blobs []blocks.VerifiedROBlob + TargetRoot [32]byte + ReceivePayloadAttestationMessageErr error } func (s *ChainService) Ancestor(ctx context.Context, root []byte, slot primitives.Slot) ([]byte, error) { @@ -642,5 +643,5 @@ func (c *ChainService) HashInForkchoice([32]byte) bool { // ReceivePayloadAttestationMessage mocks the same method in the chain service func (c *ChainService) ReceivePayloadAttestationMessage(_ context.Context, _ *ethpb.PayloadAttestationMessage) error { - return nil + return c.ReceivePayloadAttestationMessageErr } diff --git a/beacon-chain/node/node.go b/beacon-chain/node/node.go index a2bbe7401668..5c3dd814a837 100644 --- a/beacon-chain/node/node.go +++ b/beacon-chain/node/node.go @@ -999,6 +999,7 @@ func (b *BeaconNode) registerRPCService(router *mux.Router) error { FinalizationFetcher: chainService, BlockReceiver: chainService, BlobReceiver: chainService, + PayloadAttestationReceiver: chainService, AttestationReceiver: chainService, GenesisTimeFetcher: chainService, GenesisFetcher: chainService, diff --git a/beacon-chain/rpc/eth/events/BUILD.bazel b/beacon-chain/rpc/eth/events/BUILD.bazel index 3d1709e35997..b545789a20cf 100644 --- a/beacon-chain/rpc/eth/events/BUILD.bazel +++ b/beacon-chain/rpc/eth/events/BUILD.bazel @@ -20,8 +20,8 @@ go_library( "//beacon-chain/core/time:go_default_library", "//beacon-chain/core/transition:go_default_library", "//config/params:go_default_library", - "//monitoring/tracing/trace:go_default_library", "//consensus-types/primitives:go_default_library", + "//monitoring/tracing/trace:go_default_library", "//network/httputil:go_default_library", "//proto/eth/v1:go_default_library", "//proto/eth/v2:go_default_library", diff --git a/beacon-chain/rpc/prysm/v1alpha1/validator/BUILD.bazel b/beacon-chain/rpc/prysm/v1alpha1/validator/BUILD.bazel index f70d1c5fbf80..1e4707fbd6c0 100644 --- a/beacon-chain/rpc/prysm/v1alpha1/validator/BUILD.bazel +++ b/beacon-chain/rpc/prysm/v1alpha1/validator/BUILD.bazel @@ -201,6 +201,7 @@ go_test( "proposer_exits_test.go", "proposer_slashings_test.go", "proposer_sync_aggregate_test.go", + "ptc_attester_test.go", "proposer_test.go", "server_mainnet_test.go", "server_test.go", diff --git a/beacon-chain/rpc/prysm/v1alpha1/validator/ptc_attester.go b/beacon-chain/rpc/prysm/v1alpha1/validator/ptc_attester.go index b54a5e1c5c4e..2a5fd0913045 100644 --- a/beacon-chain/rpc/prysm/v1alpha1/validator/ptc_attester.go +++ b/beacon-chain/rpc/prysm/v1alpha1/validator/ptc_attester.go @@ -6,12 +6,27 @@ import ( "github.com/golang/protobuf/ptypes/empty" "github.com/pkg/errors" ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) func (vs *Server) GetPayloadAttestationData(ctx context.Context, req *ethpb.GetPayloadAttestationDataRequest) (*ethpb.PayloadAttestationData, error) { return nil, errors.New("not implemented") } -func (vs *Server) SubmitPayloadAttestation(ctx context.Context, in *ethpb.PayloadAttestationMessage) (*empty.Empty, error) { - return nil, errors.New("not implemented") +// SubmitPayloadAttestation broadcasts a payload attestation message to the network and saves the payload attestation to the cache. +// This handler does not validate the payload attestation message before broadcasting and saving it to the cache. +// The caller should be responsible for validating the message, as it assumes a trusted relationship between the caller and the server. +func (vs *Server) SubmitPayloadAttestation(ctx context.Context, a *ethpb.PayloadAttestationMessage) (*empty.Empty, error) { + // Broadcast the payload attestation message to the network. + if err := vs.P2P.Broadcast(ctx, a); err != nil { + return nil, status.Errorf(codes.Internal, "Could not broadcast payload attestation message: %v", err) + } + + // Save the payload attestation to the cache. + if err := vs.PayloadAttestationReceiver.ReceivePayloadAttestationMessage(ctx, a); err != nil { + return nil, status.Errorf(codes.Internal, "Could not save payload attestation to cache: %v", err) + } + + return &empty.Empty{}, nil } diff --git a/beacon-chain/rpc/prysm/v1alpha1/validator/ptc_attester_test.go b/beacon-chain/rpc/prysm/v1alpha1/validator/ptc_attester_test.go new file mode 100644 index 000000000000..a2abc0e68955 --- /dev/null +++ b/beacon-chain/rpc/prysm/v1alpha1/validator/ptc_attester_test.go @@ -0,0 +1,41 @@ +package validator + +import ( + "context" + "testing" + + "github.com/pkg/errors" + mock "github.com/prysmaticlabs/prysm/v5/beacon-chain/blockchain/testing" + p2ptest "github.com/prysmaticlabs/prysm/v5/beacon-chain/p2p/testing" + ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/v5/testing/require" +) + +func TestServer_SubmitPayloadAttestation(t *testing.T) { + ctx := context.Background() + t.Run("Error", func(t *testing.T) { + s := &Server{ + P2P: p2ptest.NewTestP2P(t), + PayloadAttestationReceiver: &mock.ChainService{ReceivePayloadAttestationMessageErr: errors.New("error")}, + } + _, err := s.SubmitPayloadAttestation(ctx, ðpb.PayloadAttestationMessage{ + Data: ðpb.PayloadAttestationData{ + Slot: 1, + }, + }) + require.ErrorContains(t, "error", err) + }) + + t.Run("Happy case", func(t *testing.T) { + s := &Server{ + P2P: p2ptest.NewTestP2P(t), + PayloadAttestationReceiver: &mock.ChainService{}, + } + _, err := s.SubmitPayloadAttestation(ctx, ðpb.PayloadAttestationMessage{ + Data: ðpb.PayloadAttestationData{ + Slot: 1, + }, + }) + require.NoError(t, err) + }) +} diff --git a/beacon-chain/rpc/prysm/v1alpha1/validator/server.go b/beacon-chain/rpc/prysm/v1alpha1/validator/server.go index 5dc6190151f6..a9ef3bcc7104 100644 --- a/beacon-chain/rpc/prysm/v1alpha1/validator/server.go +++ b/beacon-chain/rpc/prysm/v1alpha1/validator/server.go @@ -43,42 +43,43 @@ import ( // and committees in which particular validators need to perform their responsibilities, // and more. type Server struct { - Ctx context.Context - PayloadIDCache *cache.PayloadIDCache - TrackedValidatorsCache *cache.TrackedValidatorsCache - HeadFetcher blockchain.HeadFetcher - ForkFetcher blockchain.ForkFetcher - ForkchoiceFetcher blockchain.ForkchoiceFetcher - GenesisFetcher blockchain.GenesisFetcher - FinalizationFetcher blockchain.FinalizationFetcher - TimeFetcher blockchain.TimeFetcher - BlockFetcher execution.POWBlockFetcher - DepositFetcher cache.DepositFetcher - ChainStartFetcher execution.ChainStartFetcher - Eth1InfoFetcher execution.ChainInfoFetcher - OptimisticModeFetcher blockchain.OptimisticModeFetcher - SyncChecker sync.Checker - StateNotifier statefeed.Notifier - BlockNotifier blockfeed.Notifier - P2P p2p.Broadcaster - AttPool attestations.Pool - SlashingsPool slashings.PoolManager - ExitPool voluntaryexits.PoolManager - SyncCommitteePool synccommittee.Pool - BlockReceiver blockchain.BlockReceiver - BlobReceiver blockchain.BlobReceiver - MockEth1Votes bool - Eth1BlockFetcher execution.POWBlockFetcher - PendingDepositsFetcher depositsnapshot.PendingDepositsFetcher - OperationNotifier opfeed.Notifier - StateGen stategen.StateManager - ReplayerBuilder stategen.ReplayerBuilder - BeaconDB db.HeadAccessDatabase - ExecutionEngineCaller execution.EngineCaller - BlockBuilder builder.BlockBuilder - BLSChangesPool blstoexec.PoolManager - ClockWaiter startup.ClockWaiter - CoreService *core.Service + Ctx context.Context + PayloadIDCache *cache.PayloadIDCache + TrackedValidatorsCache *cache.TrackedValidatorsCache + HeadFetcher blockchain.HeadFetcher + ForkFetcher blockchain.ForkFetcher + ForkchoiceFetcher blockchain.ForkchoiceFetcher + GenesisFetcher blockchain.GenesisFetcher + FinalizationFetcher blockchain.FinalizationFetcher + TimeFetcher blockchain.TimeFetcher + BlockFetcher execution.POWBlockFetcher + DepositFetcher cache.DepositFetcher + ChainStartFetcher execution.ChainStartFetcher + Eth1InfoFetcher execution.ChainInfoFetcher + OptimisticModeFetcher blockchain.OptimisticModeFetcher + SyncChecker sync.Checker + StateNotifier statefeed.Notifier + BlockNotifier blockfeed.Notifier + P2P p2p.Broadcaster + AttPool attestations.Pool + SlashingsPool slashings.PoolManager + ExitPool voluntaryexits.PoolManager + SyncCommitteePool synccommittee.Pool + BlockReceiver blockchain.BlockReceiver + BlobReceiver blockchain.BlobReceiver + PayloadAttestationReceiver blockchain.PayloadAttestationReceiver + MockEth1Votes bool + Eth1BlockFetcher execution.POWBlockFetcher + PendingDepositsFetcher depositsnapshot.PendingDepositsFetcher + OperationNotifier opfeed.Notifier + StateGen stategen.StateManager + ReplayerBuilder stategen.ReplayerBuilder + BeaconDB db.HeadAccessDatabase + ExecutionEngineCaller execution.EngineCaller + BlockBuilder builder.BlockBuilder + BLSChangesPool blstoexec.PoolManager + ClockWaiter startup.ClockWaiter + CoreService *core.Service } // WaitForActivation checks if a validator public key exists in the active validator registry of the current diff --git a/beacon-chain/rpc/service.go b/beacon-chain/rpc/service.go index 335b60e0ad38..b7dbae5d61ed 100644 --- a/beacon-chain/rpc/service.go +++ b/beacon-chain/rpc/service.go @@ -107,6 +107,7 @@ type Config struct { AttestationReceiver blockchain.AttestationReceiver BlockReceiver blockchain.BlockReceiver BlobReceiver blockchain.BlobReceiver + PayloadAttestationReceiver blockchain.PayloadAttestationReceiver ExecutionChainService execution.Chain ChainStartFetcher execution.ChainStartFetcher ExecutionChainInfoFetcher execution.ChainInfoFetcher @@ -230,42 +231,43 @@ func NewService(ctx context.Context, cfg *Config) *Service { OptimisticModeFetcher: s.cfg.OptimisticModeFetcher, } validatorServer := &validatorv1alpha1.Server{ - Ctx: s.ctx, - AttPool: s.cfg.AttestationsPool, - ExitPool: s.cfg.ExitPool, - HeadFetcher: s.cfg.HeadFetcher, - ForkFetcher: s.cfg.ForkFetcher, - ForkchoiceFetcher: s.cfg.ForkchoiceFetcher, - GenesisFetcher: s.cfg.GenesisFetcher, - FinalizationFetcher: s.cfg.FinalizationFetcher, - TimeFetcher: s.cfg.GenesisTimeFetcher, - BlockFetcher: s.cfg.ExecutionChainService, - DepositFetcher: s.cfg.DepositFetcher, - ChainStartFetcher: s.cfg.ChainStartFetcher, - Eth1InfoFetcher: s.cfg.ExecutionChainService, - OptimisticModeFetcher: s.cfg.OptimisticModeFetcher, - SyncChecker: s.cfg.SyncService, - StateNotifier: s.cfg.StateNotifier, - BlockNotifier: s.cfg.BlockNotifier, - OperationNotifier: s.cfg.OperationNotifier, - P2P: s.cfg.Broadcaster, - BlockReceiver: s.cfg.BlockReceiver, - BlobReceiver: s.cfg.BlobReceiver, - MockEth1Votes: s.cfg.MockEth1Votes, - Eth1BlockFetcher: s.cfg.ExecutionChainService, - PendingDepositsFetcher: s.cfg.PendingDepositFetcher, - SlashingsPool: s.cfg.SlashingsPool, - StateGen: s.cfg.StateGen, - SyncCommitteePool: s.cfg.SyncCommitteeObjectPool, - ReplayerBuilder: ch, - ExecutionEngineCaller: s.cfg.ExecutionEngineCaller, - BeaconDB: s.cfg.BeaconDB, - BlockBuilder: s.cfg.BlockBuilder, - BLSChangesPool: s.cfg.BLSChangesPool, - ClockWaiter: s.cfg.ClockWaiter, - CoreService: coreService, - TrackedValidatorsCache: s.cfg.TrackedValidatorsCache, - PayloadIDCache: s.cfg.PayloadIDCache, + Ctx: s.ctx, + AttPool: s.cfg.AttestationsPool, + ExitPool: s.cfg.ExitPool, + HeadFetcher: s.cfg.HeadFetcher, + ForkFetcher: s.cfg.ForkFetcher, + ForkchoiceFetcher: s.cfg.ForkchoiceFetcher, + GenesisFetcher: s.cfg.GenesisFetcher, + FinalizationFetcher: s.cfg.FinalizationFetcher, + TimeFetcher: s.cfg.GenesisTimeFetcher, + BlockFetcher: s.cfg.ExecutionChainService, + DepositFetcher: s.cfg.DepositFetcher, + ChainStartFetcher: s.cfg.ChainStartFetcher, + Eth1InfoFetcher: s.cfg.ExecutionChainService, + OptimisticModeFetcher: s.cfg.OptimisticModeFetcher, + SyncChecker: s.cfg.SyncService, + StateNotifier: s.cfg.StateNotifier, + BlockNotifier: s.cfg.BlockNotifier, + OperationNotifier: s.cfg.OperationNotifier, + P2P: s.cfg.Broadcaster, + BlockReceiver: s.cfg.BlockReceiver, + BlobReceiver: s.cfg.BlobReceiver, + PayloadAttestationReceiver: s.cfg.PayloadAttestationReceiver, + MockEth1Votes: s.cfg.MockEth1Votes, + Eth1BlockFetcher: s.cfg.ExecutionChainService, + PendingDepositsFetcher: s.cfg.PendingDepositFetcher, + SlashingsPool: s.cfg.SlashingsPool, + StateGen: s.cfg.StateGen, + SyncCommitteePool: s.cfg.SyncCommitteeObjectPool, + ReplayerBuilder: ch, + ExecutionEngineCaller: s.cfg.ExecutionEngineCaller, + BeaconDB: s.cfg.BeaconDB, + BlockBuilder: s.cfg.BlockBuilder, + BLSChangesPool: s.cfg.BLSChangesPool, + ClockWaiter: s.cfg.ClockWaiter, + CoreService: coreService, + TrackedValidatorsCache: s.cfg.TrackedValidatorsCache, + PayloadIDCache: s.cfg.PayloadIDCache, } s.validatorServer = validatorServer nodeServer := &nodev1alpha1.Server{ diff --git a/consensus-types/blocks/BUILD.bazel b/consensus-types/blocks/BUILD.bazel index 2b946c6f4148..a1015bcc2b47 100644 --- a/consensus-types/blocks/BUILD.bazel +++ b/consensus-types/blocks/BUILD.bazel @@ -22,8 +22,8 @@ go_library( importpath = "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks", visibility = ["//visibility:public"], deps = [ - "//beacon-chain/state/stateutil:go_default_library", "//beacon-chain/core/signing:go_default_library", + "//beacon-chain/state/stateutil:go_default_library", "//config/fieldparams:go_default_library", "//config/params:go_default_library", "//consensus-types:go_default_library",