Skip to content

Commit

Permalink
Prysm rpc: Get payload attestation data
Browse files Browse the repository at this point in the history
  • Loading branch information
terencechain committed Sep 9, 2024
1 parent b2f47ca commit 019fb8f
Show file tree
Hide file tree
Showing 14 changed files with 145 additions and 48 deletions.
9 changes: 2 additions & 7 deletions beacon-chain/blockchain/chain_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,15 @@ type ForkchoiceFetcher interface {
GetProposerHead() [32]byte
SetForkChoiceGenesisTime(uint64)
UpdateHead(context.Context, primitives.Slot)
HighestReceivedBlockSlot() primitives.Slot
HighestReceivedBlockSlotRoot() (primitives.Slot, [32]byte)
ReceivedBlocksLastEpoch() (uint64, error)
InsertNode(context.Context, state.BeaconState, [32]byte) error
ForkChoiceDump(context.Context) (*forkchoice.Dump, error)
NewSlot(context.Context, primitives.Slot) error
ProposerBoost() [32]byte
RecentBlockSlot(root [32]byte) (primitives.Slot, error)
IsCanonical(ctx context.Context, blockRoot [32]byte) (bool, error)
GetPTCVote(root [32]byte) primitives.PTCStatus
}

// TimeFetcher retrieves the Ethereum consensus data that's related to time.
Expand Down Expand Up @@ -544,12 +545,6 @@ func (s *Service) recoverStateSummary(ctx context.Context, blockRoot [32]byte) (
return nil, errBlockDoesNotExist
}

// PayloadBeingSynced returns whether the payload for the block with the given
// root is currently being synced and what is the withheld status in the payload
func (s *Service) PayloadBeingSynced(root [32]byte) (primitives.PTCStatus, bool) {
return s.payloadBeingSynced.isSyncing(root)
}

