diff --git a/api/server/structs/block.go b/api/server/structs/block.go index 5393088aa03c..19ef7bde7f5b 100644 --- a/api/server/structs/block.go +++ b/api/server/structs/block.go @@ -540,6 +540,12 @@ type PayloadAttestation struct { Signature string `json:"signature"` } +type PayloadAttestationMessage struct { + ValidatorIndex string `json:"validator_index"` + Data *PayloadAttestationData `json:"data"` + Signature string `json:"signature"` +} + type BeaconBlockBodyGloas struct { RandaoReveal string `json:"randao_reveal"` Eth1Data *Eth1Data `json:"eth1_data"` diff --git a/api/server/structs/conversions_block.go b/api/server/structs/conversions_block.go index 1effc2b0b8fc..5eb696357849 100644 --- a/api/server/structs/conversions_block.go +++ b/api/server/structs/conversions_block.go @@ -2971,6 +2971,14 @@ func PayloadAttestationDataFromConsensus(d *eth.PayloadAttestationData) *Payload } } +func PayloadAttestationMessageFromConsensus(m *eth.PayloadAttestationMessage) *PayloadAttestationMessage { + return &PayloadAttestationMessage{ + ValidatorIndex: fmt.Sprintf("%d", m.ValidatorIndex), + Data: PayloadAttestationDataFromConsensus(m.Data), + Signature: hexutil.Encode(m.Signature), + } +} + func (b *SignedBeaconBlockGloas) ToConsensus() (*eth.SignedBeaconBlockGloas, error) { if b == nil { return nil, errNilValue diff --git a/api/server/structs/endpoints_events.go b/api/server/structs/endpoints_events.go index 2ff2bb8a6098..1fd5572447ea 100644 --- a/api/server/structs/endpoints_events.go +++ b/api/server/structs/endpoints_events.go @@ -112,3 +112,8 @@ type LightClientOptimisticUpdateEvent struct { Version string `json:"version"` Data *LightClientOptimisticUpdate `json:"data"` } + +type ExecutionPayloadAvailableEvent struct { + Slot string `json:"slot"` + BlockRoot string `json:"block_root"` +} diff --git a/beacon-chain/core/feed/operation/events.go b/beacon-chain/core/feed/operation/events.go index f97173b2af56..d782a8317ec4 100644 --- a/beacon-chain/core/feed/operation/events.go +++ b/beacon-chain/core/feed/operation/events.go @@ -46,6 +46,14 @@ const ( // DataColumnReceived is sent after a data column has been seen after gossip validation rules. DataColumnReceived = 12 + + // ExecutionPayloadBidReceived is sent after a signed execution payload bid is received from gossip or API + // that passes gossip validation on the execution_payload_bid topic. + ExecutionPayloadBidReceived = 13 + + // PayloadAttestationMessageReceived is sent after a payload attestation message is received + // that passes validation rules of the payload_attestation_message topic. + PayloadAttestationMessageReceived = 14 ) // UnAggregatedAttReceivedData is the data sent with UnaggregatedAttReceived events. @@ -114,3 +122,13 @@ type DataColumnReceivedData struct { BlockRoot [32]byte KzgCommitments [][]byte } + +// ExecutionPayloadBidReceivedData is the data sent with ExecutionPayloadBidReceived events. +type ExecutionPayloadBidReceivedData struct { + SignedBid *ethpb.SignedExecutionPayloadBid +} + +// PayloadAttestationMessageReceivedData is the data sent with PayloadAttestationMessageReceived events. +type PayloadAttestationMessageReceivedData struct { + PayloadAttestationMessage *ethpb.PayloadAttestationMessage +} diff --git a/beacon-chain/core/feed/state/events.go b/beacon-chain/core/feed/state/events.go index 425c00318e31..7278a6f46250 100644 --- a/beacon-chain/core/feed/state/events.go +++ b/beacon-chain/core/feed/state/events.go @@ -33,6 +33,9 @@ const ( LightClientOptimisticUpdate // PayloadAttributes events are fired upon a missed slot or new head. PayloadAttributes + // ExecutionPayloadAvailable is sent when the node has verified that the execution payload + // and blobs for a block are available and ready for payload attestation. + ExecutionPayloadAvailable ) // BlockProcessedData is the data sent with BlockProcessed events. @@ -72,3 +75,11 @@ type InitializedData struct { // GenesisValidatorsRoot represents state.validators.HashTreeRoot(). GenesisValidatorsRoot []byte } + +// ExecutionPayloadAvailableData is the data sent with ExecutionPayloadAvailable events. +type ExecutionPayloadAvailableData struct { + // Slot is the slot of the block whose execution payload became available. + Slot primitives.Slot + // BlockRoot is the root of the block whose execution payload became available. + BlockRoot [32]byte +} diff --git a/beacon-chain/rpc/eth/events/events.go b/beacon-chain/rpc/eth/events/events.go index 92fd0f91cbfe..92429653f885 100644 --- a/beacon-chain/rpc/eth/events/events.go +++ b/beacon-chain/rpc/eth/events/events.go @@ -74,6 +74,12 @@ const ( LightClientOptimisticUpdateTopic = "light_client_optimistic_update" // DataColumnTopic represents a data column sidecar event topic DataColumnTopic = "data_column_sidecar" + // ExecutionPayloadAvailableTopic represents an event indicating execution payload and blobs are available. + ExecutionPayloadAvailableTopic = "execution_payload_available" + // ExecutionPayloadBidTopic represents an event for a signed execution payload bid passing gossip validation. + ExecutionPayloadBidTopic = "execution_payload_bid" + // PayloadAttestationMessageTopic represents an event for a payload attestation message passing validation. + PayloadAttestationMessageTopic = "payload_attestation_message" ) var ( @@ -108,6 +114,8 @@ var opsFeedEventTopics = map[feed.EventType]string{ operation.ProposerSlashingReceived: ProposerSlashingTopic, operation.BlockGossipReceived: BlockGossipTopic, operation.DataColumnReceived: DataColumnTopic, + operation.ExecutionPayloadBidReceived: ExecutionPayloadBidTopic, + operation.PayloadAttestationMessageReceived: PayloadAttestationMessageTopic, } var stateFeedEventTopics = map[feed.EventType]string{ @@ -118,6 +126,7 @@ var stateFeedEventTopics = map[feed.EventType]string{ statefeed.Reorg: ChainReorgTopic, statefeed.BlockProcessed: BlockTopic, statefeed.PayloadAttributes: PayloadAttributesTopic, + statefeed.ExecutionPayloadAvailable: ExecutionPayloadAvailableTopic, } var topicsForStateFeed = topicsForFeed(stateFeedEventTopics) @@ -466,6 +475,12 @@ func topicForEvent(event *feed.Event) string { return PayloadAttributesTopic case *operation.DataColumnReceivedData: return DataColumnTopic + case *operation.ExecutionPayloadBidReceivedData: + return ExecutionPayloadBidTopic + case *operation.PayloadAttestationMessageReceivedData: + return PayloadAttestationMessageTopic + case *statefeed.ExecutionPayloadAvailableData: + return ExecutionPayloadAvailableTopic default: return InvalidTopic } @@ -638,6 +653,21 @@ func (s *Server) lazyReaderForEvent(ctx context.Context, event *feed.Event, topi } return jsonMarshalReader(eventName, blk) }, nil + case *statefeed.ExecutionPayloadAvailableData: + return func() io.Reader { + return jsonMarshalReader(eventName, &structs.ExecutionPayloadAvailableEvent{ + Slot: fmt.Sprintf("%d", v.Slot), + BlockRoot: hexutil.Encode(v.BlockRoot[:]), + }) + }, nil + case *operation.ExecutionPayloadBidReceivedData: + return func() io.Reader { + return jsonMarshalReader(eventName, structs.SignedExecutionPayloadBidFromConsensus(v.SignedBid)) + }, nil + case *operation.PayloadAttestationMessageReceivedData: + return func() io.Reader { + return jsonMarshalReader(eventName, structs.PayloadAttestationMessageFromConsensus(v.PayloadAttestationMessage)) + }, nil default: return nil, errors.Wrapf(errUnhandledEventData, "event data type %T unsupported", v) } diff --git a/beacon-chain/rpc/eth/events/events_test.go b/beacon-chain/rpc/eth/events/events_test.go index 284c33190540..9a8069756f22 100644 --- a/beacon-chain/rpc/eth/events/events_test.go +++ b/beacon-chain/rpc/eth/events/events_test.go @@ -123,6 +123,8 @@ func operationEventsFixtures(t *testing.T) (*topicRequest, []*feed.Event) { ProposerSlashingTopic, BlockGossipTopic, DataColumnTopic, + ExecutionPayloadBidTopic, + PayloadAttestationMessageTopic, }) require.NoError(t, err) ro, err := blocks.NewROBlob(util.HydrateBlobSidecar(ð.BlobSidecar{})) @@ -312,6 +314,42 @@ func operationEventsFixtures(t *testing.T) (*topicRequest, []*feed.Event) { KzgCommitments: [][]byte{{'a'}, {'b'}, {'c'}}, }, }, + { + Type: operation.ExecutionPayloadBidReceived, + Data: &operation.ExecutionPayloadBidReceivedData{ + SignedBid: ð.SignedExecutionPayloadBid{ + Message: ð.ExecutionPayloadBid{ + ParentBlockHash: make([]byte, 32), + ParentBlockRoot: make([]byte, 32), + BlockHash: make([]byte, 32), + PrevRandao: make([]byte, 32), + FeeRecipient: make([]byte, 20), + GasLimit: 30000000, + BuilderIndex: 42, + Slot: 10, + Value: 1000000000, + ExecutionPayment: 0, + BlobKzgCommitmentsRoot: make([]byte, 32), + }, + Signature: make([]byte, 96), + }, + }, + }, + { + Type: operation.PayloadAttestationMessageReceived, + Data: &operation.PayloadAttestationMessageReceivedData{ + PayloadAttestationMessage: ð.PayloadAttestationMessage{ + ValidatorIndex: 123, + Data: ð.PayloadAttestationData{ + BeaconBlockRoot: make([]byte, 32), + Slot: 10, + PayloadPresent: true, + BlobDataAvailable: true, + }, + Signature: make([]byte, 96), + }, + }, + }, } } @@ -393,6 +431,7 @@ func TestStreamEvents_OperationsEvents(t *testing.T) { FinalizedCheckpointTopic, ChainReorgTopic, BlockTopic, + ExecutionPayloadAvailableTopic, }) require.NoError(t, err) request := topics.testHttpRequest(testSync.ctx, t) @@ -445,6 +484,13 @@ func TestStreamEvents_OperationsEvents(t *testing.T) { ExecutionOptimistic: false, }, }, + { + Type: statefeed.ExecutionPayloadAvailable, + Data: &statefeed.ExecutionPayloadAvailableData{ + Slot: 10, + BlockRoot: [32]byte{0x9a}, + }, + }, } go func() { @@ -721,7 +767,7 @@ func TestStuckReaderScenarios(t *testing.T) { func wedgedWriterTestCase(t *testing.T, queueDepth func([]*feed.Event) int) { topics, events := operationEventsFixtures(t) - require.Equal(t, 12, len(events)) + require.Equal(t, 14, len(events)) // set eventFeedDepth to a number lower than the events we intend to send to force the server to drop the reader. stn := mockChain.NewEventFeedWrapper() diff --git a/changelog/james-prysm_gloas-events.md b/changelog/james-prysm_gloas-events.md new file mode 100644 index 000000000000..c525979700fc --- /dev/null +++ b/changelog/james-prysm_gloas-events.md @@ -0,0 +1,3 @@ +### Added + +- the following events available at gloas `execution_payload_available`, `execution_payload_bid`,and `payload_attestation_message` \ No newline at end of file