Skip to content

Commit

Permalink
Add GetPTCVote helpers (#14420)
Browse files Browse the repository at this point in the history
  • Loading branch information
potuz committed Nov 4, 2024
1 parent 3beda88 commit b17e331
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 1 deletion.
1 change: 1 addition & 0 deletions beacon-chain/blockchain/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ go_test(
"chain_info_norace_test.go",
"chain_info_test.go",
"checktags_test.go",
"epbs_test.go",
"error_test.go",
"execution_engine_test.go",
"forkchoice_update_execution_test.go",
Expand Down
19 changes: 19 additions & 0 deletions beacon-chain/blockchain/chain_info_forkchoice.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,22 @@ func (s *Service) ParentRoot(root [32]byte) ([32]byte, error) {
defer s.cfg.ForkChoiceStore.RUnlock()
return s.cfg.ForkChoiceStore.ParentRoot(root)
}

// GetPTCVote wraps a call to the corresponding method in forkchoice and checks
// the currently syncing status
// Warning: this method will return the current PTC status regardless of
// timeliness. A client MUST call this method when about to submit a PTC
// attestation, that is exactly at the threshold to submit the attestation.
func (s *Service) GetPTCVote(root [32]byte) primitives.PTCStatus {
s.cfg.ForkChoiceStore.RLock()
f := s.cfg.ForkChoiceStore.GetPTCVote()
s.cfg.ForkChoiceStore.RUnlock()
if f != primitives.PAYLOAD_ABSENT {
return f
}
f, isSyncing := s.payloadBeingSynced.isSyncing(root)
if isSyncing {
return f
}
return primitives.PAYLOAD_ABSENT
}
18 changes: 18 additions & 0 deletions beacon-chain/blockchain/epbs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package blockchain

import (
"testing"

doublylinkedtree "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice/doubly-linked-tree"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/testing/require"
)

func TestServiceGetPTCVote(t *testing.T) {
c := &currentlySyncingPayload{roots: make(map[[32]byte]primitives.PTCStatus)}
s := &Service{cfg: &config{ForkChoiceStore: doublylinkedtree.New()}, payloadBeingSynced: c}
r := [32]byte{'r'}
require.Equal(t, primitives.PAYLOAD_ABSENT, s.GetPTCVote(r))
c.roots[r] = primitives.PAYLOAD_WITHHELD
require.Equal(t, primitives.PAYLOAD_WITHHELD, s.GetPTCVote(r))
}
22 changes: 22 additions & 0 deletions beacon-chain/forkchoice/doubly-linked-tree/epbs.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,31 @@
package doublylinkedtree

import (
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/time/slots"
)

func (n *Node) isParentFull() bool {
// Finalized checkpoint is considered full
if n.parent == nil || n.parent.parent == nil {
return true
}
return n.parent.payloadHash != [32]byte{}
}

func (f *ForkChoice) GetPTCVote() primitives.PTCStatus {
highestNode := f.store.highestReceivedNode
if highestNode == nil {
return primitives.PAYLOAD_ABSENT
}
if slots.CurrentSlot(f.store.genesisTime) > highestNode.slot {
return primitives.PAYLOAD_ABSENT
}
if highestNode.payloadHash == [32]byte{} {
return primitives.PAYLOAD_ABSENT
}
if highestNode.withheld {
return primitives.PAYLOAD_WITHHELD
}
return primitives.PAYLOAD_PRESENT
}
21 changes: 21 additions & 0 deletions beacon-chain/forkchoice/doubly-linked-tree/epbs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"testing"

"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/testing/require"
)

Expand Down Expand Up @@ -77,3 +78,23 @@ func TestStore_Insert_PayloadContent(t *testing.T) {
require.NoError(t, err)
require.Equal(t, n, n2)
}

func TestGetPTCVote(t *testing.T) {
ctx := context.Background()
f := setup(0, 0)
s := f.store
require.NotNil(t, s.highestReceivedNode)
fr := [32]byte{}

// Insert a child with a payload
cr := [32]byte{'a'}
cp := [32]byte{'p'}
n, err := s.insert(ctx, 1, cr, fr, cp, fr, 0, 0)
require.NoError(t, err)
require.Equal(t, n, s.highestReceivedNode)
require.Equal(t, primitives.PAYLOAD_ABSENT, f.GetPTCVote())
driftGenesisTime(f, 1, 0)
require.Equal(t, primitives.PAYLOAD_PRESENT, f.GetPTCVote())
n.withheld = true
require.Equal(t, primitives.PAYLOAD_WITHHELD, f.GetPTCVote())
}
3 changes: 2 additions & 1 deletion beacon-chain/forkchoice/doubly-linked-tree/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,10 @@ type Node struct {
balance uint64 // the balance that voted for this node directly
weight uint64 // weight of this node: the total balance including children
bestDescendant *Node // bestDescendant node of this node.
optimistic bool // whether the block has been fully validated or not
timestamp uint64 // The timestamp when the node was inserted.
ptcVote []primitives.PTCStatus // tracks the Payload Timeliness Committee (PTC) votes for the node
withheld bool // whether the builder sent a withheld message for this payload
optimistic bool // whether the block has been fully validated or not
}

// Vote defines an individual validator's vote.
Expand Down
1 change: 1 addition & 0 deletions beacon-chain/forkchoice/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ type FastGetter interface {
UnrealizedJustifiedPayloadBlockHash() [32]byte
Weight(root [32]byte) (uint64, error)
ParentRoot(root [32]byte) ([32]byte, error)
GetPTCVote() primitives.PTCStatus
}

// Setter allows to set forkchoice information
Expand Down
7 changes: 7 additions & 0 deletions beacon-chain/forkchoice/ro.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,10 @@ func (ro *ROForkChoice) ParentRoot(root [32]byte) ([32]byte, error) {
defer ro.l.RUnlock()
return ro.getter.ParentRoot(root)
}

// GetPTCVote delegates to the underlying forkchoice call, under a lock.
func (ro *ROForkChoice) GetPTCVote() primitives.PTCStatus {
ro.l.RLock()
defer ro.l.RUnlock()
return ro.getter.GetPTCVote()
}
6 changes: 6 additions & 0 deletions beacon-chain/forkchoice/ro_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const (
lastRootCalled
targetRootForEpochCalled
parentRootCalled
getPTCVoteCalled
)

func _discard(t *testing.T, e error) {
Expand Down Expand Up @@ -303,3 +304,8 @@ func (ro *mockROForkchoice) ParentRoot(_ [32]byte) ([32]byte, error) {
ro.calls = append(ro.calls, parentRootCalled)
return [32]byte{}, nil
}

func (ro *mockROForkchoice) GetPTCVote() primitives.PTCStatus {
ro.calls = append(ro.calls, getPTCVoteCalled)
return primitives.PAYLOAD_ABSENT
}

0 comments on commit b17e331

Please sign in to comment.