Skip to content

Commit a8ab279

Browse files
Protoarray: add ChainHeads (#8684)
* Add ChainHeads * Add only has bestChild case * Update beacon-chain/forkchoice/protoarray/store.go Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
1 parent feeb59d commit a8ab279

File tree

2 files changed

+40
-0
lines changed

2 files changed

+40
-0
lines changed

beacon-chain/forkchoice/protoarray/store.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,29 @@ func (s *Store) NodesIndices() map[[32]byte]uint64 {
230230
return s.nodesIndices
231231
}
232232

233+
// ChainHeads returns all possible chain heads (leaves of fork choice tree).
234+
// Heads roots and heads slots are returned.
235+
func (s *Store) ChainHeads() ([][32]byte, []types.Slot) {
236+
s.nodesLock.RLock()
237+
nodes := s.Nodes()
238+
s.nodesLock.RUnlock()
239+
240+
// Deliberate choice to not preallocate space for below.
241+
// Heads cant be more than 2-3 in the worst case where pre-allocation will be 64 to begin with.
242+
headsRoots := make([][32]byte, 0)
243+
headsSlots := make([]types.Slot, 0)
244+
245+
for _, node := range nodes {
246+
// Possible heads have no children.
247+
if node.bestDescendant == NonExistentNode && node.bestChild == NonExistentNode {
248+
headsRoots = append(headsRoots, node.root)
249+
headsSlots = append(headsSlots, node.slot)
250+
}
251+
}
252+
253+
return headsRoots, headsSlots
254+
}
255+
233256
// head starts from justified root and then follows the best descendant links
234257
// to find the best block for head.
235258
func (s *Store) head(ctx context.Context, justifiedRoot [32]byte) ([32]byte, error) {

beacon-chain/forkchoice/protoarray/store_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,3 +589,20 @@ func TestStore_UpdateCanonicalNodes_ContextCancelled(t *testing.T) {
589589
cancel()
590590
require.ErrorContains(t, "context canceled", f.store.updateCanonicalNodes(ctx, [32]byte{'c'}))
591591
}
592+
593+
func TestStore_ChainHeads(t *testing.T) {
594+
nodes := []*Node{
595+
{slot: 100, root: [32]byte{'a'}, bestChild: NonExistentNode, bestDescendant: NonExistentNode},
596+
{slot: 101, root: [32]byte{'b'}},
597+
{slot: 102, root: [32]byte{'c'}, bestDescendant: NonExistentNode},
598+
{slot: 103, root: [32]byte{'d'}, bestChild: NonExistentNode, bestDescendant: NonExistentNode},
599+
{slot: 104, root: [32]byte{'e'}, bestChild: NonExistentNode},
600+
}
601+
602+
s := &Store{
603+
nodes: nodes,
604+
}
605+
roots, slots := s.ChainHeads()
606+
require.DeepEqual(t, [][32]byte{{'a'}, {'d'}}, roots)
607+
require.DeepEqual(t, []types.Slot{100, 103}, slots)
608+
}

0 commit comments

Comments
 (0)