From 5d29ca4984a0e01468170d91f5df472564775202 Mon Sep 17 00:00:00 2001 From: Potuz Date: Wed, 29 Jun 2022 20:37:21 -0300 Subject: [PATCH] Experimental disable boundary checks (#10936) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * init * bellatrix + altair tests passing * Add Phase0 support * add feature flag * phase0 test * restore testvectors * mod tidy * state tests * gaz * do not call precompute * fix test * Fix context * move to own's method * remove spectests pulltips * time import * remove phase0 * mod tidy * fix getters * Update beacon-chain/forkchoice/doubly-linked-tree/types.go * reviews * fix workspace * Recursive rlocks Co-authored-by: terencechain Co-authored-by: RadosÅ‚aw Kapka --- beacon-chain/blockchain/process_block.go | 6 ++- .../precompute/justification_finalization.go | 11 +++- .../justification_finalization_test.go | 2 +- .../forkchoice/doubly-linked-tree/BUILD.bazel | 3 ++ .../doubly-linked-tree/forkchoice.go | 31 +++++++----- .../forkchoice/doubly-linked-tree/on_tick.go | 4 ++ .../forkchoice/doubly-linked-tree/store.go | 14 +++--- .../doubly-linked-tree/store_test.go | 3 +- .../forkchoice/doubly-linked-tree/types.go | 38 +++++++------- .../unrealized_justification.go | 50 ++++++++++++++++++- .../unrealized_justification_test.go | 3 ++ beacon-chain/forkchoice/interfaces.go | 2 +- .../forkchoice/protoarray/BUILD.bazel | 3 ++ beacon-chain/forkchoice/protoarray/on_tick.go | 4 ++ beacon-chain/forkchoice/protoarray/store.go | 47 +++++++++-------- .../forkchoice/protoarray/store_test.go | 6 ++- beacon-chain/forkchoice/protoarray/types.go | 40 ++++++++------- .../protoarray/unrealized_justification.go | 50 ++++++++++++++++++- .../unrealized_justification_test.go | 3 ++ .../state-native/getters_participation.go | 2 +- .../stateutil/unrealized_justification.go | 5 ++ .../state/v2/getters_participation.go | 2 +- .../state/v3/getters_participation.go | 2 +- config/features/config.go | 5 ++ config/features/flags.go | 7 +++ .../shared/common/forkchoice/service.go | 4 +- 26 files changed, 254 insertions(+), 93 deletions(-) diff --git a/beacon-chain/blockchain/process_block.go b/beacon-chain/blockchain/process_block.go index 95cfbbcf9e..0ba5a04591 100644 --- a/beacon-chain/blockchain/process_block.go +++ b/beacon-chain/blockchain/process_block.go @@ -212,7 +212,9 @@ func (s *Service) onBlock(ctx context.Context, signed interfaces.SignedBeaconBlo // Save justified check point to db. if justified.Epoch > currJustifiedEpoch { - if err := s.cfg.BeaconDB.SaveJustifiedCheckpoint(ctx, postState.CurrentJustifiedCheckpoint()); err != nil { + if err := s.cfg.BeaconDB.SaveJustifiedCheckpoint(ctx, ðpb.Checkpoint{ + Epoch: justified.Epoch, Root: justified.Root[:], + }); err != nil { return err } } @@ -220,7 +222,7 @@ func (s *Service) onBlock(ctx context.Context, signed interfaces.SignedBeaconBlo // Update finalized check point. finalized := s.ForkChoicer().FinalizedCheckpoint() if finalized.Epoch > currFinalizedEpoch { - if err := s.updateFinalized(ctx, postState.FinalizedCheckpoint()); err != nil { + if err := s.updateFinalized(ctx, ðpb.Checkpoint{Epoch: finalized.Epoch, Root: finalized.Root[:]}); err != nil { return err } isOptimistic, err := s.cfg.ForkChoiceStore.IsOptimistic(finalized.Root) diff --git a/beacon-chain/core/epoch/precompute/justification_finalization.go b/beacon-chain/core/epoch/precompute/justification_finalization.go index 36b8822ed7..af9a819295 100644 --- a/beacon-chain/core/epoch/precompute/justification_finalization.go +++ b/beacon-chain/core/epoch/precompute/justification_finalization.go @@ -1,11 +1,14 @@ package precompute import ( + "context" + "github.com/pkg/errors" "github.com/prysmaticlabs/go-bitfield" "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" "github.com/prysmaticlabs/prysm/beacon-chain/core/time" "github.com/prysmaticlabs/prysm/beacon-chain/state" + "github.com/prysmaticlabs/prysm/config/params" ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1" "github.com/prysmaticlabs/prysm/time/slots" ) @@ -14,11 +17,17 @@ var errNilState = errors.New("nil state") // UnrealizedCheckpoints returns the justification and finalization checkpoints of the // given state as if it was progressed with empty slots until the next epoch. -func UnrealizedCheckpoints(st state.BeaconState) (*ethpb.Checkpoint, *ethpb.Checkpoint, error) { +func UnrealizedCheckpoints(ctx context.Context, st state.BeaconState) (*ethpb.Checkpoint, *ethpb.Checkpoint, error) { if st == nil || st.IsNil() { return nil, nil, errNilState } + if slots.ToEpoch(st.Slot()) <= params.BeaconConfig().GenesisEpoch+1 { + jc := st.CurrentJustifiedCheckpoint() + fc := st.FinalizedCheckpoint() + return jc, fc, nil + } + activeBalance, prevTarget, currentTarget, err := st.UnrealizedCheckpointBalances() if err != nil { return nil, nil, err diff --git a/beacon-chain/core/epoch/precompute/justification_finalization_test.go b/beacon-chain/core/epoch/precompute/justification_finalization_test.go index 90172576ea..0c263784da 100644 --- a/beacon-chain/core/epoch/precompute/justification_finalization_test.go +++ b/beacon-chain/core/epoch/precompute/justification_finalization_test.go @@ -243,7 +243,7 @@ func TestUnrealizedCheckpoints(t *testing.T) { _, _, err = altair.InitializePrecomputeValidators(context.Background(), state) require.NoError(t, err) - jc, fc, err := precompute.UnrealizedCheckpoints(state) + jc, fc, err := precompute.UnrealizedCheckpoints(context.Background(), state) require.NoError(t, err) require.DeepEqual(t, test.expectedJustified, jc.Epoch) require.DeepEqual(t, test.expectedFinalized, fc.Epoch) diff --git a/beacon-chain/forkchoice/doubly-linked-tree/BUILD.bazel b/beacon-chain/forkchoice/doubly-linked-tree/BUILD.bazel index 7d82c2b002..2ff3b1ddb5 100644 --- a/beacon-chain/forkchoice/doubly-linked-tree/BUILD.bazel +++ b/beacon-chain/forkchoice/doubly-linked-tree/BUILD.bazel @@ -22,9 +22,12 @@ go_library( ], deps = [ "//beacon-chain/core/blocks:go_default_library", + "//beacon-chain/core/epoch/precompute:go_default_library", + "//beacon-chain/core/time:go_default_library", "//beacon-chain/forkchoice:go_default_library", "//beacon-chain/forkchoice/types:go_default_library", "//beacon-chain/state:go_default_library", + "//config/features:go_default_library", "//config/fieldparams:go_default_library", "//config/params:go_default_library", "//consensus-types/primitives:go_default_library", diff --git a/beacon-chain/forkchoice/doubly-linked-tree/forkchoice.go b/beacon-chain/forkchoice/doubly-linked-tree/forkchoice.go index 9c907802d6..78a672d038 100644 --- a/beacon-chain/forkchoice/doubly-linked-tree/forkchoice.go +++ b/beacon-chain/forkchoice/doubly-linked-tree/forkchoice.go @@ -9,6 +9,7 @@ import ( "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice" forkchoicetypes "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/types" "github.com/prysmaticlabs/prysm/beacon-chain/state" + "github.com/prysmaticlabs/prysm/config/features" fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams" "github.com/prysmaticlabs/prysm/config/params" types "github.com/prysmaticlabs/prysm/consensus-types/primitives" @@ -23,15 +24,17 @@ import ( // New initializes a new fork choice store. func New() *ForkChoice { s := &Store{ - justifiedCheckpoint: &forkchoicetypes.Checkpoint{}, - bestJustifiedCheckpoint: &forkchoicetypes.Checkpoint{}, - prevJustifiedCheckpoint: &forkchoicetypes.Checkpoint{}, - finalizedCheckpoint: &forkchoicetypes.Checkpoint{}, - proposerBoostRoot: [32]byte{}, - nodeByRoot: make(map[[fieldparams.RootLength]byte]*Node), - nodeByPayload: make(map[[fieldparams.RootLength]byte]*Node), - slashedIndices: make(map[types.ValidatorIndex]bool), - pruneThreshold: defaultPruneThreshold, + justifiedCheckpoint: &forkchoicetypes.Checkpoint{}, + bestJustifiedCheckpoint: &forkchoicetypes.Checkpoint{}, + unrealizedJustifiedCheckpoint: &forkchoicetypes.Checkpoint{}, + unrealizedFinalizedCheckpoint: &forkchoicetypes.Checkpoint{}, + prevJustifiedCheckpoint: &forkchoicetypes.Checkpoint{}, + finalizedCheckpoint: &forkchoicetypes.Checkpoint{}, + proposerBoostRoot: [32]byte{}, + nodeByRoot: make(map[[fieldparams.RootLength]byte]*Node), + nodeByPayload: make(map[[fieldparams.RootLength]byte]*Node), + slashedIndices: make(map[types.ValidatorIndex]bool), + pruneThreshold: defaultPruneThreshold, } b := make([]uint64, 0) @@ -112,7 +115,7 @@ func (f *ForkChoice) ProcessAttestation(ctx context.Context, validatorIndices [] } // InsertNode processes a new block by inserting it to the fork choice store. -func (f *ForkChoice) InsertNode(ctx context.Context, state state.ReadOnlyBeaconState, root [32]byte) error { +func (f *ForkChoice) InsertNode(ctx context.Context, state state.BeaconState, root [32]byte) error { ctx, span := trace.StartSpan(ctx, "doublyLinkedForkchoice.InsertNode") defer span.End() @@ -142,10 +145,14 @@ func (f *ForkChoice) InsertNode(ctx context.Context, state state.ReadOnlyBeaconS return errInvalidNilCheckpoint } finalizedEpoch := fc.Epoch - err := f.store.insert(ctx, slot, root, parentRoot, payloadHash, justifiedEpoch, finalizedEpoch) + node, err := f.store.insert(ctx, slot, root, parentRoot, payloadHash, justifiedEpoch, finalizedEpoch) if err != nil { return err } + + if features.Get().PullTips { + jc, fc = f.store.pullTips(ctx, state, node, jc, fc) + } return f.updateCheckpoints(ctx, jc, fc) } @@ -546,7 +553,7 @@ func (f *ForkChoice) InsertOptimisticChain(ctx context.Context, chain []*forkcho if err != nil { return err } - if err := f.store.insert(ctx, + if _, err := f.store.insert(ctx, b.Slot(), r, parentRoot, payloadHash, chain[i].JustifiedCheckpoint.Epoch, chain[i].FinalizedCheckpoint.Epoch); err != nil { return err diff --git a/beacon-chain/forkchoice/doubly-linked-tree/on_tick.go b/beacon-chain/forkchoice/doubly-linked-tree/on_tick.go index a614234bf6..d6aa52caa3 100644 --- a/beacon-chain/forkchoice/doubly-linked-tree/on_tick.go +++ b/beacon-chain/forkchoice/doubly-linked-tree/on_tick.go @@ -4,6 +4,7 @@ import ( "context" "github.com/pkg/errors" + "github.com/prysmaticlabs/prysm/config/features" types "github.com/prysmaticlabs/prysm/consensus-types/primitives" "github.com/prysmaticlabs/prysm/time/slots" ) @@ -64,5 +65,8 @@ func (f *ForkChoice) NewSlot(ctx context.Context, slot types.Slot) error { f.store.justifiedCheckpoint = bjcp } } + if features.Get().PullTips { + f.UpdateUnrealizedCheckpoints() + } return nil } diff --git a/beacon-chain/forkchoice/doubly-linked-tree/store.go b/beacon-chain/forkchoice/doubly-linked-tree/store.go index 0e10f5ea53..bdec7d2c90 100644 --- a/beacon-chain/forkchoice/doubly-linked-tree/store.go +++ b/beacon-chain/forkchoice/doubly-linked-tree/store.go @@ -108,7 +108,7 @@ func (s *Store) head(ctx context.Context) ([32]byte, error) { func (s *Store) insert(ctx context.Context, slot types.Slot, root, parentRoot, payloadHash [fieldparams.RootLength]byte, - justifiedEpoch, finalizedEpoch types.Epoch) error { + justifiedEpoch, finalizedEpoch types.Epoch) (*Node, error) { _, span := trace.StartSpan(ctx, "doublyLinkedForkchoice.insert") defer span.End() @@ -116,8 +116,8 @@ func (s *Store) insert(ctx context.Context, defer s.nodesLock.Unlock() // Return if the block has been inserted into Store before. - if _, ok := s.nodeByRoot[root]; ok { - return nil + if n, ok := s.nodeByRoot[root]; ok { + return n, nil } parent := s.nodeByRoot[parentRoot] @@ -141,14 +141,14 @@ func (s *Store) insert(ctx context.Context, s.treeRootNode = n s.headNode = n } else { - return errInvalidParentRoot + return n, errInvalidParentRoot } } else { parent.children = append(parent.children, n) // Apply proposer boost timeNow := uint64(time.Now().Unix()) if timeNow < s.genesisTime { - return nil + return n, nil } secondsIntoSlot := (timeNow - s.genesisTime) % params.BeaconConfig().SecondsPerSlot currentSlot := slots.CurrentSlot(s.genesisTime) @@ -162,14 +162,14 @@ func (s *Store) insert(ctx context.Context, // Update best descendants if err := s.treeRootNode.updateBestDescendant(ctx, s.justifiedCheckpoint.Epoch, s.finalizedCheckpoint.Epoch); err != nil { - return err + return n, err } } // Update metrics. processedBlockCount.Inc() nodeCount.Set(float64(len(s.nodeByRoot))) - return nil + return n, nil } // pruneFinalizedNodeByRootMap prunes the `nodeByRoot` map diff --git a/beacon-chain/forkchoice/doubly-linked-tree/store_test.go b/beacon-chain/forkchoice/doubly-linked-tree/store_test.go index 301b08b205..b0314951e0 100644 --- a/beacon-chain/forkchoice/doubly-linked-tree/store_test.go +++ b/beacon-chain/forkchoice/doubly-linked-tree/store_test.go @@ -141,7 +141,8 @@ func TestStore_Insert(t *testing.T) { fc := &forkchoicetypes.Checkpoint{Epoch: 0} s := &Store{nodeByRoot: nodeByRoot, treeRootNode: treeRootNode, nodeByPayload: nodeByPayload, justifiedCheckpoint: jc, finalizedCheckpoint: fc} payloadHash := [32]byte{'a'} - require.NoError(t, s.insert(context.Background(), 100, indexToHash(100), indexToHash(0), payloadHash, 1, 1)) + _, err := s.insert(context.Background(), 100, indexToHash(100), indexToHash(0), payloadHash, 1, 1) + require.NoError(t, err) assert.Equal(t, 2, len(s.nodeByRoot), "Did not insert block") assert.Equal(t, (*Node)(nil), treeRootNode.parent, "Incorrect parent") assert.Equal(t, 1, len(treeRootNode.children), "Incorrect children number") diff --git a/beacon-chain/forkchoice/doubly-linked-tree/types.go b/beacon-chain/forkchoice/doubly-linked-tree/types.go index f5656758c9..5c49a3a550 100644 --- a/beacon-chain/forkchoice/doubly-linked-tree/types.go +++ b/beacon-chain/forkchoice/doubly-linked-tree/types.go @@ -18,24 +18,26 @@ type ForkChoice struct { // Store defines the fork choice store which includes block nodes and the last view of checkpoint information. type Store struct { - justifiedCheckpoint *forkchoicetypes.Checkpoint // latest justified epoch in store. - bestJustifiedCheckpoint *forkchoicetypes.Checkpoint // best justified checkpoint in store. - prevJustifiedCheckpoint *forkchoicetypes.Checkpoint // previous justified checkpoint in store. - finalizedCheckpoint *forkchoicetypes.Checkpoint // latest finalized epoch in store. - pruneThreshold uint64 // do not prune tree unless threshold is reached. - 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. - previousProposerBoostScore uint64 // previous proposer boosted root score. - treeRootNode *Node // the root node of the store tree. - headNode *Node // last head Node - nodeByRoot map[[fieldparams.RootLength]byte]*Node // nodes indexed by roots. - nodeByPayload map[[fieldparams.RootLength]byte]*Node // nodes indexed by payload Hash - slashedIndices map[types.ValidatorIndex]bool // the list of equivocating validator indices - originRoot [fieldparams.RootLength]byte // The genesis block root - nodesLock sync.RWMutex - proposerBoostLock sync.RWMutex - checkpointsLock sync.RWMutex - genesisTime uint64 + justifiedCheckpoint *forkchoicetypes.Checkpoint // latest justified epoch in store. + bestJustifiedCheckpoint *forkchoicetypes.Checkpoint // best justified checkpoint in store. + unrealizedJustifiedCheckpoint *forkchoicetypes.Checkpoint // best unrealized justified checkpoint in store. + unrealizedFinalizedCheckpoint *forkchoicetypes.Checkpoint // best unrealized finalized checkpoint in store. + prevJustifiedCheckpoint *forkchoicetypes.Checkpoint // previous justified checkpoint in store. + finalizedCheckpoint *forkchoicetypes.Checkpoint // latest finalized epoch in store. + pruneThreshold uint64 // do not prune tree unless threshold is reached. + 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. + previousProposerBoostScore uint64 // previous proposer boosted root score. + treeRootNode *Node // the root node of the store tree. + headNode *Node // last head Node + nodeByRoot map[[fieldparams.RootLength]byte]*Node // nodes indexed by roots. + nodeByPayload map[[fieldparams.RootLength]byte]*Node // nodes indexed by payload Hash + slashedIndices map[types.ValidatorIndex]bool // the list of equivocating validator indices + originRoot [fieldparams.RootLength]byte // The genesis block root + nodesLock sync.RWMutex + proposerBoostLock sync.RWMutex + checkpointsLock sync.RWMutex + genesisTime uint64 } // Node defines the individual block which includes its block parent, ancestor and how much weight accounted for it. diff --git a/beacon-chain/forkchoice/doubly-linked-tree/unrealized_justification.go b/beacon-chain/forkchoice/doubly-linked-tree/unrealized_justification.go index d3febe8238..fbcc9f3e94 100644 --- a/beacon-chain/forkchoice/doubly-linked-tree/unrealized_justification.go +++ b/beacon-chain/forkchoice/doubly-linked-tree/unrealized_justification.go @@ -1,8 +1,17 @@ package doublylinkedtree import ( + "context" + "github.com/pkg/errors" + "github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute" + "github.com/prysmaticlabs/prysm/beacon-chain/core/time" + forkchoicetypes "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/types" + "github.com/prysmaticlabs/prysm/beacon-chain/state" types "github.com/prysmaticlabs/prysm/consensus-types/primitives" + "github.com/prysmaticlabs/prysm/encoding/bytesutil" + ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/time/slots" ) func (s *Store) setUnrealizedJustifiedEpoch(root [32]byte, epoch types.Epoch) error { @@ -45,10 +54,47 @@ func (f *ForkChoice) UpdateUnrealizedCheckpoints() { node.justifiedEpoch = node.unrealizedJustifiedEpoch node.finalizedEpoch = node.unrealizedFinalizedEpoch if node.justifiedEpoch > f.store.justifiedCheckpoint.Epoch { - f.store.justifiedCheckpoint.Epoch = node.justifiedEpoch + if node.justifiedEpoch > f.store.bestJustifiedCheckpoint.Epoch { + f.store.bestJustifiedCheckpoint = f.store.unrealizedJustifiedCheckpoint + } + f.store.justifiedCheckpoint = f.store.unrealizedJustifiedCheckpoint } if node.finalizedEpoch > f.store.finalizedCheckpoint.Epoch { - f.store.finalizedCheckpoint.Epoch = node.finalizedEpoch + f.store.justifiedCheckpoint = f.store.unrealizedJustifiedCheckpoint + f.store.finalizedCheckpoint = f.store.unrealizedFinalizedCheckpoint } } } + +func (s *Store) pullTips(ctx context.Context, state state.BeaconState, node *Node, jc, fc *ethpb.Checkpoint) (*ethpb.Checkpoint, *ethpb.Checkpoint) { + var uj, uf *ethpb.Checkpoint + uj, uf, err := precompute.UnrealizedCheckpoints(ctx, state) + if err != nil { + log.WithError(err).Debug("could not compute unrealized checkpoints") + uj, uf = jc, fc + } + node.unrealizedJustifiedEpoch, node.unrealizedFinalizedEpoch = uj.Epoch, uf.Epoch + s.checkpointsLock.Lock() + if uj.Epoch > s.unrealizedJustifiedCheckpoint.Epoch { + s.unrealizedJustifiedCheckpoint = &forkchoicetypes.Checkpoint{ + Epoch: uj.Epoch, Root: bytesutil.ToBytes32(uj.Root), + } + } + if uf.Epoch > s.unrealizedFinalizedCheckpoint.Epoch { + s.unrealizedJustifiedCheckpoint = &forkchoicetypes.Checkpoint{ + Epoch: uj.Epoch, Root: bytesutil.ToBytes32(uj.Root), + } + s.unrealizedFinalizedCheckpoint = &forkchoicetypes.Checkpoint{ + Epoch: uf.Epoch, Root: bytesutil.ToBytes32(uf.Root), + } + } + + currentSlot := slots.CurrentSlot(s.genesisTime) + if time.CurrentEpoch(state) < slots.ToEpoch(currentSlot) { + jc, fc = uj, uf + node.justifiedEpoch = uj.Epoch + node.finalizedEpoch = uf.Epoch + } + s.checkpointsLock.Unlock() + return jc, fc +} diff --git a/beacon-chain/forkchoice/doubly-linked-tree/unrealized_justification_test.go b/beacon-chain/forkchoice/doubly-linked-tree/unrealized_justification_test.go index 620dddeb04..5d790ad101 100644 --- a/beacon-chain/forkchoice/doubly-linked-tree/unrealized_justification_test.go +++ b/beacon-chain/forkchoice/doubly-linked-tree/unrealized_justification_test.go @@ -147,6 +147,8 @@ func TestStore_NoDeadLock(t *testing.T) { require.NoError(t, f.InsertNode(ctx, state, blkRoot)) require.NoError(t, f.store.setUnrealizedJustifiedEpoch([32]byte{'g'}, 2)) require.NoError(t, f.store.setUnrealizedFinalizedEpoch([32]byte{'g'}, 1)) + f.store.unrealizedJustifiedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: 2} + f.store.unrealizedFinalizedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: 1} state, blkRoot, err = prepareForkchoiceState(ctx, 107, [32]byte{'h'}, [32]byte{'g'}, [32]byte{'H'}, 0, 0) require.NoError(t, err) require.NoError(t, f.InsertNode(ctx, state, blkRoot)) @@ -236,6 +238,7 @@ func TestStore_ForkNextEpoch(t *testing.T) { require.NoError(t, err) require.NoError(t, f.InsertNode(ctx, state, blkRoot)) require.NoError(t, f.store.setUnrealizedJustifiedEpoch([32]byte{'d'}, 1)) + f.store.unrealizedJustifiedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: 1} f.UpdateUnrealizedCheckpoints() headRoot, err = f.Head(ctx, []uint64{100}) require.NoError(t, err) diff --git a/beacon-chain/forkchoice/interfaces.go b/beacon-chain/forkchoice/interfaces.go index c8f8d54d79..6a49c9b0d2 100644 --- a/beacon-chain/forkchoice/interfaces.go +++ b/beacon-chain/forkchoice/interfaces.go @@ -30,7 +30,7 @@ type HeadRetriever interface { // BlockProcessor processes the block that's used for accounting fork choice. type BlockProcessor interface { - InsertNode(context.Context, state.ReadOnlyBeaconState, [32]byte) error + InsertNode(context.Context, state.BeaconState, [32]byte) error InsertOptimisticChain(context.Context, []*forkchoicetypes.BlockAndCheckpoints) error } diff --git a/beacon-chain/forkchoice/protoarray/BUILD.bazel b/beacon-chain/forkchoice/protoarray/BUILD.bazel index aecef25c3f..807ccffaa1 100644 --- a/beacon-chain/forkchoice/protoarray/BUILD.bazel +++ b/beacon-chain/forkchoice/protoarray/BUILD.bazel @@ -22,9 +22,12 @@ go_library( ], deps = [ "//beacon-chain/core/blocks:go_default_library", + "//beacon-chain/core/epoch/precompute:go_default_library", + "//beacon-chain/core/time:go_default_library", "//beacon-chain/forkchoice:go_default_library", "//beacon-chain/forkchoice/types:go_default_library", "//beacon-chain/state:go_default_library", + "//config/features:go_default_library", "//config/fieldparams:go_default_library", "//config/params:go_default_library", "//consensus-types/primitives:go_default_library", diff --git a/beacon-chain/forkchoice/protoarray/on_tick.go b/beacon-chain/forkchoice/protoarray/on_tick.go index f2ed348d65..0b656a49ac 100644 --- a/beacon-chain/forkchoice/protoarray/on_tick.go +++ b/beacon-chain/forkchoice/protoarray/on_tick.go @@ -4,6 +4,7 @@ import ( "context" "github.com/pkg/errors" + "github.com/prysmaticlabs/prysm/config/features" types "github.com/prysmaticlabs/prysm/consensus-types/primitives" "github.com/prysmaticlabs/prysm/time/slots" ) @@ -64,5 +65,8 @@ func (f *ForkChoice) NewSlot(ctx context.Context, slot types.Slot) error { f.store.justifiedCheckpoint = bjcp } } + if features.Get().PullTips { + f.UpdateUnrealizedCheckpoints() + } return nil } diff --git a/beacon-chain/forkchoice/protoarray/store.go b/beacon-chain/forkchoice/protoarray/store.go index e58496e857..a62bef36aa 100644 --- a/beacon-chain/forkchoice/protoarray/store.go +++ b/beacon-chain/forkchoice/protoarray/store.go @@ -11,6 +11,7 @@ import ( "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice" forkchoicetypes "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/types" "github.com/prysmaticlabs/prysm/beacon-chain/state" + "github.com/prysmaticlabs/prysm/config/features" fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams" "github.com/prysmaticlabs/prysm/config/params" types "github.com/prysmaticlabs/prysm/consensus-types/primitives" @@ -30,17 +31,19 @@ const defaultPruneThreshold = 256 // New initializes a new fork choice store. func New() *ForkChoice { s := &Store{ - justifiedCheckpoint: &forkchoicetypes.Checkpoint{}, - bestJustifiedCheckpoint: &forkchoicetypes.Checkpoint{}, - prevJustifiedCheckpoint: &forkchoicetypes.Checkpoint{}, - finalizedCheckpoint: &forkchoicetypes.Checkpoint{}, - proposerBoostRoot: [32]byte{}, - nodes: make([]*Node, 0), - nodesIndices: make(map[[32]byte]uint64), - payloadIndices: make(map[[32]byte]uint64), - canonicalNodes: make(map[[32]byte]bool), - slashedIndices: make(map[types.ValidatorIndex]bool), - pruneThreshold: defaultPruneThreshold, + justifiedCheckpoint: &forkchoicetypes.Checkpoint{}, + bestJustifiedCheckpoint: &forkchoicetypes.Checkpoint{}, + unrealizedJustifiedCheckpoint: &forkchoicetypes.Checkpoint{}, + prevJustifiedCheckpoint: &forkchoicetypes.Checkpoint{}, + finalizedCheckpoint: &forkchoicetypes.Checkpoint{}, + unrealizedFinalizedCheckpoint: &forkchoicetypes.Checkpoint{}, + proposerBoostRoot: [32]byte{}, + nodes: make([]*Node, 0), + nodesIndices: make(map[[32]byte]uint64), + payloadIndices: make(map[[32]byte]uint64), + canonicalNodes: make(map[[32]byte]bool), + slashedIndices: make(map[types.ValidatorIndex]bool), + pruneThreshold: defaultPruneThreshold, } b := make([]uint64, 0) @@ -117,7 +120,7 @@ func (f *ForkChoice) ProposerBoost() [fieldparams.RootLength]byte { } // InsertNode processes a new block by inserting it to the fork choice store. -func (f *ForkChoice) InsertNode(ctx context.Context, state state.ReadOnlyBeaconState, root [32]byte) error { +func (f *ForkChoice) InsertNode(ctx context.Context, state state.BeaconState, root [32]byte) error { ctx, span := trace.StartSpan(ctx, "protoArrayForkChoice.InsertNode") defer span.End() @@ -147,10 +150,14 @@ func (f *ForkChoice) InsertNode(ctx context.Context, state state.ReadOnlyBeaconS return errInvalidNilCheckpoint } finalizedEpoch := fc.Epoch - err := f.store.insert(ctx, slot, root, parentRoot, payloadHash, justifiedEpoch, finalizedEpoch) + node, err := f.store.insert(ctx, slot, root, parentRoot, payloadHash, justifiedEpoch, finalizedEpoch) if err != nil { return err } + + if features.Get().PullTips { + jc, fc = f.store.pullTips(ctx, state, node, jc, fc) + } return f.updateCheckpoints(ctx, jc, fc) } @@ -462,7 +469,7 @@ func (s *Store) updateCanonicalNodes(ctx context.Context, root [32]byte) error { func (s *Store) insert(ctx context.Context, slot types.Slot, root, parent, payloadHash [32]byte, - justifiedEpoch, finalizedEpoch types.Epoch) error { + justifiedEpoch, finalizedEpoch types.Epoch) (*Node, error) { _, span := trace.StartSpan(ctx, "protoArrayForkChoice.insert") defer span.End() @@ -470,8 +477,8 @@ func (s *Store) insert(ctx context.Context, defer s.nodesLock.Unlock() // Return if the block has been inserted into Store before. - if _, ok := s.nodesIndices[root]; ok { - return nil + if idx, ok := s.nodesIndices[root]; ok { + return s.nodes[idx], nil } index := uint64(len(s.nodes)) @@ -502,7 +509,7 @@ func (s *Store) insert(ctx context.Context, // Apply proposer boost timeNow := uint64(time.Now().Unix()) if timeNow < s.genesisTime { - return nil + return n, nil } secondsIntoSlot := (timeNow - s.genesisTime) % params.BeaconConfig().SecondsPerSlot currentSlot := slots.CurrentSlot(s.genesisTime) @@ -516,7 +523,7 @@ func (s *Store) insert(ctx context.Context, // Update parent with the best child and descendant only if it's available. if n.parent != NonExistentNode { if err := s.updateBestChildAndDescendant(parentIndex, index); err != nil { - return err + return n, err } } @@ -524,7 +531,7 @@ func (s *Store) insert(ctx context.Context, processedBlockCount.Inc() nodeCount.Set(float64(len(s.nodes))) - return nil + return n, nil } // applyWeightChanges iterates backwards through the nodes in store. It checks all nodes parent @@ -991,7 +998,7 @@ func (f *ForkChoice) InsertOptimisticChain(ctx context.Context, chain []*forkcho if err != nil { return err } - if err := f.store.insert(ctx, + if _, err := f.store.insert(ctx, b.Slot(), r, parentRoot, payloadHash, chain[i].JustifiedCheckpoint.Epoch, chain[i].FinalizedCheckpoint.Epoch); err != nil { return err diff --git a/beacon-chain/forkchoice/protoarray/store_test.go b/beacon-chain/forkchoice/protoarray/store_test.go index 8e02ecd991..9adb40bf22 100644 --- a/beacon-chain/forkchoice/protoarray/store_test.go +++ b/beacon-chain/forkchoice/protoarray/store_test.go @@ -114,7 +114,8 @@ func TestStore_Head_ContextCancelled(t *testing.T) { func TestStore_Insert_UnknownParent(t *testing.T) { // The new node does not have a parent. s := &Store{nodesIndices: make(map[[32]byte]uint64), payloadIndices: make(map[[32]byte]uint64)} - require.NoError(t, s.insert(context.Background(), 100, [32]byte{'A'}, [32]byte{'B'}, params.BeaconConfig().ZeroHash, 1, 1)) + _, err := s.insert(context.Background(), 100, [32]byte{'A'}, [32]byte{'B'}, params.BeaconConfig().ZeroHash, 1, 1) + require.NoError(t, err) assert.Equal(t, 1, len(s.nodes), "Did not insert block") assert.Equal(t, 1, len(s.nodesIndices), "Did not insert block") assert.Equal(t, NonExistentNode, s.nodes[0].parent, "Incorrect parent") @@ -133,7 +134,8 @@ func TestStore_Insert_KnownParent(t *testing.T) { payloadHash := [32]byte{'c'} s.justifiedCheckpoint = &forkchoicetypes.Checkpoint{} s.finalizedCheckpoint = &forkchoicetypes.Checkpoint{} - require.NoError(t, s.insert(context.Background(), 100, [32]byte{'A'}, p, payloadHash, 1, 1)) + _, err := s.insert(context.Background(), 100, [32]byte{'A'}, p, payloadHash, 1, 1) + require.NoError(t, err) assert.Equal(t, 2, len(s.nodes), "Did not insert block") assert.Equal(t, 2, len(s.nodesIndices), "Did not insert block") assert.Equal(t, uint64(0), s.nodes[1].parent, "Incorrect parent") diff --git a/beacon-chain/forkchoice/protoarray/types.go b/beacon-chain/forkchoice/protoarray/types.go index 95e38160aa..a31325e517 100644 --- a/beacon-chain/forkchoice/protoarray/types.go +++ b/beacon-chain/forkchoice/protoarray/types.go @@ -18,25 +18,27 @@ type ForkChoice struct { // Store defines the fork choice store which includes block nodes and the last view of checkpoint information. type Store struct { - pruneThreshold uint64 // do not prune tree unless threshold is reached. - justifiedCheckpoint *forkchoicetypes.Checkpoint // latest justified checkpoint in store. - bestJustifiedCheckpoint *forkchoicetypes.Checkpoint // best justified checkpoint in store. - prevJustifiedCheckpoint *forkchoicetypes.Checkpoint // previous justified checkpoint in store. - finalizedCheckpoint *forkchoicetypes.Checkpoint // latest finalized checkpoint in store. - 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. - previousProposerBoostScore uint64 // previous proposer boosted root score. - nodes []*Node // list of block nodes, each node is a representation of one block. - nodesIndices map[[fieldparams.RootLength]byte]uint64 // the root of block node and the nodes index in the list. - canonicalNodes map[[fieldparams.RootLength]byte]bool // the canonical block nodes. - payloadIndices map[[fieldparams.RootLength]byte]uint64 // the payload hash of block node and the index in the list - slashedIndices map[types.ValidatorIndex]bool // The list of equivocating validators - originRoot [fieldparams.RootLength]byte // The genesis block root - lastHeadRoot [fieldparams.RootLength]byte // The last cached head block root - nodesLock sync.RWMutex - proposerBoostLock sync.RWMutex - checkpointsLock sync.RWMutex - genesisTime uint64 + pruneThreshold uint64 // do not prune tree unless threshold is reached. + justifiedCheckpoint *forkchoicetypes.Checkpoint // latest justified checkpoint in store. + bestJustifiedCheckpoint *forkchoicetypes.Checkpoint // best justified checkpoint in store. + unrealizedJustifiedCheckpoint *forkchoicetypes.Checkpoint // best justified checkpoint in store. + unrealizedFinalizedCheckpoint *forkchoicetypes.Checkpoint // best justified checkpoint in store. + prevJustifiedCheckpoint *forkchoicetypes.Checkpoint // previous justified checkpoint in store. + finalizedCheckpoint *forkchoicetypes.Checkpoint // latest finalized checkpoint in store. + 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. + previousProposerBoostScore uint64 // previous proposer boosted root score. + nodes []*Node // list of block nodes, each node is a representation of one block. + nodesIndices map[[fieldparams.RootLength]byte]uint64 // the root of block node and the nodes index in the list. + canonicalNodes map[[fieldparams.RootLength]byte]bool // the canonical block nodes. + payloadIndices map[[fieldparams.RootLength]byte]uint64 // the payload hash of block node and the index in the list + slashedIndices map[types.ValidatorIndex]bool // The list of equivocating validators + originRoot [fieldparams.RootLength]byte // The genesis block root + lastHeadRoot [fieldparams.RootLength]byte // The last cached head block root + nodesLock sync.RWMutex + proposerBoostLock sync.RWMutex + checkpointsLock sync.RWMutex + genesisTime uint64 } // Node defines the individual block which includes its block parent, ancestor and how much weight accounted for it. diff --git a/beacon-chain/forkchoice/protoarray/unrealized_justification.go b/beacon-chain/forkchoice/protoarray/unrealized_justification.go index eacff9a6e5..9665d3ec71 100644 --- a/beacon-chain/forkchoice/protoarray/unrealized_justification.go +++ b/beacon-chain/forkchoice/protoarray/unrealized_justification.go @@ -1,7 +1,16 @@ package protoarray import ( + "context" + + "github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute" + "github.com/prysmaticlabs/prysm/beacon-chain/core/time" + forkchoicetypes "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/types" + "github.com/prysmaticlabs/prysm/beacon-chain/state" types "github.com/prysmaticlabs/prysm/consensus-types/primitives" + "github.com/prysmaticlabs/prysm/encoding/bytesutil" + ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/time/slots" ) func (s *Store) setUnrealizedJustifiedEpoch(root [32]byte, epoch types.Epoch) error { @@ -56,10 +65,47 @@ func (f *ForkChoice) UpdateUnrealizedCheckpoints() { node.justifiedEpoch = node.unrealizedJustifiedEpoch node.finalizedEpoch = node.unrealizedFinalizedEpoch if node.justifiedEpoch > f.store.justifiedCheckpoint.Epoch { - f.store.justifiedCheckpoint.Epoch = node.justifiedEpoch + if node.justifiedEpoch > f.store.bestJustifiedCheckpoint.Epoch { + f.store.bestJustifiedCheckpoint = f.store.unrealizedJustifiedCheckpoint + } + f.store.justifiedCheckpoint = f.store.unrealizedJustifiedCheckpoint } if node.finalizedEpoch > f.store.finalizedCheckpoint.Epoch { - f.store.finalizedCheckpoint.Epoch = node.finalizedEpoch + f.store.justifiedCheckpoint = f.store.unrealizedJustifiedCheckpoint + f.store.finalizedCheckpoint = f.store.unrealizedFinalizedCheckpoint } } } + +func (s *Store) pullTips(ctx context.Context, state state.BeaconState, node *Node, jc, fc *ethpb.Checkpoint) (*ethpb.Checkpoint, *ethpb.Checkpoint) { + var uj, uf *ethpb.Checkpoint + uj, uf, err := precompute.UnrealizedCheckpoints(ctx, state) + if err != nil { + log.WithError(err).Debug("could not compute unrealized checkpoints") + uj, uf = jc, fc + } + node.unrealizedJustifiedEpoch, node.unrealizedFinalizedEpoch = uj.Epoch, uf.Epoch + s.checkpointsLock.Lock() + if uj.Epoch > s.unrealizedJustifiedCheckpoint.Epoch { + s.unrealizedJustifiedCheckpoint = &forkchoicetypes.Checkpoint{ + Epoch: uj.Epoch, Root: bytesutil.ToBytes32(uj.Root), + } + } + if uf.Epoch > s.unrealizedFinalizedCheckpoint.Epoch { + s.unrealizedJustifiedCheckpoint = &forkchoicetypes.Checkpoint{ + Epoch: uj.Epoch, Root: bytesutil.ToBytes32(uj.Root), + } + s.unrealizedFinalizedCheckpoint = &forkchoicetypes.Checkpoint{ + Epoch: uf.Epoch, Root: bytesutil.ToBytes32(uf.Root), + } + } + + currentSlot := slots.CurrentSlot(s.genesisTime) + if time.CurrentEpoch(state) < slots.ToEpoch(currentSlot) { + jc, fc = uj, uf + node.justifiedEpoch = uj.Epoch + node.finalizedEpoch = uf.Epoch + } + s.checkpointsLock.Unlock() + return jc, fc +} diff --git a/beacon-chain/forkchoice/protoarray/unrealized_justification_test.go b/beacon-chain/forkchoice/protoarray/unrealized_justification_test.go index db4367899f..68ded9dfd7 100644 --- a/beacon-chain/forkchoice/protoarray/unrealized_justification_test.go +++ b/beacon-chain/forkchoice/protoarray/unrealized_justification_test.go @@ -147,6 +147,8 @@ func TestStore_NoDeadLock(t *testing.T) { require.NoError(t, f.InsertNode(ctx, state, blkRoot)) require.NoError(t, f.store.setUnrealizedJustifiedEpoch([32]byte{'g'}, 2)) require.NoError(t, f.store.setUnrealizedFinalizedEpoch([32]byte{'g'}, 1)) + f.store.unrealizedJustifiedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: 2} + f.store.unrealizedFinalizedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: 1} state, blkRoot, err = prepareForkchoiceState(ctx, 107, [32]byte{'h'}, [32]byte{'g'}, [32]byte{'H'}, 0, 0) require.NoError(t, err) require.NoError(t, f.InsertNode(ctx, state, blkRoot)) @@ -236,6 +238,7 @@ func TestStore_ForkNextEpoch(t *testing.T) { require.NoError(t, err) require.NoError(t, f.InsertNode(ctx, state, blkRoot)) require.NoError(t, f.store.setUnrealizedJustifiedEpoch([32]byte{'d'}, 1)) + f.store.unrealizedJustifiedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: 1} f.UpdateUnrealizedCheckpoints() headRoot, err = f.Head(ctx, []uint64{100}) require.NoError(t, err) diff --git a/beacon-chain/state/state-native/getters_participation.go b/beacon-chain/state/state-native/getters_participation.go index e58e58a4f9..a8de9727f4 100644 --- a/beacon-chain/state/state-native/getters_participation.go +++ b/beacon-chain/state/state-native/getters_participation.go @@ -46,6 +46,7 @@ func (b *BeaconState) UnrealizedCheckpointBalances() (uint64, uint64, uint64, er return 0, 0, 0, errNotSupported("UnrealizedCheckpointBalances", b.version) } + currentEpoch := time.CurrentEpoch(b) b.lock.RLock() defer b.lock.RUnlock() @@ -55,7 +56,6 @@ func (b *BeaconState) UnrealizedCheckpointBalances() (uint64, uint64, uint64, er return 0, 0, 0, ErrNilParticipation } - currentEpoch := time.CurrentEpoch(b) return stateutil.UnrealizedCheckpointBalances(cp, pp, b.validators, currentEpoch) } diff --git a/beacon-chain/state/stateutil/unrealized_justification.go b/beacon-chain/state/stateutil/unrealized_justification.go index 78dd0e6a52..3942613ec2 100644 --- a/beacon-chain/state/stateutil/unrealized_justification.go +++ b/beacon-chain/state/stateutil/unrealized_justification.go @@ -8,6 +8,11 @@ import ( ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1" ) +// UnrealizedCheckpointBalances returns the total current active balance, the +// total previous epoch correctly attested for target balance, and the total +// current epoch correctly attested for target balance. It takes the current and +// previous epoch participation bits as parameters so implicitly only works for +// beacon states post-Altair. func UnrealizedCheckpointBalances(cp, pp []byte, validators []*ethpb.Validator, currentEpoch types.Epoch) (uint64, uint64, uint64, error) { targetIdx := params.BeaconConfig().TimelyTargetFlagIndex activeBalance := uint64(0) diff --git a/beacon-chain/state/v2/getters_participation.go b/beacon-chain/state/v2/getters_participation.go index d5de0b4b13..90009b88c0 100644 --- a/beacon-chain/state/v2/getters_participation.go +++ b/beacon-chain/state/v2/getters_participation.go @@ -42,6 +42,7 @@ func (b *BeaconState) UnrealizedCheckpointBalances() (uint64, uint64, uint64, er if !b.hasInnerState() { return 0, 0, 0, ErrNilInnerState } + currentEpoch := time.CurrentEpoch(b) b.lock.RLock() defer b.lock.RUnlock() @@ -50,7 +51,6 @@ func (b *BeaconState) UnrealizedCheckpointBalances() (uint64, uint64, uint64, er if cp == nil || pp == nil { return 0, 0, 0, ErrNilParticipation } - currentEpoch := time.CurrentEpoch(b) return stateutil.UnrealizedCheckpointBalances(cp, pp, b.state.Validators, currentEpoch) } diff --git a/beacon-chain/state/v3/getters_participation.go b/beacon-chain/state/v3/getters_participation.go index c1f62383bb..c24fbde626 100644 --- a/beacon-chain/state/v3/getters_participation.go +++ b/beacon-chain/state/v3/getters_participation.go @@ -42,6 +42,7 @@ func (b *BeaconState) UnrealizedCheckpointBalances() (uint64, uint64, uint64, er if !b.hasInnerState() { return 0, 0, 0, ErrNilInnerState } + currentEpoch := time.CurrentEpoch(b) b.lock.RLock() defer b.lock.RUnlock() @@ -50,7 +51,6 @@ func (b *BeaconState) UnrealizedCheckpointBalances() (uint64, uint64, uint64, er if cp == nil || pp == nil { return 0, 0, 0, ErrNilParticipation } - currentEpoch := time.CurrentEpoch(b) return stateutil.UnrealizedCheckpointBalances(cp, pp, b.state.Validators, currentEpoch) } diff --git a/config/features/config.go b/config/features/config.go index 22c395f1d5..cf8664ca20 100644 --- a/config/features/config.go +++ b/config/features/config.go @@ -61,6 +61,7 @@ type Flags struct { EnableSlashingProtectionPruning bool EnableNativeState bool // EnableNativeState defines whether the beacon state will be represented as a pure Go struct or a Go struct that wraps a proto struct. + PullTips bool // Experimental disable of boundary checks EnableVectorizedHTR bool // EnableVectorizedHTR specifies whether the beacon state will use the optimized sha256 routines. EnableForkChoiceDoublyLinkedTree bool // EnableForkChoiceDoublyLinkedTree specifies whether fork choice store will use a doubly linked tree. EnableBatchGossipAggregation bool // EnableBatchGossipAggregation specifies whether to further aggregate our gossip batches before verifying them. @@ -211,6 +212,10 @@ func ConfigureBeaconChain(ctx *cli.Context) error { logDisabled(disableNativeState) cfg.EnableNativeState = false } + if ctx.Bool(pullTips.Name) { + logEnabled(pullTips) + cfg.PullTips = true + } if ctx.Bool(enableVecHTR.Name) { logEnabled(enableVecHTR) cfg.EnableVectorizedHTR = true diff --git a/config/features/flags.go b/config/features/flags.go index 7029406bc0..84425d0f78 100644 --- a/config/features/flags.go +++ b/config/features/flags.go @@ -105,6 +105,12 @@ var ( Name: "disable-native-state", Usage: "Disables representing the beacon state as a pure Go struct.", } + + pullTips = &cli.BoolFlag{ + Name: "experimental-disable-boundary-checks", + Usage: "Experimental disable of boundary checks, useful for debugging, may cause bad votes.", + } + enableVecHTR = &cli.BoolFlag{ Name: "enable-vectorized-htr", Usage: "Enables new go sha256 library which utilizes optimized routines for merkle trees", @@ -163,6 +169,7 @@ var BeaconChainFlags = append(deprecatedFlags, []cli.Flag{ enableSlasherFlag, enableHistoricalSpaceRepresentation, disableNativeState, + pullTips, enableVecHTR, enableForkChoiceDoublyLinkedTree, enableGossipBatchAggregation, diff --git a/testing/spectest/shared/common/forkchoice/service.go b/testing/spectest/shared/common/forkchoice/service.go index 20b786bea9..77592826ee 100644 --- a/testing/spectest/shared/common/forkchoice/service.go +++ b/testing/spectest/shared/common/forkchoice/service.go @@ -31,12 +31,12 @@ func startChainService(t testing.TB, st state.BeaconState, block interfaces.Sign r, err := block.Block().HashTreeRoot() require.NoError(t, err) require.NoError(t, db.SaveGenesisBlockRoot(ctx, r)) - require.NoError(t, db.SaveState(ctx, st, r)) + cp := ðpb.Checkpoint{ Epoch: coreTime.CurrentEpoch(st), Root: r[:], } - + require.NoError(t, db.SaveState(ctx, st, r)) require.NoError(t, db.SaveJustifiedCheckpoint(ctx, cp)) require.NoError(t, db.SaveFinalizedCheckpoint(ctx, cp)) attPool, err := attestations.NewService(ctx, &attestations.Config{