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

forkchoice changes #12126

Merged
merged 12 commits into from
Mar 16, 2023
8 changes: 0 additions & 8 deletions beacon-chain/blockchain/chain_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,14 +118,6 @@ func (s *Service) CurrentJustifiedCheckpt() *ethpb.Checkpoint {
return &ethpb.Checkpoint{Epoch: cp.Epoch, Root: bytesutil.SafeCopyBytes(cp.Root[:])}
}

// BestJustifiedCheckpt returns the best justified checkpoint from store.
func (s *Service) BestJustifiedCheckpt() *ethpb.Checkpoint {
s.ForkChoicer().RLock()
defer s.ForkChoicer().RUnlock()
cp := s.ForkChoicer().BestJustifiedCheckpoint()
return &ethpb.Checkpoint{Epoch: cp.Epoch, Root: bytesutil.SafeCopyBytes(cp.Root[:])}
}

// HeadSlot returns the slot of the head of the chain.
func (s *Service) HeadSlot() primitives.Slot {
s.headLock.RLock()
Expand Down
1 change: 0 additions & 1 deletion beacon-chain/forkchoice/doubly-linked-tree/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ go_test(
"//beacon-chain/forkchoice/types:go_default_library",
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/state-native:go_default_library",
"//config/features:go_default_library",
"//config/params:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/primitives:go_default_library",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,6 @@ func setup(justifiedEpoch, finalizedEpoch primitives.Epoch) *ForkChoice {
ctx := context.Background()
f := New()
f.store.justifiedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: justifiedEpoch, Root: params.BeaconConfig().ZeroHash}
f.store.bestJustifiedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: justifiedEpoch, Root: params.BeaconConfig().ZeroHash}
f.store.finalizedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: finalizedEpoch, Root: params.BeaconConfig().ZeroHash}
state, blkRoot, err := prepareForkchoiceState(ctx, 0, params.BeaconConfig().ZeroHash, [32]byte{}, params.BeaconConfig().ZeroHash, justifiedEpoch, finalizedEpoch)
if err != nil {
Expand Down
75 changes: 6 additions & 69 deletions beacon-chain/forkchoice/doubly-linked-tree/forkchoice.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice"
forkchoicetypes "github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/types"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v3/config/features"
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
"github.com/prysmaticlabs/prysm/v3/config/params"
"github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
Expand All @@ -27,7 +26,6 @@ import (
func New() *ForkChoice {
s := &Store{
justifiedCheckpoint: &forkchoicetypes.Checkpoint{},
bestJustifiedCheckpoint: &forkchoicetypes.Checkpoint{},
unrealizedJustifiedCheckpoint: &forkchoicetypes.Checkpoint{},
unrealizedFinalizedCheckpoint: &forkchoicetypes.Checkpoint{},
prevJustifiedCheckpoint: &forkchoicetypes.Checkpoint{},
Expand Down Expand Up @@ -142,60 +140,18 @@ func (f *ForkChoice) InsertNode(ctx context.Context, state state.BeaconState, ro
return err
}

if !features.Get().DisablePullTips {
jc, fc = f.store.pullTips(state, node, jc, fc)
}
jc, fc = f.store.pullTips(state, node, jc, fc)
return f.updateCheckpoints(ctx, jc, fc)
}

// updateCheckpoints update the checkpoints when inserting a new node.
func (f *ForkChoice) updateCheckpoints(ctx context.Context, jc, fc *ethpb.Checkpoint) error {
if jc.Epoch > f.store.justifiedCheckpoint.Epoch {
if jc.Epoch > f.store.bestJustifiedCheckpoint.Epoch {
f.store.bestJustifiedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: jc.Epoch,
Root: bytesutil.ToBytes32(jc.Root)}
}
if !features.Get().EnableDefensivePull {
currentSlot := slots.CurrentSlot(f.store.genesisTime)
if slots.SinceEpochStarts(currentSlot) < params.BeaconConfig().SafeSlotsToUpdateJustified {
f.store.prevJustifiedCheckpoint = f.store.justifiedCheckpoint
root := bytesutil.ToBytes32(jc.Root)
f.store.justifiedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: jc.Epoch,
Root: root}
if err := f.updateJustifiedBalances(ctx, root); err != nil {
return errors.Wrap(err, "could not update justified balances")
}
} else {
currentJcp := f.store.justifiedCheckpoint
currentRoot := currentJcp.Root
if currentRoot == params.BeaconConfig().ZeroHash {
currentRoot = f.store.originRoot
}
jSlot, err := slots.EpochStart(currentJcp.Epoch)
if err != nil {
return err
}
jcRoot := bytesutil.ToBytes32(jc.Root)
root, err := f.AncestorRoot(ctx, jcRoot, jSlot)
if err != nil {
return err
}
if root == currentRoot {
f.store.prevJustifiedCheckpoint = f.store.justifiedCheckpoint
f.store.justifiedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: jc.Epoch,
Root: jcRoot}
if err := f.updateJustifiedBalances(ctx, jcRoot); err != nil {
return errors.Wrap(err, "could not update justified balances")
}
}
}
} else {
f.store.prevJustifiedCheckpoint = f.store.justifiedCheckpoint
jcRoot := bytesutil.ToBytes32(jc.Root)
f.store.justifiedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: jc.Epoch, Root: jcRoot}
if err := f.updateJustifiedBalances(ctx, jcRoot); err != nil {
return errors.Wrap(err, "could not update justified balances")
}
f.store.prevJustifiedCheckpoint = f.store.justifiedCheckpoint
jcRoot := bytesutil.ToBytes32(jc.Root)
f.store.justifiedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: jc.Epoch, Root: jcRoot}
if err := f.updateJustifiedBalances(ctx, jcRoot); err != nil {
return errors.Wrap(err, "could not update justified balances")
}
}
// Update finalization
Expand All @@ -204,14 +160,6 @@ func (f *ForkChoice) updateCheckpoints(ctx context.Context, jc, fc *ethpb.Checkp
}
f.store.finalizedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: fc.Epoch,
Root: bytesutil.ToBytes32(fc.Root)}
if !features.Get().EnableDefensivePull {
root := bytesutil.ToBytes32(jc.Root)
f.store.justifiedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: jc.Epoch,
Root: root}
if err := f.updateJustifiedBalances(ctx, root); err != nil {
return errors.Wrap(err, "could not update justified balances")
}
}
return f.store.prune(ctx)
}