// BlockBeingSynced returns whether the block with the given root is currently being synced
func (s *Service) BlockBeingSynced(root [32]byte) bool {
return s.blockBeingSynced.isSyncing(root)
Expand Down
6 changes: 3 additions & 3 deletions beacon-chain/blockchain/chain_info_forkchoice.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ func (s *Service) SetForkChoiceGenesisTime(timestamp uint64) {
s.cfg.ForkChoiceStore.SetGenesisTime(timestamp)
}

// HighestReceivedBlockSlot returns the corresponding value from forkchoice
func (s *Service) HighestReceivedBlockSlot() primitives.Slot {
// HighestReceivedBlockSlotRoot returns the corresponding value from forkchoice
func (s *Service) HighestReceivedBlockSlotRoot() (primitives.Slot, [32]byte) {
s.cfg.ForkChoiceStore.RLock()
defer s.cfg.ForkChoiceStore.RUnlock()
return s.cfg.ForkChoiceStore.HighestReceivedBlockSlot()
return s.cfg.ForkChoiceStore.HighestReceivedBlockSlotRoot()
}

// ReceivedBlocksLastEpoch returns the corresponding value from forkchoice
Expand Down
10 changes: 5 additions & 5 deletions beacon-chain/blockchain/receive_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,17 @@ type PayloadAttestationReceiver interface {
ReceivePayloadAttestationMessage(ctx context.Context, a *ethpb.PayloadAttestationMessage) error
}

// ExecutionPayloadReceiver interface defines the methods of chain service for receiving and processing new execution payload envelope.
type ExecutionPayloadReceiver interface {
ReceiveExecutionPayloadEnvelope(ctx context.Context, envelope interfaces.ROExecutionPayloadEnvelope, _ das.AvailabilityStore) error
}

// BlobReceiver interface defines the methods of chain service for receiving new
// blobs
type BlobReceiver interface {
ReceiveBlob(context.Context, blocks.VerifiedROBlob) error
}

// ExecutionPayloadReceiver interface defines the methods of chain service for receiving `ROExecutionPayloadEnvelope`.
type ExecutionPayloadReceiver interface {
ReceiveExecutionPayloadEnvelope(ctx context.Context, envelope interfaces.ROExecutionPayloadEnvelope, _ das.AvailabilityStore) error
}

// SlashingReceiver interface defines the methods of chain service for receiving validated slashing over the wire.
type SlashingReceiver interface {
ReceiveAttesterSlashing(ctx context.Context, slashing ethpb.AttSlashing)
Expand Down
16 changes: 12 additions & 4 deletions beacon-chain/blockchain/testing/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ type ChainService struct {
NotFinalized bool
Optimistic bool
ValidAttestation bool
HasPayload bool
ValidatorsRoot [32]byte
PublicKey [fieldparams.BLSPubkeyLength]byte
FinalizedCheckPoint *ethpb.Checkpoint
Expand Down Expand Up @@ -77,6 +78,9 @@ type ChainService struct {
SyncingRoot [32]byte
Blobs []blocks.VerifiedROBlob
TargetRoot [32]byte
HighestReceivedSlot primitives.Slot
HighestReceivedRoot [32]byte
PayloadStatus primitives.PTCStatus
ReceivePayloadAttestationMessageErr error
}

Expand Down Expand Up @@ -570,12 +574,12 @@ func (s *ChainService) ReceivedBlocksLastEpoch() (uint64, error) {
return 0, nil
}

// HighestReceivedBlockSlot mocks the same method in the chain service
func (s *ChainService) HighestReceivedBlockSlot() primitives.Slot {
// HighestReceivedBlockSlotRoot mocks the same method in the chain service
func (s *ChainService) HighestReceivedBlockSlotRoot() (primitives.Slot, [32]byte) {
if s.ForkChoiceStore != nil {
return s.ForkChoiceStore.HighestReceivedBlockSlot()
return s.ForkChoiceStore.HighestReceivedBlockSlotRoot()
}
return 0
return s.HighestReceivedSlot, s.HighestReceivedRoot
}

// InsertNode mocks the same method in the chain service
Expand Down Expand Up @@ -645,3 +649,7 @@ func (c *ChainService) HashInForkchoice([32]byte) bool {
func (c *ChainService) ReceivePayloadAttestationMessage(_ context.Context, _ *ethpb.PayloadAttestationMessage) error {
return c.ReceivePayloadAttestationMessageErr
}

func (c *ChainService) GetPTCVote(root [32]byte) primitives.PTCStatus {
return c.PayloadStatus
}
8 changes: 4 additions & 4 deletions beacon-chain/forkchoice/doubly-linked-tree/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,12 +249,12 @@ func (s *Store) tips() ([][32]byte, []primitives.Slot) {
return roots, slots
}

// HighestReceivedBlockSlot returns the highest slot received by the forkchoice
func (f *ForkChoice) HighestReceivedBlockSlot() primitives.Slot {
// HighestReceivedBlockSlotRoot returns the highest slot and root received by the forkchoice
func (f *ForkChoice) HighestReceivedBlockSlotRoot() (primitives.Slot, [32]byte) {
if f.store.highestReceivedNode == nil {
return 0
return 0, [32]byte{}
}
return f.store.highestReceivedNode.slot
return f.store.highestReceivedNode.slot, f.store.highestReceivedNode.root
}

// HighestReceivedBlockSlotDelay returns the number of slots that the highest
Expand Down
27 changes: 18 additions & 9 deletions beacon-chain/forkchoice/doubly-linked-tree/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,8 @@ func TestForkChoice_ReceivedBlocksLastEpoch(t *testing.T) {
count, err := f.ReceivedBlocksLastEpoch()
require.NoError(t, err)
require.Equal(t, uint64(1), count)
require.Equal(t, primitives.Slot(1), f.HighestReceivedBlockSlot())
slot, _ := f.HighestReceivedBlockSlotRoot()
require.Equal(t, primitives.Slot(1), slot)
require.Equal(t, primitives.Slot(0), f.HighestReceivedBlockDelay())

// 64
Expand All @@ -343,7 +344,8 @@ func TestForkChoice_ReceivedBlocksLastEpoch(t *testing.T) {
count, err = f.ReceivedBlocksLastEpoch()
require.NoError(t, err)
require.Equal(t, uint64(1), count)
require.Equal(t, primitives.Slot(64), f.HighestReceivedBlockSlot())
slot, _ = f.HighestReceivedBlockSlotRoot()
require.Equal(t, primitives.Slot(64), slot)
require.Equal(t, primitives.Slot(0), f.HighestReceivedBlockDelay())

// 64 65
Expand All @@ -354,7 +356,8 @@ func TestForkChoice_ReceivedBlocksLastEpoch(t *testing.T) {
count, err = f.ReceivedBlocksLastEpoch()
require.NoError(t, err)
require.Equal(t, uint64(2), count)
require.Equal(t, primitives.Slot(65), f.HighestReceivedBlockSlot())
slot, _ = f.HighestReceivedBlockSlotRoot()
require.Equal(t, primitives.Slot(65), slot)
require.Equal(t, primitives.Slot(1), f.HighestReceivedBlockDelay())

// 64 65 66
Expand All @@ -365,7 +368,8 @@ func TestForkChoice_ReceivedBlocksLastEpoch(t *testing.T) {
count, err = f.ReceivedBlocksLastEpoch()
require.NoError(t, err)
require.Equal(t, uint64(3), count)
require.Equal(t, primitives.Slot(66), f.HighestReceivedBlockSlot())
slot, _ = f.HighestReceivedBlockSlotRoot()
require.Equal(t, primitives.Slot(66), slot)

// 64 65 66
// 98
Expand All @@ -376,7 +380,8 @@ func TestForkChoice_ReceivedBlocksLastEpoch(t *testing.T) {
count, err = f.ReceivedBlocksLastEpoch()
require.NoError(t, err)
require.Equal(t, uint64(1), count)
require.Equal(t, primitives.Slot(98), f.HighestReceivedBlockSlot())
slot, _ = f.HighestReceivedBlockSlotRoot()
require.Equal(t, primitives.Slot(98), slot)

// 64 65 66
// 98
Expand All @@ -388,7 +393,8 @@ func TestForkChoice_ReceivedBlocksLastEpoch(t *testing.T) {
count, err = f.ReceivedBlocksLastEpoch()
require.NoError(t, err)
require.Equal(t, uint64(1), count)
require.Equal(t, primitives.Slot(132), f.HighestReceivedBlockSlot())
slot, _ = f.HighestReceivedBlockSlotRoot()
require.Equal(t, primitives.Slot(132), slot)

// 64 65 66
// 98
Expand All @@ -401,7 +407,8 @@ func TestForkChoice_ReceivedBlocksLastEpoch(t *testing.T) {
count, err = f.ReceivedBlocksLastEpoch()
require.NoError(t, err)
require.Equal(t, uint64(1), count)
require.Equal(t, primitives.Slot(132), f.HighestReceivedBlockSlot())
slot, _ = f.HighestReceivedBlockSlotRoot()
require.Equal(t, primitives.Slot(132), slot)

// 64 65 66
// 98
Expand All @@ -414,7 +421,8 @@ func TestForkChoice_ReceivedBlocksLastEpoch(t *testing.T) {
count, err = f.ReceivedBlocksLastEpoch()
require.NoError(t, err)
require.Equal(t, uint64(1), count)
require.Equal(t, primitives.Slot(132), f.HighestReceivedBlockSlot())
slot, _ = f.HighestReceivedBlockSlotRoot()
require.Equal(t, primitives.Slot(132), slot)

// 64 65 66
// 98
Expand All @@ -427,7 +435,8 @@ func TestForkChoice_ReceivedBlocksLastEpoch(t *testing.T) {
count, err = f.ReceivedBlocksLastEpoch()
require.NoError(t, err)
require.Equal(t, uint64(2), count)
require.Equal(t, primitives.Slot(132), f.HighestReceivedBlockSlot())
slot, _ = f.HighestReceivedBlockSlotRoot()
require.Equal(t, primitives.Slot(132), slot)

s.genesisTime = uint64(time.Now().Add(time.Duration(-134*int64(params.BeaconConfig().SecondsPerSlot)) * time.Second).Unix())
count, err = f.ReceivedBlocksLastEpoch()
Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/forkchoice/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ type FastGetter interface {
FinalizedPayloadBlockHash() [32]byte
HasNode([32]byte) bool
HasHash([32]byte) bool
HighestReceivedBlockSlot() primitives.Slot
HighestReceivedBlockSlotRoot() (primitives.Slot, [32]byte)
HighestReceivedBlockDelay() primitives.Slot
IsCanonical(root [32]byte) bool
IsOptimistic(root [32]byte) (bool, error)
Expand Down
6 changes: 3 additions & 3 deletions beacon-chain/forkchoice/ro.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,11 @@ func (ro *ROForkChoice) NodeCount() int {
return ro.getter.NodeCount()
}

// HighestReceivedBlockSlot delegates to the underlying forkchoice call, under a lock.
func (ro *ROForkChoice) HighestReceivedBlockSlot() primitives.Slot {
// HighestReceivedBlockSlotRoot delegates to the underlying forkchoice call, under a lock.
func (ro *ROForkChoice) HighestReceivedBlockSlotRoot() (primitives.Slot, [32]byte) {
ro.l.RLock()
defer ro.l.RUnlock()
return ro.getter.HighestReceivedBlockSlot()
return ro.getter.HighestReceivedBlockSlotRoot()
}

// HighestReceivedBlockDelay delegates to the underlying forkchoice call, under a lock.
Expand Down
14 changes: 7 additions & 7 deletions beacon-chain/forkchoice/ro_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const (
justifiedPayloadBlockHashCalled
unrealizedJustifiedPayloadBlockHashCalled
nodeCountCalled
highestReceivedBlockSlotCalled
highestReceivedBlockSlotRootCalled
highestReceivedBlockDelayCalled
receivedBlocksLastEpochCalled
weightCalled
Expand Down Expand Up @@ -113,9 +113,9 @@ func TestROLocking(t *testing.T) {
cb: func(g FastGetter) { g.NodeCount() },
},
{
name: "highestReceivedBlockSlotCalled",
call: highestReceivedBlockSlotCalled,
cb: func(g FastGetter) { g.HighestReceivedBlockSlot() },
name: "highestReceivedBlockSlotRootCalled",
call: highestReceivedBlockSlotRootCalled,
cb: func(g FastGetter) { g.HighestReceivedBlockSlotRoot() },
},
{
name: "highestReceivedBlockDelayCalled",
Expand Down Expand Up @@ -254,9 +254,9 @@ func (ro *mockROForkchoice) NodeCount() int {
return 0
}

func (ro *mockROForkchoice) HighestReceivedBlockSlot() primitives.Slot {
ro.calls = append(ro.calls, highestReceivedBlockSlotCalled)
return 0
func (ro *mockROForkchoice) HighestReceivedBlockSlotRoot() (primitives.Slot, [32]byte) {
ro.calls = append(ro.calls, highestReceivedBlockSlotRootCalled)
return 0, [32]byte{}
}

func (ro *mockROForkchoice) HighestReceivedBlockDelay() primitives.Slot {
Expand Down
3 changes: 2 additions & 1 deletion beacon-chain/rpc/eth/beacon/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -1024,7 +1024,8 @@ func (s *Server) validateConsensus(ctx context.Context, blk interfaces.ReadOnlyS
}

func (s *Server) validateEquivocation(blk interfaces.ReadOnlyBeaconBlock) error {
if s.ForkchoiceFetcher.HighestReceivedBlockSlot() == blk.Slot() {
slot, _ := s.ForkchoiceFetcher.HighestReceivedBlockSlotRoot()
if slot == blk.Slot() {
return errors.Wrapf(errEquivocatedBlock, "block for slot %d already exists in fork choice", blk.Slot())
}
return nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func (vs *Server) circuitBreakBuilder(s primitives.Slot) (bool, error) {
}

// Circuit breaker is active if the missing consecutive slots greater than `MaxBuilderConsecutiveMissedSlots`.
highestReceivedSlot := vs.ForkchoiceFetcher.HighestReceivedBlockSlot()
highestReceivedSlot, _ := vs.ForkchoiceFetcher.HighestReceivedBlockSlotRoot()
maxConsecutiveSkipSlotsAllowed := params.BeaconConfig().MaxBuilderConsecutiveMissedSlots
diff, err := s.SafeSubSlot(highestReceivedSlot)
if err != nil {
Expand Down
22 changes: 20 additions & 2 deletions beacon-chain/rpc/prysm/v1alpha1/validator/ptc_attester.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,32 @@ import (
"context"

"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"
)

// GetPayloadAttestationData returns the payload attestation data for a given slot.
// The request slot must be the current slot and there must exist a block from the current slot or the request will fail.
func (vs *Server) GetPayloadAttestationData(ctx context.Context, req *ethpb.GetPayloadAttestationDataRequest) (*ethpb.PayloadAttestationData, error) {
return nil, errors.New("not implemented")
reqSlot := req.Slot
currentSlot := vs.TimeFetcher.CurrentSlot()
if reqSlot != currentSlot {
return nil, status.Errorf(codes.InvalidArgument, "Payload attestation request slot %d != current slot %d", reqSlot, currentSlot)
}

highestSlot, root := vs.ForkchoiceFetcher.HighestReceivedBlockSlotRoot()
if reqSlot != highestSlot {
return nil, status.Errorf(codes.Unavailable, "Did not receive current slot %d block ", reqSlot)
}

payloadStatus := vs.ForkchoiceFetcher.GetPTCVote(root)

return &ethpb.PayloadAttestationData{
BeaconBlockRoot: root[:],
Slot: highestSlot,
PayloadStatus: payloadStatus,
}, nil
}

// SubmitPayloadAttestation broadcasts a payload attestation message to the network and saves the payload attestation to the cache.
Expand Down
Loading

0 comments on commit 019fb8f

Please sign in to comment.