Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Caplin Phase 1 #7290

Merged
merged 74 commits into from
Apr 17, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
521f8be
added caplin phase 1
Giulio2002 Apr 8, 2023
e873a05
added caplin-phase1-client
Giulio2002 Apr 8, 2023
b5ad262
m
Giulio2002 Apr 8, 2023
8003320
a
Giulio2002 Apr 8, 2023
ed0b346
added peers report
Giulio2002 Apr 8, 2023
8475c22
logs demotion
Giulio2002 Apr 8, 2023
dba4934
correct peer counting
Giulio2002 Apr 8, 2023
1605c08
always fully validate
Giulio2002 Apr 8, 2023
734102f
extra logging
Giulio2002 Apr 8, 2023
4817141
timeout
Giulio2002 Apr 8, 2023
f90b08d
timeout
Giulio2002 Apr 8, 2023
9c29319
proper timeout
Giulio2002 Apr 8, 2023
2723103
oops
Giulio2002 Apr 8, 2023
fc7493f
oops
Giulio2002 Apr 8, 2023
d0d8285
re-adapted cache sizes
Giulio2002 Apr 8, 2023
8d8d3f1
oops
Giulio2002 Apr 9, 2023
6887fdb
maps
Giulio2002 Apr 9, 2023
b5a41c3
ops
Giulio2002 Apr 9, 2023
c316a13
oops
Giulio2002 Apr 9, 2023
53a8252
general peer connection
Giulio2002 Apr 9, 2023
76f397a
forgot dangling error
Giulio2002 Apr 9, 2023
9339daf
aa
Giulio2002 Apr 10, 2023
8ef82e0
ops
Giulio2002 Apr 10, 2023
7071dcb
goodbye lightclient
Giulio2002 Apr 10, 2023
2bb8317
fixed missing changeset
Giulio2002 Apr 10, 2023
de421b9
a
Giulio2002 Apr 10, 2023
97f8768
fixed another bug
Giulio2002 Apr 10, 2023
58c1978
fixed yet another issue
Giulio2002 Apr 10, 2023
4550053
Merge remote-tracking branch 'origin/devel' into erigon-cl
Giulio2002 Apr 10, 2023
b328873
docker
Giulio2002 Apr 10, 2023
26a9a59
lol
Giulio2002 Apr 11, 2023
435fd90
logs
Giulio2002 Apr 11, 2023
6a79240
logs
Giulio2002 Apr 11, 2023
16567c4
gut
Giulio2002 Apr 11, 2023
bf6587f
gut
Giulio2002 Apr 11, 2023
80f8efa
done
Giulio2002 Apr 11, 2023
db3a5d8
logging
Giulio2002 Apr 11, 2023
ba6ca09
bacc
Giulio2002 Apr 11, 2023
9921f04
btree map layout
Giulio2002 Apr 12, 2023
8393b72
tests
Giulio2002 Apr 12, 2023
f321802
added log
Giulio2002 Apr 12, 2023
52d4e58
added log
Giulio2002 Apr 12, 2023
fa2b868
lol
Giulio2002 Apr 12, 2023
5cfd86f
added stuff
Giulio2002 Apr 12, 2023
04886a8
added stuff
Giulio2002 Apr 13, 2023
196be78
better get_checkpoint state
Giulio2002 Apr 13, 2023
9613b84
disabled gossip publishing
Giulio2002 Apr 13, 2023
388457a
removed inneficiency
Giulio2002 Apr 13, 2023
264dde8
fixed
Giulio2002 Apr 14, 2023
75badb4
lenient discovery
Giulio2002 Apr 14, 2023
590a695
done
Giulio2002 Apr 14, 2023
c29472a
a
Giulio2002 Apr 14, 2023
907f3c4
forgot removal
Giulio2002 Apr 14, 2023
b7b4935
removed subscription filter
Giulio2002 Apr 14, 2023
e0a0588
added correct gossip sub params
Giulio2002 Apr 14, 2023
68c8438
smol refactor to sentinel
Giulio2002 Apr 14, 2023
708884f
added better handling of missed blocks
Giulio2002 Apr 15, 2023
a80637a
attempt general connection
Giulio2002 Apr 15, 2023
e3435e1
attempt general connection
Giulio2002 Apr 15, 2023
d0a4cd0
keccak of first hash
Giulio2002 Apr 15, 2023
a816d53
try now
Giulio2002 Apr 15, 2023
eeba9a6
correct msg id
Giulio2002 Apr 15, 2023
b5c53af
ops
Giulio2002 Apr 15, 2023
f038e7b
added refresh system
Giulio2002 Apr 16, 2023
3446603
reasonable message
Giulio2002 Apr 16, 2023
c80a0e0
added stuff
Giulio2002 Apr 16, 2023
e4966aa
lol
Giulio2002 Apr 16, 2023
76e07e1
lol
Giulio2002 Apr 16, 2023
17df4d8
caplin verbosity
Giulio2002 Apr 16, 2023
7fe4072
gossip silenced
Giulio2002 Apr 16, 2023
20ac540
merge
Giulio2002 Apr 16, 2023
d7188b3
ops
Giulio2002 Apr 17, 2023
79498e9
merge again
Giulio2002 Apr 17, 2023
cde623a
always fully validate
Giulio2002 Apr 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
maps
  • Loading branch information