Expand Down Expand Up @@ -370,11 +318,6 @@ func (f *ForkChoice) SetOptimisticToValid(ctx context.Context, root [fieldparams
return node.setNodeAndParentValidated(ctx)
}

// BestJustifiedCheckpoint of fork choice store.
func (f *ForkChoice) BestJustifiedCheckpoint() *forkchoicetypes.Checkpoint {
return f.store.bestJustifiedCheckpoint
}

// PreviousJustifiedCheckpoint of fork choice store.
func (f *ForkChoice) PreviousJustifiedCheckpoint() *forkchoicetypes.Checkpoint {
return f.store.prevJustifiedCheckpoint
Expand Down Expand Up @@ -434,7 +377,6 @@ func (f *ForkChoice) UpdateJustifiedCheckpoint(ctx context.Context, jc *forkchoi
}
f.store.prevJustifiedCheckpoint = f.store.justifiedCheckpoint
f.store.justifiedCheckpoint = jc
f.store.bestJustifiedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: jc.Epoch, Root: jc.Root}
if err := f.updateJustifiedBalances(ctx, jc.Root); err != nil {
return errors.Wrap(err, "could not update justified balances")
}
Expand Down Expand Up @@ -572,10 +514,6 @@ func (f *ForkChoice) ForkChoiceDump(ctx context.Context) (*v1.ForkChoiceDump, er
Epoch: f.store.justifiedCheckpoint.Epoch,
Root: f.store.justifiedCheckpoint.Root[:],
}
bjc := &v1.Checkpoint{
Epoch: f.store.bestJustifiedCheckpoint.Epoch,
Root: f.store.bestJustifiedCheckpoint.Root[:],
}
ujc := &v1.Checkpoint{
Epoch: f.store.unrealizedJustifiedCheckpoint.Epoch,
Root: f.store.unrealizedJustifiedCheckpoint.Root[:],
Expand All @@ -602,7 +540,6 @@ func (f *ForkChoice) ForkChoiceDump(ctx context.Context) (*v1.ForkChoiceDump, er
}
resp := &v1.ForkChoiceDump{
JustifiedCheckpoint: jc,
BestJustifiedCheckpoint: bjc,
UnrealizedJustifiedCheckpoint: ujc,
FinalizedCheckpoint: fc,
UnrealizedFinalizedCheckpoint: ufc,
Expand Down
54 changes: 0 additions & 54 deletions beacon-chain/forkchoice/doubly-linked-tree/forkchoice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,6 @@ func TestForkChoice_UpdateCheckpoints(t *testing.T) {
tests := []struct {
name string
justified *forkchoicetypes.Checkpoint
bestJustified *forkchoicetypes.Checkpoint
finalized *forkchoicetypes.Checkpoint
newJustified *forkchoicetypes.Checkpoint
newFinalized *forkchoicetypes.Checkpoint
Expand All @@ -636,7 +635,6 @@ func TestForkChoice_UpdateCheckpoints(t *testing.T) {
name: "lower than store justified and finalized",
justified: &forkchoicetypes.Checkpoint{Epoch: 2, Root: [32]byte{'j'}},
finalized: &forkchoicetypes.Checkpoint{Epoch: 1, Root: [32]byte{'f'}},
bestJustified: &forkchoicetypes.Checkpoint{Epoch: 2, Root: [32]byte{'j'}},
newJustified: &forkchoicetypes.Checkpoint{Epoch: 1},
newFinalized: &forkchoicetypes.Checkpoint{Epoch: 0},
wantedJustified: &forkchoicetypes.Checkpoint{Epoch: 2, Root: [32]byte{'j'}},
Expand All @@ -646,7 +644,6 @@ func TestForkChoice_UpdateCheckpoints(t *testing.T) {
{
name: "higher than store justified, early slot, direct descendant",
justified: &forkchoicetypes.Checkpoint{Epoch: 2, Root: [32]byte{'j'}},
bestJustified: &forkchoicetypes.Checkpoint{Epoch: 2, Root: [32]byte{'j'}},
finalized: &forkchoicetypes.Checkpoint{Epoch: 1, Root: [32]byte{'f'}},
newJustified: &forkchoicetypes.Checkpoint{Epoch: 3, Root: [32]byte{'b'}},
newFinalized: &forkchoicetypes.Checkpoint{Epoch: 1, Root: [32]byte{'g'}},
Expand All @@ -657,67 +654,19 @@ func TestForkChoice_UpdateCheckpoints(t *testing.T) {
{
name: "higher than store justified, early slot, not a descendant",
justified: &forkchoicetypes.Checkpoint{Epoch: 2, Root: [32]byte{'j'}},
bestJustified: &forkchoicetypes.Checkpoint{Epoch: 2, Root: [32]byte{'j'}},
finalized: &forkchoicetypes.Checkpoint{Epoch: 1, Root: [32]byte{'f'}},
newJustified: &forkchoicetypes.Checkpoint{Epoch: 3, Root: [32]byte{'c'}},
newFinalized: &forkchoicetypes.Checkpoint{Epoch: 1, Root: [32]byte{'g'}},
wantedJustified: &forkchoicetypes.Checkpoint{Epoch: 3, Root: [32]byte{'c'}},
wantedBestJustified: &forkchoicetypes.Checkpoint{Epoch: 3, Root: [32]byte{'c'}},
wantedFinalized: &forkchoicetypes.Checkpoint{Epoch: 1, Root: [32]byte{'f'}},
},
{
name: "higher than store justified, late slot, descendant",
justified: &forkchoicetypes.Checkpoint{Epoch: 2, Root: [32]byte{'j'}},
bestJustified: &forkchoicetypes.Checkpoint{Epoch: 2, Root: [32]byte{'j'}},
finalized: &forkchoicetypes.Checkpoint{Epoch: 1, Root: [32]byte{'f'}},
newJustified: &forkchoicetypes.Checkpoint{Epoch: 3, Root: [32]byte{'b'}},
newFinalized: &forkchoicetypes.Checkpoint{Epoch: 1, Root: [32]byte{'g'}},
wantedJustified: &forkchoicetypes.Checkpoint{Epoch: 3, Root: [32]byte{'b'}},
wantedFinalized: &forkchoicetypes.Checkpoint{Epoch: 1, Root: [32]byte{'f'}},
wantedBestJustified: &forkchoicetypes.Checkpoint{Epoch: 3, Root: [32]byte{'b'}},
currentSlot: params.BeaconConfig().SafeSlotsToUpdateJustified.Add(1),
},
{
name: "higher than store justified, late slot, not descendant",
justified: &forkchoicetypes.Checkpoint{Epoch: 2, Root: [32]byte{'j'}},
bestJustified: &forkchoicetypes.Checkpoint{Epoch: 2, Root: [32]byte{'j'}},
finalized: &forkchoicetypes.Checkpoint{Epoch: 1, Root: [32]byte{'f'}},
newJustified: &forkchoicetypes.Checkpoint{Epoch: 3, Root: [32]byte{'c'}},
newFinalized: &forkchoicetypes.Checkpoint{Epoch: 1, Root: [32]byte{'g'}},
wantedJustified: &forkchoicetypes.Checkpoint{Epoch: 2, Root: [32]byte{'j'}},
wantedFinalized: &forkchoicetypes.Checkpoint{Epoch: 1, Root: [32]byte{'f'}},
wantedBestJustified: &forkchoicetypes.Checkpoint{Epoch: 3, Root: [32]byte{'c'}},
currentSlot: params.BeaconConfig().SafeSlotsToUpdateJustified.Add(1),
},
{
name: "higher than store finalized, late slot, not descendant",
justified: &forkchoicetypes.Checkpoint{Epoch: 2, Root: [32]byte{'j'}},
bestJustified: &forkchoicetypes.Checkpoint{Epoch: 2, Root: [32]byte{'j'}},
finalized: &forkchoicetypes.Checkpoint{Epoch: 1, Root: [32]byte{'f'}},
newJustified: &forkchoicetypes.Checkpoint{Epoch: 3, Root: [32]byte{'c'}},
newFinalized: &forkchoicetypes.Checkpoint{Epoch: 2, Root: [32]byte{'h'}},
wantedJustified: &forkchoicetypes.Checkpoint{Epoch: 3, Root: [32]byte{'c'}},
wantedFinalized: &forkchoicetypes.Checkpoint{Epoch: 2, Root: [32]byte{'h'}},
wantedBestJustified: &forkchoicetypes.Checkpoint{Epoch: 3, Root: [32]byte{'c'}},
currentSlot: params.BeaconConfig().SafeSlotsToUpdateJustified.Add(1),
},
{
name: "Unknown checkpoint root, late slot",
justified: &forkchoicetypes.Checkpoint{Epoch: 2, Root: [32]byte{'j'}},
bestJustified: &forkchoicetypes.Checkpoint{Epoch: 2, Root: [32]byte{'j'}},
finalized: &forkchoicetypes.Checkpoint{Epoch: 1, Root: [32]byte{'f'}},
newJustified: &forkchoicetypes.Checkpoint{Epoch: 3, Root: [32]byte{'d'}},
newFinalized: &forkchoicetypes.Checkpoint{Epoch: 1, Root: [32]byte{'h'}},
currentSlot: params.BeaconConfig().SafeSlotsToUpdateJustified.Add(1),
wantedErr: "could not determine ancestor root",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
fcs := setup(tt.justified.Epoch, tt.finalized.Epoch)
fcs.store.justifiedCheckpoint = tt.justified
fcs.store.finalizedCheckpoint = tt.finalized
fcs.store.bestJustifiedCheckpoint = tt.bestJustified
fcs.store.genesisTime = uint64(time.Now().Unix()) - uint64(tt.currentSlot)*params.BeaconConfig().SecondsPerSlot

st, blkRoot, err := prepareForkchoiceState(ctx, 32, [32]byte{'f'},
Expand All @@ -743,7 +692,6 @@ func TestForkChoice_UpdateCheckpoints(t *testing.T) {
// restart justifications cause insertion messed it up
fcs.store.justifiedCheckpoint = tt.justified
fcs.store.finalizedCheckpoint = tt.finalized
fcs.store.bestJustifiedCheckpoint = tt.bestJustified

jc := &ethpb.Checkpoint{Epoch: tt.newJustified.Epoch, Root: tt.newJustified.Root[:]}
fc := &ethpb.Checkpoint{Epoch: tt.newFinalized.Epoch, Root: tt.newFinalized.Root[:]}
Expand All @@ -756,8 +704,6 @@ func TestForkChoice_UpdateCheckpoints(t *testing.T) {
require.Equal(t, tt.wantedFinalized.Epoch, fcs.store.finalizedCheckpoint.Epoch)
require.Equal(t, tt.wantedJustified.Root, fcs.store.justifiedCheckpoint.Root)
require.Equal(t, tt.wantedFinalized.Root, fcs.store.finalizedCheckpoint.Root)
require.Equal(t, tt.wantedBestJustified.Epoch, fcs.store.bestJustifiedCheckpoint.Epoch)
require.Equal(t, tt.wantedBestJustified.Root, fcs.store.bestJustifiedCheckpoint.Root)
}
})
}
Expand Down
3 changes: 1 addition & 2 deletions beacon-chain/forkchoice/doubly-linked-tree/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"context"

"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v3/config/features"
"github.com/prysmaticlabs/prysm/v3/config/params"
"github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
v1 "github.com/prysmaticlabs/prysm/v3/proto/eth/v1"
Expand Down Expand Up @@ -99,7 +98,7 @@ func (n *Node) updateBestDescendant(ctx context.Context, justifiedEpoch, finaliz
// the ones in fork choice store should not be viable to head.
func (n *Node) viableForHead(justifiedEpoch, currentEpoch primitives.Epoch) bool {
justified := justifiedEpoch == n.justifiedEpoch || justifiedEpoch == 0
if features.Get().EnableDefensivePull && !justified && justifiedEpoch+1 == currentEpoch {
if !justified && justifiedEpoch+1 == currentEpoch {
if n.unrealizedJustifiedEpoch+1 >= currentEpoch && n.justifiedEpoch+2 >= currentEpoch {
justified = true
}
Expand Down
32 changes: 2 additions & 30 deletions beacon-chain/forkchoice/doubly-linked-tree/on_tick.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"

"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v3/config/features"
"github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v3/time/slots"
)
Expand Down Expand Up @@ -42,35 +41,8 @@ func (f *ForkChoice) NewSlot(ctx context.Context, slot primitives.Slot) error {
}

// Update store.justified_checkpoint if a better checkpoint on the store.finalized_checkpoint chain
bjcp := f.store.bestJustifiedCheckpoint
jcp := f.store.justifiedCheckpoint
fcp := f.store.finalizedCheckpoint
if bjcp.Epoch > jcp.Epoch {
finalizedSlot, err := slots.EpochStart(fcp.Epoch)
if err != nil {
return err
}

// We check that the best justified checkpoint is a descendant of the finalized checkpoint.
// This should always happen as forkchoice enforces that every node is a descendant of the
// finalized checkpoint. This check is here for additional security, consider removing the extra
// loop call here.
r, err := f.AncestorRoot(ctx, bjcp.Root, finalizedSlot)
if err != nil {
return err
}
if r == fcp.Root {
f.store.prevJustifiedCheckpoint = jcp
f.store.justifiedCheckpoint = bjcp
if err := f.updateJustifiedBalances(ctx, bjcp.Root); err != nil {
log.Error("could not update justified balances")
}
}
}
if !features.Get().DisablePullTips {
if err := f.updateUnrealizedCheckpoints(ctx); err != nil {
return errors.Wrap(err, "could not update unrealized checkpoints")
}
if err := f.updateUnrealizedCheckpoints(ctx); err != nil {
return errors.Wrap(err, "could not update unrealized checkpoints")
}
return f.store.prune(ctx)
}
Loading