Compare commits

...

2 Commits

Author SHA1 Message Date
Potuz
848a4d56ed init 2 2026-02-04 17:29:52 -03:00
potuz
4340b61a78 init 2026-02-04 07:42:24 -03:00
4 changed files with 107 additions and 47 deletions

View File

@@ -31,8 +31,8 @@ func New() *ForkChoice {
prevJustifiedCheckpoint: &forkchoicetypes.Checkpoint{}, prevJustifiedCheckpoint: &forkchoicetypes.Checkpoint{},
finalizedCheckpoint: &forkchoicetypes.Checkpoint{}, finalizedCheckpoint: &forkchoicetypes.Checkpoint{},
proposerBoostRoot: [32]byte{}, proposerBoostRoot: [32]byte{},
nodeByRoot: make(map[[fieldparams.RootLength]byte]*Node), nodeByRoot: make(map[[fieldparams.RootLength]byte]*PayloadNode),
nodeByPayload: make(map[[fieldparams.RootLength]byte]*Node), nodeByPayload: make(map[[fieldparams.RootLength]byte]*PayloadNode),
slashedIndices: make(map[primitives.ValidatorIndex]bool), slashedIndices: make(map[primitives.ValidatorIndex]bool),
receivedBlocksLastEpoch: [fieldparams.SlotsPerEpoch]primitives.Slot{}, receivedBlocksLastEpoch: [fieldparams.SlotsPerEpoch]primitives.Slot{},
} }
@@ -119,14 +119,14 @@ func (f *ForkChoice) InsertNode(ctx context.Context, state state.BeaconState, ro
return errInvalidNilCheckpoint return errInvalidNilCheckpoint
} }
finalizedEpoch := fc.Epoch finalizedEpoch := fc.Epoch
node, err := f.store.insert(ctx, roblock, justifiedEpoch, finalizedEpoch) pn, err := f.store.insert(ctx, roblock, justifiedEpoch, finalizedEpoch)
if err != nil { if err != nil {
return err return err
} }
jc, fc = f.store.pullTips(state, node, jc, fc) jc, fc = f.store.pullTips(state, pn.node, jc, fc)
if err := f.updateCheckpoints(ctx, jc, fc); err != nil { if err := f.updateCheckpoints(ctx, jc, fc); err != nil {
_, remErr := f.store.removeNode(ctx, node) _, remErr := f.store.removeNode(ctx, pn)
if remErr != nil { if remErr != nil {
log.WithError(remErr).Error("Could not remove node") log.WithError(remErr).Error("Could not remove node")
} }

View File

@@ -0,0 +1,32 @@
package doublylinkedtree
import (
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
"github.com/pkg/errors"
)
func (s *Store) getNodeInformation(block interfaces.ReadOnlyBeaconBlock, parent *PayloadNode, payloadHash *[32]byte) error {
sb, err := block.Body().SignedExecutionPayloadBid()
if err != nil {
return err
}
wb, err := blocks.WrappedROSignedExecutionPayloadBid(sb)
if err != nil {
return errors.Wrap(err, "failed to wrap signed bid")
}
bid, err := wb.Bid()
if err != nil {
return errors.Wrap(err, "failed to get bid from wrapped bid")
}
*payloadHash = bid.BlockHash()
if parent == nil {
// This is the tree root node.
return nil
}
if bid.ParentBlockHash() == parent.node.payloadHash {
//block builds on full
parent = s.nodeByPayload[parent.node.payloadHash]
}
return nil
}

View File

@@ -66,16 +66,27 @@ func (s *Store) head(ctx context.Context) ([32]byte, error) {
// It then updates the new node's parent with the best child and descendant node. // It then updates the new node's parent with the best child and descendant node.
func (s *Store) insert(ctx context.Context, func (s *Store) insert(ctx context.Context,
roblock consensus_blocks.ROBlock, roblock consensus_blocks.ROBlock,
justifiedEpoch, finalizedEpoch primitives.Epoch) (*Node, error) { justifiedEpoch, finalizedEpoch primitives.Epoch,
) (*PayloadNode, error) {
ctx, span := trace.StartSpan(ctx, "doublyLinkedForkchoice.insert") ctx, span := trace.StartSpan(ctx, "doublyLinkedForkchoice.insert")
defer span.End() defer span.End()
root := roblock.Root() root := roblock.Root()
// Return if the block has been inserted into Store before.
if n, ok := s.nodeByRoot[root]; ok {
return n, nil
}
block := roblock.Block() block := roblock.Block()
slot := block.Slot() slot := block.Slot()
parentRoot := block.ParentRoot() parentRoot := block.ParentRoot()
var payloadHash [32]byte parent := s.nodeByRoot[parentRoot]
if block.Version() >= version.Bellatrix { var payloadHash *[32]byte
if block.Version() >= version.Gloas {
if err := s.getNodeInformation(block, parent, payloadHash); err != nil {
return nil, err
}
} else if block.Version() >= version.Bellatrix {
execution, err := block.Body().Execution() execution, err := block.Body().Execution()
if err != nil { if err != nil {
return nil, err return nil, err
@@ -83,12 +94,6 @@ func (s *Store) insert(ctx context.Context,
copy(payloadHash[:], execution.BlockHash()) copy(payloadHash[:], execution.BlockHash())
} }
// Return if the block has been inserted into Store before.
if n, ok := s.nodeByRoot[root]; ok {
return n, nil
}
parent := s.nodeByRoot[parentRoot]
n := &Node{ n := &Node{
slot: slot, slot: slot,
root: root, root: root,
@@ -97,24 +102,39 @@ func (s *Store) insert(ctx context.Context,
unrealizedJustifiedEpoch: justifiedEpoch, unrealizedJustifiedEpoch: justifiedEpoch,
finalizedEpoch: finalizedEpoch, finalizedEpoch: finalizedEpoch,
unrealizedFinalizedEpoch: finalizedEpoch, unrealizedFinalizedEpoch: finalizedEpoch,
optimistic: true, payloadHash: *payloadHash,
payloadHash: payloadHash,
timestamp: time.Now(),
} }
// Set the node's target checkpoint // Set the node's target checkpoint
if slot%params.BeaconConfig().SlotsPerEpoch == 0 { if slot%params.BeaconConfig().SlotsPerEpoch == 0 {
n.target = n n.target = n
} else if parent != nil { } else if parent != nil {
if slots.ToEpoch(slot) == slots.ToEpoch(parent.slot) { if slots.ToEpoch(slot) == slots.ToEpoch(parent.node.slot) {
n.target = parent.target n.target = parent.node.target
} else { } else {
n.target = parent n.target = parent.node
} }
} }
var ret *PayloadNode
// Make the empty node.
pn := &PayloadNode{
node: n,
optimistic: true,
timestamp: time.Now(),
}
s.nodeByRoot[root] = pn
ret = pn
if block.Version() < version.Gloas {
// Make also the full node
fn := &PayloadNode{
node: n,
optimistic: true,
timestamp: time.Now(),
full: true,
}
ret = fn
s.nodeByPayload[*payloadHash] = fn
}
s.nodeByPayload[payloadHash] = n
s.nodeByRoot[root] = n
if parent == nil { if parent == nil {
if s.treeRootNode == nil { if s.treeRootNode == nil {
s.treeRootNode = n s.treeRootNode = n
@@ -122,7 +142,7 @@ func (s *Store) insert(ctx context.Context,
s.highestReceivedNode = n s.highestReceivedNode = n
} else { } else {
delete(s.nodeByRoot, root) delete(s.nodeByRoot, root)
delete(s.nodeByPayload, payloadHash) delete(s.nodeByPayload, *payloadHash)
return nil, errInvalidParentRoot return nil, errInvalidParentRoot
} }
} else { } else {
@@ -130,7 +150,7 @@ func (s *Store) insert(ctx context.Context,
// Apply proposer boost // Apply proposer boost
now := time.Now() now := time.Now()
if now.Before(s.genesisTime) { if now.Before(s.genesisTime) {
return n, nil return ret, nil
} }
currentSlot := slots.CurrentSlot(s.genesisTime) currentSlot := slots.CurrentSlot(s.genesisTime)
sss, err := slots.SinceSlotStart(currentSlot, s.genesisTime, now) sss, err := slots.SinceSlotStart(currentSlot, s.genesisTime, now)
@@ -167,7 +187,7 @@ func (s *Store) insert(ctx context.Context,
s.highestReceivedNode = n s.highestReceivedNode = n
} }
return n, nil return ret, nil
} }
// pruneFinalizedNodeByRootMap prunes the `nodeByRoot` map // pruneFinalizedNodeByRootMap prunes the `nodeByRoot` map

View File

@@ -23,22 +23,22 @@ type ForkChoice struct {
// Store defines the fork choice store which includes block nodes and the last view of checkpoint information. // Store defines the fork choice store which includes block nodes and the last view of checkpoint information.
type Store struct { type Store struct {
justifiedCheckpoint *forkchoicetypes.Checkpoint // latest justified epoch in store. justifiedCheckpoint *forkchoicetypes.Checkpoint // latest justified epoch in store.
unrealizedJustifiedCheckpoint *forkchoicetypes.Checkpoint // best unrealized justified checkpoint in store. unrealizedJustifiedCheckpoint *forkchoicetypes.Checkpoint // best unrealized justified checkpoint in store.
unrealizedFinalizedCheckpoint *forkchoicetypes.Checkpoint // best unrealized finalized checkpoint in store. unrealizedFinalizedCheckpoint *forkchoicetypes.Checkpoint // best unrealized finalized checkpoint in store.
prevJustifiedCheckpoint *forkchoicetypes.Checkpoint // previous justified checkpoint in store. prevJustifiedCheckpoint *forkchoicetypes.Checkpoint // previous justified checkpoint in store.
finalizedCheckpoint *forkchoicetypes.Checkpoint // latest finalized epoch in store. finalizedCheckpoint *forkchoicetypes.Checkpoint // latest finalized epoch in store.
proposerBoostRoot [fieldparams.RootLength]byte // latest block root that was boosted after being received in a timely manner. proposerBoostRoot [fieldparams.RootLength]byte // latest block root that was boosted after being received in a timely manner.
previousProposerBoostRoot [fieldparams.RootLength]byte // previous block root that was boosted after being received in a timely manner. previousProposerBoostRoot [fieldparams.RootLength]byte // previous block root that was boosted after being received in a timely manner.
previousProposerBoostScore uint64 // previous proposer boosted root score. previousProposerBoostScore uint64 // previous proposer boosted root score.
finalizedDependentRoot [fieldparams.RootLength]byte // dependent root at finalized checkpoint. finalizedDependentRoot [fieldparams.RootLength]byte // dependent root at finalized checkpoint.
committeeWeight uint64 // tracks the total active validator balance divided by the number of slots per Epoch. committeeWeight uint64 // tracks the total active validator balance divided by the number of slots per Epoch.
treeRootNode *Node // the root node of the store tree. treeRootNode *Node // the root node of the store tree.
headNode *Node // last head Node headNode *Node // last head Node
nodeByRoot map[[fieldparams.RootLength]byte]*Node // nodes indexed by roots. nodeByRoot map[[fieldparams.RootLength]byte]*PayloadNode // nodes indexed by roots.
nodeByPayload map[[fieldparams.RootLength]byte]*Node // nodes indexed by payload Hash nodeByPayload map[[fieldparams.RootLength]byte]*PayloadNode // nodes indexed by payload Hash
slashedIndices map[primitives.ValidatorIndex]bool // the list of equivocating validator indices slashedIndices map[primitives.ValidatorIndex]bool // the list of equivocating validator indices
originRoot [fieldparams.RootLength]byte // The genesis block root originRoot [fieldparams.RootLength]byte // The genesis block root
genesisTime time.Time genesisTime time.Time
highestReceivedNode *Node // The highest slot node. highestReceivedNode *Node // The highest slot node.
receivedBlocksLastEpoch [fieldparams.SlotsPerEpoch]primitives.Slot // Using `highestReceivedSlot`. The slot of blocks received in the last epoch. receivedBlocksLastEpoch [fieldparams.SlotsPerEpoch]primitives.Slot // Using `highestReceivedSlot`. The slot of blocks received in the last epoch.
@@ -51,18 +51,26 @@ type Node struct {
slot primitives.Slot // slot of the block converted to the node. slot primitives.Slot // slot of the block converted to the node.
root [fieldparams.RootLength]byte // root of the block converted to the node. root [fieldparams.RootLength]byte // root of the block converted to the node.
payloadHash [fieldparams.RootLength]byte // payloadHash of the block converted to the node. payloadHash [fieldparams.RootLength]byte // payloadHash of the block converted to the node.
parent *Node // parent index of this node. parent *PayloadNode // parent index of this node.
target *Node // target checkpoint for target *Node // target checkpoint for
children []*Node // the list of direct children of this Node
justifiedEpoch primitives.Epoch // justifiedEpoch of this node. justifiedEpoch primitives.Epoch // justifiedEpoch of this node.
unrealizedJustifiedEpoch primitives.Epoch // the epoch that would be justified if the block would be advanced to the next epoch. unrealizedJustifiedEpoch primitives.Epoch // the epoch that would be justified if the block would be advanced to the next epoch.
finalizedEpoch primitives.Epoch // finalizedEpoch of this node. finalizedEpoch primitives.Epoch // finalizedEpoch of this node.
unrealizedFinalizedEpoch primitives.Epoch // the epoch that would be finalized if the block would be advanced to the next epoch. unrealizedFinalizedEpoch primitives.Epoch // the epoch that would be finalized if the block would be advanced to the next epoch.
balance uint64 // the balance that voted for this node directly balance uint64 // the balance that voted for this node directly
weight uint64 // weight of this node: the total balance including children 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 time.Time // The timestamp when the node was inserted. // PayloadNode defines a full Forkchoice node after the Gloas fork, with the payload status either empty of full
type PayloadNode struct {
node *Node // the consensus part of this full forkchoice node
children []*Node // the list of direct children of this Node
bestDescendant *Node // bestDescendant node of this node.
full bool // whether this node represents a payload present or not
balance uint64 // the balance that voted for this node directly
weight uint64 // weight of this node: the total balance including children
optimistic bool // whether the block has been fully validated or not
timestamp time.Time // The timestamp when the node was inserted.
} }
// Vote defines an individual validator's vote. // Vote defines an individual validator's vote.