Giulio2002 committed Apr 9, 2023
commit 6887fdbecbac14d7aa519609ff566b10202d1ffe
2 changes: 1 addition & 1 deletion cl/clparams/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ var CheckpointSyncEndpoints = map[NetworkType][]string{
MainnetNetwork: {
"https://sync.invis.tools/eth/v2/debug/beacon/states/finalized",
"https://mainnet-checkpoint-sync.attestant.io/eth/v2/debug/beacon/states/finalized",
"https://mainnet.checkpoint.sigp.io/eth/v2/debug/beacon/states/finalized",
//"https://mainnet.checkpoint.sigp.io/eth/v2/debug/beacon/states/finalized",
"https://mainnet-checkpoint-sync.stakely.io/eth/v2/debug/beacon/states/finalized",
"https://checkpointz.pietjepuk.net/eth/v2/debug/beacon/states/finalized",
},
Expand Down
141 changes: 66 additions & 75 deletions cmd/erigon-cl/forkchoice/fork_graph/fork_graph.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package fork_graph

import (
lru "github.com/hashicorp/golang-lru/v2"
libcommon "github.com/ledgerwatch/erigon-lib/common"
"github.com/ledgerwatch/erigon/cl/clparams"
"github.com/ledgerwatch/erigon/cl/cltypes"
Expand All @@ -23,8 +22,6 @@ const (
PreValidated ChainSegmentInsertionResult = 5
)

const maxGraphExtension = 128

/*
* The state store process is related to graph theory in the sense that the Ethereum blockchain can be thought of as a directed graph,
* where each block represents a node and the links between blocks represent directed edges.
Expand All @@ -40,78 +37,48 @@ const maxGraphExtension = 128
// each edge is the path described as (prevBlockRoot, currBlockRoot). if we want to go forward we use blocks.
type ForkGraph struct {
// I am using lrus caches because of the auto cleanup feature.
inverseEdges *lru.Cache[libcommon.Hash, *beacon_changeset.ChangeSet]
forwardEdges *lru.Cache[libcommon.Hash, *beacon_changeset.ChangeSet]
headers *lru.Cache[libcommon.Hash, *cltypes.BeaconBlockHeader] // Could be either a checkpoint or state
farthestExtendingPath *lru.Cache[libcommon.Hash, bool] // The longest path is used as the "canonical"
badBlocks *lru.Cache[libcommon.Hash, bool] // blocks that are invalid and that leads to automatic fail of extension.
inverseEdges map[libcommon.Hash]*beacon_changeset.ChangeSet
forwardEdges map[libcommon.Hash]*beacon_changeset.ChangeSet
headers map[libcommon.Hash]*cltypes.BeaconBlockHeader // Could be either a checkpoint or state
farthestExtendingPath map[libcommon.Hash]bool // The longest path is used as the "canonical"
badBlocks map[libcommon.Hash]bool // blocks that are invalid and that leads to automatic fail of extension.
lastState *state.BeaconState
// Cap for how farther we can reorg (initial state slot)
anchorSlot uint64
// childrens maps each block roots to its children block roots
childrens *lru.Cache[libcommon.Hash, []libcommon.Hash]
childrens map[libcommon.Hash][]libcommon.Hash
// for each block root we also keep track of te equivalent current justified and finalized checkpoints for faster head retrieval.
currentJustifiedCheckpoints *lru.Cache[libcommon.Hash, *cltypes.Checkpoint]
finalizedCheckpoints *lru.Cache[libcommon.Hash, *cltypes.Checkpoint]
currentJustifiedCheckpoints map[libcommon.Hash]*cltypes.Checkpoint
finalizedCheckpoints map[libcommon.Hash]*cltypes.Checkpoint
}

// Initialize fork graph with a new state
func New(anchorState *state.BeaconState) *ForkGraph {
inverseEdges, err := lru.New[libcommon.Hash, *beacon_changeset.ChangeSet](maxGraphExtension)
if err != nil {
panic(err)
}
forwardEdges, err := lru.New[libcommon.Hash, *beacon_changeset.ChangeSet](maxGraphExtension)
if err != nil {
panic(err)
}
farthestExtendingPath, err := lru.New[libcommon.Hash, bool](maxGraphExtension)
if err != nil {
panic(err)
}
badBlocks, err := lru.New[libcommon.Hash, bool](maxGraphExtension)
if err != nil {
panic(err)
}
headers, err := lru.New[libcommon.Hash, *cltypes.BeaconBlockHeader](maxGraphExtension)
if err != nil {
panic(err)
}
childrens, err := lru.New[libcommon.Hash, []libcommon.Hash](maxGraphExtension)
if err != nil {
panic(err)
}
currentJustifiedCheckpoints, err := lru.New[libcommon.Hash, *cltypes.Checkpoint](maxGraphExtension)
if err != nil {
panic(err)
}
finalizedCheckpoints, err := lru.New[libcommon.Hash, *cltypes.Checkpoint](maxGraphExtension)
if err != nil {
panic(err)
}
farthestExtendingPath := make(map[libcommon.Hash]bool)
headers := make(map[libcommon.Hash]*cltypes.BeaconBlockHeader)
anchorRoot, err := anchorState.BlockRoot()
if err != nil {
panic(err)
}
anchorHeader := anchorState.LatestBlockHeader()
headers.Add(anchorRoot, &anchorHeader)
farthestExtendingPath.Add(anchorRoot, true)
headers[anchorRoot] = &anchorHeader
farthestExtendingPath[anchorRoot] = true
return &ForkGraph{
// Bidirectional edges
inverseEdges: inverseEdges,
forwardEdges: forwardEdges,
inverseEdges: make(map[libcommon.Hash]*beacon_changeset.ChangeSet),
forwardEdges: make(map[libcommon.Hash]*beacon_changeset.ChangeSet),
// storage
headers: headers,
farthestExtendingPath: farthestExtendingPath,
badBlocks: badBlocks,
badBlocks: make(map[libcommon.Hash]bool),
lastState: anchorState,
// Slots configuration
anchorSlot: anchorState.Slot(),
// childrens
childrens: childrens,
childrens: make(map[libcommon.Hash][]libcommon.Hash),
// checkpoints trackers
currentJustifiedCheckpoints: currentJustifiedCheckpoints,
finalizedCheckpoints: finalizedCheckpoints,
currentJustifiedCheckpoints: make(map[libcommon.Hash]*cltypes.Checkpoint),
finalizedCheckpoints: make(map[libcommon.Hash]*cltypes.Checkpoint),
}
}

Expand All @@ -123,19 +90,19 @@ func (f *ForkGraph) AddChainSegment(signedBlock *cltypes.SignedBeaconBlock, full
return LogisticError, err
}

if _, ok := f.forwardEdges.Get(blockRoot); ok {
if _, ok := f.forwardEdges[blockRoot]; ok {
return PreValidated, nil
}
// Blocks below anchors are invalid.
if block.Slot <= f.anchorSlot {
log.Debug("block below anchor slot", "slot", block.Slot, "hash", libcommon.Hash(blockRoot))
f.badBlocks.Add(blockRoot, true)
f.badBlocks[blockRoot] = true
return BelowAnchor, nil
}
// Check if block being process right now was marked as invalid.
if invalid, ok := f.badBlocks.Get(blockRoot); ok && invalid {
if invalid, ok := f.badBlocks[blockRoot]; ok && invalid {
log.Debug("block has invalid parent", "slot", block.Slot, "hash", libcommon.Hash(blockRoot))
f.badBlocks.Add(blockRoot, true)
f.badBlocks[blockRoot] = true
return InvalidBlock, nil
}

Expand All @@ -157,30 +124,30 @@ func (f *ForkGraph) AddChainSegment(signedBlock *cltypes.SignedBeaconBlock, full
f.lastState.StopCollectingForwardChangeSet()
// Add block to list of invalid blocks
log.Debug("Invalid beacon block", "reason", err)
f.badBlocks.Add(blockRoot, true)
f.badBlocks[blockRoot] = true
return InvalidBlock, err
}

// if it is finished then update the graph
f.inverseEdges.Add(blockRoot, f.lastState.StopCollectingReverseChangeSet())
f.forwardEdges.Add(blockRoot, f.lastState.StopCollectingForwardChangeSet())
f.inverseEdges[blockRoot] = f.lastState.StopCollectingReverseChangeSet()
f.forwardEdges[blockRoot] = f.lastState.StopCollectingForwardChangeSet()
bodyRoot, err := block.Body.HashSSZ()
if err != nil {
return LogisticError, err
}
f.headers.Add(blockRoot, &cltypes.BeaconBlockHeader{
f.headers[blockRoot] = &cltypes.BeaconBlockHeader{
Slot: block.Slot,
ProposerIndex: block.ProposerIndex,
ParentRoot: block.ParentRoot,
Root: block.StateRoot,
BodyRoot: bodyRoot,
})
f.farthestExtendingPath.Add(blockRoot, true)
}
f.farthestExtendingPath[blockRoot] = true
// Update the children of the parent
f.updateChildren(block.ParentRoot, blockRoot)
// Lastly add checkpoints to caches as well.
f.currentJustifiedCheckpoints.Add(blockRoot, f.lastState.CurrentJustifiedCheckpoint().Copy())
f.finalizedCheckpoints.Add(blockRoot, f.lastState.FinalizedCheckpoint().Copy())
f.currentJustifiedCheckpoints[blockRoot] = f.lastState.CurrentJustifiedCheckpoint().Copy()
f.finalizedCheckpoints[blockRoot] = f.lastState.FinalizedCheckpoint().Copy()
return Success, nil
}

Expand All @@ -198,7 +165,8 @@ func (f *ForkGraph) Config() *clparams.BeaconChainConfig {
}

func (f *ForkGraph) GetHeader(blockRoot libcommon.Hash) (*cltypes.BeaconBlockHeader, bool) {
return f.headers.Get(blockRoot)
obj, has := f.headers[blockRoot]
return obj, has
}

func (f *ForkGraph) GetState(blockRoot libcommon.Hash) (*state.BeaconState, error) {
Expand All @@ -214,9 +182,10 @@ func (f *ForkGraph) GetState(blockRoot libcommon.Hash) (*state.BeaconState, erro
// Use the parent root as a reverse iterator.
currentIteratorRoot := blockRoot
// try and find the point of recconection
for reconnect, ok := f.farthestExtendingPath.Get(currentIteratorRoot); !ok || !reconnect; reconnect, ok = f.farthestExtendingPath.Get(currentIteratorRoot) {
for reconnect, ok := f.farthestExtendingPath[currentIteratorRoot]; !ok || !reconnect; reconnect, ok = f.farthestExtendingPath[currentIteratorRoot] {
parent, isSegmentPresent := f.GetHeader(currentIteratorRoot)
if !isSegmentPresent {
log.Debug("Could not retrieve state: Missing header", "missing", currentIteratorRoot)
return nil, nil
}
blockRootsFromFarthestExtendingPath = append(blockRootsFromFarthestExtendingPath, currentIteratorRoot)
Expand All @@ -228,8 +197,9 @@ func (f *ForkGraph) GetState(blockRoot libcommon.Hash) (*state.BeaconState, erro

// Unwind to the recconection root.
for edge != currentIteratorRoot {
changeset, isChangesetPreset := f.inverseEdges.Get(edge)
changeset, isChangesetPreset := f.inverseEdges[edge]
if !isChangesetPreset {
log.Debug("Could not retrieve state: Missing changeset", "missing", currentIteratorRoot)
return nil, nil
}
// Recompute currentBlockRoot
Expand All @@ -244,42 +214,63 @@ func (f *ForkGraph) GetState(blockRoot libcommon.Hash) (*state.BeaconState, erro
}
// Traverse the graph forward now (the nodes are in reverse order).
for i := len(blockRootsFromFarthestExtendingPath) - 1; i >= 0; i-- {
changeset, _ := f.forwardEdges.Get(blockRootsFromFarthestExtendingPath[i])
changeset := f.forwardEdges[blockRootsFromFarthestExtendingPath[i]]
f.lastState.RevertWithChangeset(changeset)
}
// If we have a new farthest extended path, update it accordingly.
for _, root := range inverselyTraversedRoots {
if root == edge {
continue
}
f.farthestExtendingPath.Add(root, false)
f.farthestExtendingPath[root] = false
}
for _, root := range blockRootsFromFarthestExtendingPath {
f.farthestExtendingPath.Add(root, true)
f.farthestExtendingPath[root] = true
}
return f.lastState, nil
}

// updateChildren adds a new child to the parent node hash.
func (f *ForkGraph) updateChildren(parent, child libcommon.Hash) {
childrens, _ := f.childrens.Get(parent)
childrens := f.childrens[parent]
if slices.Contains(childrens, child) {
return
}
childrens = append(childrens, child)
f.childrens.Add(parent, childrens)
f.childrens[parent] = childrens
}

// GetChildren retrieves the children block root of the given block root.
func (f *ForkGraph) GetChildren(parent libcommon.Hash) []libcommon.Hash {
childrens, _ := f.childrens.Get(parent)
return childrens
return f.childrens[parent]
}

func (f *ForkGraph) GetCurrentJustifiedCheckpoint(blockRoot libcommon.Hash) (*cltypes.Checkpoint, bool) {
return f.currentJustifiedCheckpoints.Get(blockRoot)
obj, has := f.currentJustifiedCheckpoints[blockRoot]
return obj, has
}

func (f *ForkGraph) GetFinalizedCheckpoint(blockRoot libcommon.Hash) (*cltypes.Checkpoint, bool) {
return f.finalizedCheckpoints.Get(blockRoot)
obj, has := f.finalizedCheckpoints[blockRoot]
return obj, has
}

func (f *ForkGraph) RemoveOldBlocks(pruneSlot uint64) {
oldRoots := make([]libcommon.Hash, 0, len(f.headers))
for hash, header := range f.headers {
if header.Slot >= pruneSlot {
continue
}
oldRoots = append(oldRoots, hash)
}
for _, root := range oldRoots {
delete(f.inverseEdges, root)
delete(f.headers, root)
delete(f.forwardEdges, root)
delete(f.farthestExtendingPath, root)
delete(f.badBlocks, root)
delete(f.childrens, root)
delete(f.currentJustifiedCheckpoints, root)
delete(f.finalizedCheckpoints, root)
}
}
10 changes: 2 additions & 8 deletions cmd/erigon-cl/forkchoice/forkchoice.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,8 @@ type ForkChoiceStore struct {
equivocatingIndicies map[uint64]struct{}
forkGraph *fork_graph.ForkGraph
// I use the cache due to the convenient auto-cleanup feauture.
unrealizedJustifications *lru.Cache[libcommon.Hash, *cltypes.Checkpoint]
checkpointStates *lru.Cache[cltypes.Checkpoint, *state.BeaconState] // We keep ssz snappy of it as the full beacon state is full of rendundant data.
latestMessages map[uint64]*LatestMessage
checkpointStates *lru.Cache[cltypes.Checkpoint, *state.BeaconState] // We keep ssz snappy of it as the full beacon state is full of rendundant data.
latestMessages map[uint64]*LatestMessage
// We keep track of them so that we can forkchoice with EL.
eth2Roots *lru.Cache[libcommon.Hash, libcommon.Hash] // ETH2 root -> ETH1 hash
mu sync.Mutex
Expand All @@ -59,10 +58,6 @@ func NewForkChoiceStore(anchorState *state.BeaconState, engine execution_client.
Epoch: anchorState.Epoch(),
Root: anchorRoot,
}
unrealizedJustifications, err := lru.New[libcommon.Hash, *cltypes.Checkpoint](checkpointsPerCache)
if err != nil {
return nil, err
}
checkpointStates, err := lru.New[cltypes.Checkpoint, *state.BeaconState](allowedCachedStates)
if err != nil {
return nil, err
Expand All @@ -79,7 +74,6 @@ func NewForkChoiceStore(anchorState *state.BeaconState, engine execution_client.
unrealizedJustifiedCheckpoint: anchorCheckpoint.Copy(),
unrealizedFinalizedCheckpoint: anchorCheckpoint.Copy(),
forkGraph: fork_graph.New(anchorState),
unrealizedJustifications: unrealizedJustifications,
equivocatingIndicies: map[uint64]struct{}{},
latestMessages: map[uint64]*LatestMessage{},
checkpointStates: checkpointStates,
Expand Down
4 changes: 0 additions & 4 deletions cmd/erigon-cl/forkchoice/on_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,6 @@ func (f *ForkChoiceStore) OnBlock(block *cltypes.SignedBeaconBlock, fullValidati
lastProcessedState.RevertWithChangeset(lastProcessedState.StopCollectingReverseChangeSet())
return err
}
// Add justied checkpoint
copiedCheckpoint := *lastProcessedState.CurrentJustifiedCheckpoint()
f.unrealizedJustifications.Add(blockRoot, &copiedCheckpoint)

f.updateUnrealizedCheckpoints(lastProcessedState.CurrentJustifiedCheckpoint().Copy(), lastProcessedState.FinalizedCheckpoint().Copy())
// If the block is from a prior epoch, apply the realized values
blockEpoch := f.computeEpochAtSlot(block.Block.Slot)
Expand Down
7 changes: 5 additions & 2 deletions cmd/erigon-cl/forkchoice/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ import (
"github.com/ledgerwatch/erigon/cl/cltypes"
"github.com/ledgerwatch/erigon/cmd/erigon-cl/core/state"
"github.com/ledgerwatch/erigon/cmd/erigon-cl/core/transition"
"github.com/ledgerwatch/log/v3"
)

var noChangeCheckpointEncoding = []byte{0xff}

// Slot calculates the current slot number using the time and genesis slot.
func (f *ForkChoiceStore) Slot() uint64 {
return f.forkGraph.Config().GenesisSlot + ((f.time - f.forkGraph.GenesisTime()) / f.forkGraph.Config().SecondsPerSlot)
Expand All @@ -23,6 +22,10 @@ func (f *ForkChoiceStore) updateCheckpoints(justifiedCheckpoint, finalizedCheckp
}
if finalizedCheckpoint.Epoch > f.finalizedCheckpoint.Epoch {
f.finalizedCheckpoint = finalizedCheckpoint
// We cannot go past point of finalization
pruneSlot := f.computeStartSlotAtEpoch(finalizedCheckpoint.Epoch)
log.Debug("Pruning old blocks", "pruneSlot", pruneSlot)
f.forkGraph.RemoveOldBlocks(pruneSlot)
}
}

Expand Down