Compare commits

..

10 Commits

Author SHA1 Message Date
Potuz
b82ec00778 init 2022-06-09 08:48:33 -03:00
Potuz
8562af7754 Terence's review 2022-06-08 10:28:04 -03:00
Potuz
42e4d5ea2c Merge branch 'develop' into forkchoice_checkpoints 2022-06-07 21:44:08 -03:00
Potuz
7414e9abcf more conflicts 2022-06-07 13:56:07 -03:00
Potuz
4db40cafcc more conflicts 2022-06-06 17:18:52 -03:00
Potuz
0587d9077a Merge remote-tracking branch 'origin/develop' into forkchoice_checkpoints 2022-06-06 17:07:50 -03:00
Potuz
70647aa321 spec tests and debug rpc fixes 2022-06-05 15:24:37 -03:00
Potuz
d8a36384f8 beacon-chain changes 2022-06-05 15:05:07 -03:00
Potuz
1a5c3cb49d protoarray changes 2022-06-05 15:05:07 -03:00
Potuz
572cc82ebc double_tree_changes 2022-06-05 15:05:07 -03:00
93 changed files with 734 additions and 614 deletions

View File

@@ -12,6 +12,7 @@ import (
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/encoding/ssz/detect"
"github.com/prysmaticlabs/prysm/io/file"
"github.com/prysmaticlabs/prysm/runtime/version"
"github.com/prysmaticlabs/prysm/time/slots"
log "github.com/sirupsen/logrus"
"golang.org/x/mod/semver"
@@ -55,7 +56,7 @@ func (o *OriginData) BlockBytes() []byte {
}
func fname(prefix string, vu *detect.VersionedUnmarshaler, slot types.Slot, root [32]byte) string {
return fmt.Sprintf("%s_%s_%s_%d-%#x.ssz", prefix, vu.Config.ConfigName, vu.Fork.String(), slot, root)
return fmt.Sprintf("%s_%s_%s_%d-%#x.ssz", prefix, vu.Config.ConfigName, version.String(vu.Fork), slot, root)
}
// DownloadFinalizedData downloads the most recently finalized state, and the block most recently applied to that state.
@@ -69,7 +70,7 @@ func DownloadFinalizedData(ctx context.Context, client *Client) (*OriginData, er
if err != nil {
return nil, errors.Wrap(err, "error detecting chain config for finalized state")
}
log.Printf("detected supported config in remote finalized state, name=%s, fork=%s", vu.Config.ConfigName, vu.Fork.String())
log.Printf("detected supported config in remote finalized state, name=%s, fork=%s", vu.Config.ConfigName, version.String(vu.Fork))
s, err := vu.UnmarshalBeaconState(sb)
if err != nil {
return nil, errors.Wrap(err, "error unmarshaling finalized state to correct version")
@@ -193,7 +194,7 @@ func computeBackwardsCompatible(ctx context.Context, client *Client) (*WeakSubje
if err != nil {
return nil, errors.Wrap(err, "error detecting chain config for beacon state")
}
log.Printf("detected supported config in checkpoint state, name=%s, fork=%s", vu.Config.ConfigName, vu.Fork.String())
log.Printf("detected supported config in checkpoint state, name=%s, fork=%s", vu.Config.ConfigName, version.String(vu.Fork))
s, err := vu.UnmarshalBeaconState(sb)
if err != nil {
@@ -244,7 +245,7 @@ func getWeakSubjectivityEpochFromHead(ctx context.Context, client *Client) (type
if err != nil {
return 0, errors.Wrap(err, "error detecting chain config for beacon state")
}
log.Printf("detected supported config in remote head state, name=%s, fork=%s", vu.Config.ConfigName, vu.Fork.String())
log.Printf("detected supported config in remote head state, name=%s, fork=%s", vu.Config.ConfigName, version.String(vu.Fork))
headState, err := vu.UnmarshalBeaconState(headBytes)
if err != nil {
return 0, errors.Wrap(err, "error unmarshaling state to correct version")

View File

@@ -80,9 +80,9 @@ func TestHeadRoot_Nil(t *testing.T) {
}
func TestService_ForkChoiceStore(t *testing.T) {
c := &Service{cfg: &config{ForkChoiceStore: doublylinkedtree.New(0, 0)}}
c := &Service{cfg: &config{ForkChoiceStore: doublylinkedtree.New()}}
p := c.ForkChoiceStore()
require.Equal(t, 0, int(p.FinalizedEpoch()))
require.Equal(t, types.Epoch(0), p.FinalizedCheckpoint().Epoch)
}
func TestFinalizedCheckpt_CanRetrieve(t *testing.T) {
@@ -327,7 +327,7 @@ func TestService_HeadGenesisValidatorsRoot(t *testing.T) {
}
func TestService_ChainHeads_ProtoArray(t *testing.T) {
ctx := context.Background()
c := &Service{cfg: &config{ForkChoiceStore: protoarray.New(0, 0)}}
c := &Service{cfg: &config{ForkChoiceStore: protoarray.New()}}
state, blkRoot, err := prepareForkchoiceState(ctx, 100, [32]byte{'a'}, [32]byte{}, params.BeaconConfig().ZeroHash, 0, 0)
require.NoError(t, err)
require.NoError(t, c.cfg.ForkChoiceStore.InsertNode(ctx, state, blkRoot))
@@ -357,7 +357,7 @@ func TestService_ChainHeads_ProtoArray(t *testing.T) {
func TestService_ChainHeads_DoublyLinkedTree(t *testing.T) {
ctx := context.Background()
c := &Service{cfg: &config{ForkChoiceStore: doublylinkedtree.New(0, 0)}}
c := &Service{cfg: &config{ForkChoiceStore: doublylinkedtree.New()}}
state, blkRoot, err := prepareForkchoiceState(ctx, 0, [32]byte{}, [32]byte{}, params.BeaconConfig().ZeroHash, 0, 0)
require.NoError(t, err)
require.NoError(t, c.cfg.ForkChoiceStore.InsertNode(ctx, state, blkRoot))
@@ -452,7 +452,7 @@ func TestService_IsOptimistic_ProtoArray(t *testing.T) {
params.OverrideBeaconConfig(cfg)
ctx := context.Background()
c := &Service{cfg: &config{ForkChoiceStore: protoarray.New(0, 0)}, head: &head{slot: 101, root: [32]byte{'b'}}}
c := &Service{cfg: &config{ForkChoiceStore: protoarray.New()}, head: &head{slot: 101, root: [32]byte{'b'}}}
state, blkRoot, err := prepareForkchoiceState(ctx, 100, [32]byte{'a'}, [32]byte{}, params.BeaconConfig().ZeroHash, 0, 0)
require.NoError(t, err)
require.NoError(t, c.cfg.ForkChoiceStore.InsertNode(ctx, state, blkRoot))
@@ -472,7 +472,7 @@ func TestService_IsOptimistic_DoublyLinkedTree(t *testing.T) {
params.OverrideBeaconConfig(cfg)
ctx := context.Background()
c := &Service{cfg: &config{ForkChoiceStore: doublylinkedtree.New(0, 0)}, head: &head{slot: 101, root: [32]byte{'b'}}}
c := &Service{cfg: &config{ForkChoiceStore: doublylinkedtree.New()}, head: &head{slot: 101, root: [32]byte{'b'}}}
state, blkRoot, err := prepareForkchoiceState(ctx, 100, [32]byte{'a'}, [32]byte{}, params.BeaconConfig().ZeroHash, 0, 0)
require.NoError(t, err)
require.NoError(t, c.cfg.ForkChoiceStore.InsertNode(ctx, state, blkRoot))
@@ -495,7 +495,7 @@ func TestService_IsOptimisticBeforeBellatrix(t *testing.T) {
func TestService_IsOptimisticForRoot_ProtoArray(t *testing.T) {
ctx := context.Background()
c := &Service{cfg: &config{ForkChoiceStore: protoarray.New(0, 0)}, head: &head{slot: 101, root: [32]byte{'b'}}}
c := &Service{cfg: &config{ForkChoiceStore: protoarray.New()}, head: &head{slot: 101, root: [32]byte{'b'}}}
state, blkRoot, err := prepareForkchoiceState(ctx, 100, [32]byte{'a'}, [32]byte{}, params.BeaconConfig().ZeroHash, 0, 0)
require.NoError(t, err)
require.NoError(t, c.cfg.ForkChoiceStore.InsertNode(ctx, state, blkRoot))
@@ -510,7 +510,7 @@ func TestService_IsOptimisticForRoot_ProtoArray(t *testing.T) {
func TestService_IsOptimisticForRoot_DoublyLinkedTree(t *testing.T) {
ctx := context.Background()
c := &Service{cfg: &config{ForkChoiceStore: doublylinkedtree.New(0, 0)}, head: &head{slot: 101, root: [32]byte{'b'}}}
c := &Service{cfg: &config{ForkChoiceStore: doublylinkedtree.New()}, head: &head{slot: 101, root: [32]byte{'b'}}}
state, blkRoot, err := prepareForkchoiceState(ctx, 100, [32]byte{'a'}, [32]byte{}, params.BeaconConfig().ZeroHash, 0, 0)
require.NoError(t, err)
require.NoError(t, c.cfg.ForkChoiceStore.InsertNode(ctx, state, blkRoot))
@@ -526,7 +526,7 @@ func TestService_IsOptimisticForRoot_DoublyLinkedTree(t *testing.T) {
func TestService_IsOptimisticForRoot_DB_ProtoArray(t *testing.T) {
beaconDB := testDB.SetupDB(t)
ctx := context.Background()
c := &Service{cfg: &config{BeaconDB: beaconDB, ForkChoiceStore: protoarray.New(0, 0)}, head: &head{slot: 101, root: [32]byte{'b'}}}
c := &Service{cfg: &config{BeaconDB: beaconDB, ForkChoiceStore: protoarray.New()}, head: &head{slot: 101, root: [32]byte{'b'}}}
c.head = &head{root: params.BeaconConfig().ZeroHash}
b := util.NewBeaconBlock()
b.Block.Slot = 10
@@ -591,7 +591,7 @@ func TestService_IsOptimisticForRoot_DB_ProtoArray(t *testing.T) {
func TestService_IsOptimisticForRoot_DB_DoublyLinkedTree(t *testing.T) {
beaconDB := testDB.SetupDB(t)
ctx := context.Background()
c := &Service{cfg: &config{BeaconDB: beaconDB, ForkChoiceStore: doublylinkedtree.New(0, 0)}, head: &head{slot: 101, root: [32]byte{'b'}}}
c := &Service{cfg: &config{BeaconDB: beaconDB, ForkChoiceStore: doublylinkedtree.New()}, head: &head{slot: 101, root: [32]byte{'b'}}}
c.head = &head{root: params.BeaconConfig().ZeroHash}
b := util.NewBeaconBlock()
b.Block.Slot = 10
@@ -655,7 +655,7 @@ func TestService_IsOptimisticForRoot_DB_DoublyLinkedTree(t *testing.T) {
func TestService_IsOptimisticForRoot_DB_non_canonical(t *testing.T) {
beaconDB := testDB.SetupDB(t)
ctx := context.Background()
c := &Service{cfg: &config{BeaconDB: beaconDB, ForkChoiceStore: doublylinkedtree.New(0, 0)}, head: &head{slot: 101, root: [32]byte{'b'}}}
c := &Service{cfg: &config{BeaconDB: beaconDB, ForkChoiceStore: doublylinkedtree.New()}, head: &head{slot: 101, root: [32]byte{'b'}}}
c.head = &head{root: params.BeaconConfig().ZeroHash}
b := util.NewBeaconBlock()
b.Block.Slot = 10

View File

@@ -19,7 +19,6 @@ import (
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/runtime/version"
"github.com/prysmaticlabs/prysm/time/slots"
"github.com/sirupsen/logrus"
"go.opencensus.io/trace"
@@ -142,7 +141,7 @@ func (s *Service) getPayloadHash(ctx context.Context, root []byte) ([32]byte, er
if err != nil {
return [32]byte{}, err
}
if blk.Block().Version().IsPreBellatrix() {
if blocks.IsPreBellatrixVersion(blk.Block().Version()) {
return params.BeaconConfig().ZeroHash, nil
}
payload, err := blk.Block().Body().ExecutionPayload()
@@ -154,14 +153,14 @@ func (s *Service) getPayloadHash(ctx context.Context, root []byte) ([32]byte, er
// notifyForkchoiceUpdate signals execution engine on a new payload.
// It returns true if the EL has returned VALID for the block
func (s *Service) notifyNewPayload(ctx context.Context, postStateVersion version.ForkVersion,
func (s *Service) notifyNewPayload(ctx context.Context, postStateVersion int,
postStateHeader *ethpb.ExecutionPayloadHeader, blk interfaces.SignedBeaconBlock) (bool, error) {
ctx, span := trace.StartSpan(ctx, "blockChain.notifyNewPayload")
defer span.End()
// Execution payload is only supported in Bellatrix and beyond. Pre
// merge blocks are never optimistic
if postStateVersion.IsPreBellatrix() {
if blocks.IsPreBellatrixVersion(postStateVersion) {
return true, nil
}
if err := wrapper.BeaconBlockIsNil(blk); err != nil {

View File

@@ -11,6 +11,7 @@ import (
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
doublylinkedtree "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/doubly-linked-tree"
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
forkchoicetypes "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/types"
"github.com/prysmaticlabs/prysm/beacon-chain/powchain"
mockPOW "github.com/prysmaticlabs/prysm/beacon-chain/powchain/testing"
bstate "github.com/prysmaticlabs/prysm/beacon-chain/state"
@@ -43,7 +44,7 @@ func Test_NotifyForkchoiceUpdate(t *testing.T) {
require.NoError(t, err)
require.NoError(t, beaconDB.SaveBlock(ctx, altairBlk))
require.NoError(t, beaconDB.SaveBlock(ctx, bellatrixBlk))
fcs := protoarray.New(0, 0)
fcs := protoarray.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -184,7 +185,7 @@ func Test_NotifyForkchoiceUpdate(t *testing.T) {
st, _ := util.DeterministicGenesisState(t, 1)
require.NoError(t, beaconDB.SaveState(ctx, st, tt.finalizedRoot))
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, tt.finalizedRoot))
fc := &ethpb.Checkpoint{Epoch: 1, Root: tt.finalizedRoot[:]}
fc := &ethpb.Checkpoint{Epoch: 0, Root: tt.finalizedRoot[:]}
service.store.SetFinalizedCheckptAndPayloadHash(fc, [32]byte{'a'})
service.store.SetJustifiedCheckptAndPayloadHash(fc, [32]byte{'b'})
arg := &notifyForkchoiceUpdateArg{
@@ -289,7 +290,7 @@ func Test_NotifyForkchoiceUpdateRecursive(t *testing.T) {
require.NoError(t, beaconDB.SaveBlock(ctx, wbg))
// Insert blocks into forkchoice
fcs := doublylinkedtree.New(0, 0)
fcs := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -326,7 +327,9 @@ func Test_NotifyForkchoiceUpdateRecursive(t *testing.T) {
fcs.ProcessAttestation(ctx, []uint64{0}, brd, 1)
fcs.ProcessAttestation(ctx, []uint64{1}, brf, 1)
fcs.ProcessAttestation(ctx, []uint64{2}, brg, 1)
headRoot, err := fcs.Head(ctx, bra, []uint64{50, 100, 200})
jc := &forkchoicetypes.Checkpoint{Epoch: 0, Root: bra}
require.NoError(t, fcs.UpdateJustifiedCheckpoint(jc))
headRoot, err := fcs.Head(ctx, []uint64{50, 100, 200})
require.NoError(t, err)
require.Equal(t, brg, headRoot)
@@ -347,7 +350,7 @@ func Test_NotifyForkchoiceUpdateRecursive(t *testing.T) {
_, err = service.notifyForkchoiceUpdate(ctx, a)
require.ErrorIs(t, ErrInvalidPayload, err)
// Ensure Head is D
headRoot, err = fcs.Head(ctx, bra, service.justifiedBalances.balances)
headRoot, err = fcs.Head(ctx, service.justifiedBalances.balances)
require.NoError(t, err)
require.Equal(t, brd, headRoot)
@@ -364,7 +367,7 @@ func Test_NotifyNewPayload(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0)
fcs := protoarray.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -582,7 +585,7 @@ func Test_NotifyNewPayload_SetOptimisticToValid(t *testing.T) {
params.OverrideBeaconConfig(cfg)
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0)
fcs := protoarray.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -625,7 +628,7 @@ func Test_IsOptimisticCandidateBlock(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0)
fcs := protoarray.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -827,7 +830,7 @@ func Test_UpdateLastValidatedCheckpoint(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
stateGen := stategen.New(beaconDB)
fcs := protoarray.New(0, 0)
fcs := protoarray.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stateGen),
@@ -927,7 +930,7 @@ func TestService_removeInvalidBlockAndState(t *testing.T) {
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
WithForkChoiceStore(protoarray.New(0, 0)),
WithForkChoiceStore(protoarray.New()),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
@@ -983,7 +986,7 @@ func TestService_getPayloadHash(t *testing.T) {
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
WithForkChoiceStore(protoarray.New(0, 0)),
WithForkChoiceStore(protoarray.New()),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)

View File

@@ -12,6 +12,7 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice"
doublylinkedtree "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/doubly-linked-tree"
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
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"
@@ -95,16 +96,23 @@ func (s *Service) updateHead(ctx context.Context, balances []uint64) ([32]byte,
return [32]byte{}, err
}
if features.Get().EnableForkChoiceDoublyLinkedTree {
s.cfg.ForkChoiceStore = doublylinkedtree.New(j.Epoch, f.Epoch)
s.cfg.ForkChoiceStore = doublylinkedtree.New()
} else {
s.cfg.ForkChoiceStore = protoarray.New(j.Epoch, f.Epoch)
s.cfg.ForkChoiceStore = protoarray.New()
}
if err := s.insertBlockToForkChoiceStore(ctx, jb.Block(), headStartRoot, st, f, j); err != nil {
return [32]byte{}, err
}
}
return s.cfg.ForkChoiceStore.Head(ctx, headStartRoot, balances)
jc := &forkchoicetypes.Checkpoint{Epoch: j.Epoch, Root: headStartRoot}
fc := &forkchoicetypes.Checkpoint{Epoch: f.Epoch, Root: s.ensureRootNotZeros(bytesutil.ToBytes32(f.Root))}
if err := s.cfg.ForkChoiceStore.UpdateJustifiedCheckpoint(jc); err != nil {
return [32]byte{}, err
}
if err := s.cfg.ForkChoiceStore.UpdateFinalizedCheckpoint(fc); err != nil {
return [32]byte{}, err
}
return s.cfg.ForkChoiceStore.Head(ctx, balances)
}
// This saves head info to the local service cache, it also saves the

View File

@@ -174,10 +174,8 @@ func TestUpdateHead_MissingJustifiedRoot(t *testing.T) {
service.store.SetJustifiedCheckptAndPayloadHash(&ethpb.Checkpoint{Root: r[:]}, [32]byte{'a'})
service.store.SetFinalizedCheckptAndPayloadHash(&ethpb.Checkpoint{}, [32]byte{'b'})
service.store.SetBestJustifiedCheckpt(&ethpb.Checkpoint{})
headRoot, err := service.updateHead(context.Background(), []uint64{})
_, err = service.updateHead(context.Background(), []uint64{})
require.NoError(t, err)
st, _ := util.DeterministicGenesisState(t, 1)
require.NoError(t, service.saveHead(context.Background(), headRoot, wsb, st))
}
func Test_notifyNewHeadEvent(t *testing.T) {
@@ -613,7 +611,7 @@ func TestUpdateHead_noSavedChanges(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := doublylinkedtree.New(0, 0)
fcs := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -630,7 +628,7 @@ func TestUpdateHead_noSavedChanges(t *testing.T) {
require.NoError(t, beaconDB.SaveBlock(ctx, bellatrixBlk))
fcp := &ethpb.Checkpoint{
Root: bellatrixBlkRoot[:],
Epoch: 1,
Epoch: 0,
}
service.store.SetFinalizedCheckptAndPayloadHash(fcp, [32]byte{'a'})
service.store.SetJustifiedCheckptAndPayloadHash(fcp, [32]byte{'b'})

View File

@@ -67,7 +67,7 @@ func logBlockSyncStatus(block interfaces.BeaconBlock, blockRoot [32]byte, justif
log = log.WithField("justifiedEpoch", justified.Epoch)
log = log.WithField("justifiedRoot", fmt.Sprintf("0x%s...", hex.EncodeToString(justified.Root)[:8]))
log = log.WithField("parentRoot", fmt.Sprintf("0x%s...", hex.EncodeToString(block.ParentRoot())[:8]))
log = log.WithField("version", block.Version().String())
log = log.WithField("version", version.String(block.Version()))
log = log.WithField("sinceSlotStartTime", prysmTime.Now().Sub(startTime))
log = log.WithField("chainServiceProcessedTime", prysmTime.Now().Sub(receivedTime))
}

View File

@@ -14,6 +14,7 @@ import (
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/runtime/version"
)
var (
@@ -265,8 +266,8 @@ func reportEpochMetrics(ctx context.Context, postState, headState state.BeaconSt
var b *precompute.Balance
var v []*precompute.Validator
var err error
switch {
case headState.Version().IsPhase0Compatible():
switch headState.Version() {
case version.Phase0:
// Validator participation should be viewed on the canonical chain.
v, b, err = precompute.New(ctx, headState)
if err != nil {
@@ -276,7 +277,7 @@ func reportEpochMetrics(ctx context.Context, postState, headState state.BeaconSt
if err != nil {
return err
}
case headState.Version().IsParticipationBitsCompatible():
case version.Altair, version.Bellatrix:
v, b, err = altair.InitializePrecomputeValidators(ctx, headState)
if err != nil {
return err

View File

@@ -13,7 +13,7 @@ import (
func testServiceOptsWithDB(t *testing.T) []Option {
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0)
fcs := protoarray.New()
return []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),

View File

@@ -5,7 +5,9 @@ import (
"context"
"github.com/pkg/errors"
forkchoicetypes "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/types"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/time/slots"
)
@@ -68,7 +70,8 @@ func (s *Service) NewSlot(ctx context.Context, slot types.Slot) error {
return err
}
s.store.SetJustifiedCheckptAndPayloadHash(bj, h)
if err := s.cfg.ForkChoiceStore.UpdateJustifiedCheckpoint(bj); err != nil {
if err := s.cfg.ForkChoiceStore.UpdateJustifiedCheckpoint(&forkchoicetypes.Checkpoint{
Epoch: bj.Epoch, Root: bytesutil.ToBytes32(bj.Root)}); err != nil {
return err
}
}

View File

@@ -20,7 +20,7 @@ import (
func TestService_newSlot(t *testing.T) {
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0)
fcs := protoarray.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),

View File

@@ -109,7 +109,7 @@ func Test_validateMergeBlock(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0)
fcs := protoarray.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -152,7 +152,7 @@ func Test_validateMergeBlock(t *testing.T) {
func Test_getBlkParentHashAndTD(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0)
fcs := protoarray.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),

View File

@@ -9,6 +9,7 @@ import (
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
doublylinkedtree "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/doubly-linked-tree"
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
forkchoicetypes "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/types"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
"github.com/prysmaticlabs/prysm/config/params"
@@ -28,7 +29,7 @@ func TestStore_OnAttestation_ErrorConditions_ProtoArray(t *testing.T) {
opts := []Option{
WithDatabase(beaconDB),
WithForkChoiceStore(protoarray.New(0, 0)),
WithForkChoiceStore(protoarray.New()),
WithStateGen(stategen.New(beaconDB)),
}
service, err := NewService(ctx, opts...)
@@ -140,7 +141,7 @@ func TestStore_OnAttestation_ErrorConditions_DoublyLinkedTree(t *testing.T) {
opts := []Option{
WithDatabase(beaconDB),
WithForkChoiceStore(doublylinkedtree.New(0, 0)),
WithForkChoiceStore(doublylinkedtree.New()),
WithStateGen(stategen.New(beaconDB)),
}
service, err := NewService(ctx, opts...)
@@ -250,7 +251,7 @@ func TestStore_OnAttestation_Ok_ProtoArray(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0)
fcs := protoarray.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -278,7 +279,7 @@ func TestStore_OnAttestation_Ok_DoublyLinkedTree(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := doublylinkedtree.New(0, 0)
fcs := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -487,7 +488,7 @@ func TestVerifyFinalizedConsistency_InconsistentRoot_ProtoArray(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0)
fcs := protoarray.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -522,7 +523,7 @@ func TestVerifyFinalizedConsistency_InconsistentRoot_DoublyLinkedTree(t *testing
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := doublylinkedtree.New(0, 0)
fcs := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -610,7 +611,9 @@ func TestVerifyFinalizedConsistency_IsCanonical(t *testing.T) {
require.NoError(t, err)
require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, state, blkRoot))
_, err = service.cfg.ForkChoiceStore.Head(ctx, r32, []uint64{})
jc := &forkchoicetypes.Checkpoint{Epoch: 0, Root: r32}
require.NoError(t, service.cfg.ForkChoiceStore.UpdateJustifiedCheckpoint(jc))
_, err = service.cfg.ForkChoiceStore.Head(ctx, []uint64{})
require.NoError(t, err)
err = service.VerifyFinalizedConsistency(context.Background(), r33[:])
require.NoError(t, err)

View File

@@ -222,10 +222,12 @@ func (s *Service) onBlock(ctx context.Context, signed interfaces.SignedBeaconBlo
}
s.store.SetJustifiedCheckptAndPayloadHash(postState.CurrentJustifiedCheckpoint(), h)
// Update Forkchoice checkpoints
if err := s.cfg.ForkChoiceStore.UpdateJustifiedCheckpoint(psj); err != nil {
if err := s.cfg.ForkChoiceStore.UpdateJustifiedCheckpoint(&forkchoicetypes.Checkpoint{
Epoch: psj.Epoch, Root: bytesutil.ToBytes32(psj.Root)}); err != nil {
return err
}
if err := s.cfg.ForkChoiceStore.UpdateFinalizedCheckpoint(psf); err != nil {
if err := s.cfg.ForkChoiceStore.UpdateFinalizedCheckpoint(&forkchoicetypes.Checkpoint{
Epoch: psf.Epoch, Root: bytesutil.ToBytes32(psf.Root)}); err != nil {
return err
}
}
@@ -317,15 +319,15 @@ func (s *Service) onBlock(ctx context.Context, signed interfaces.SignedBeaconBlo
return s.handleEpochBoundary(ctx, postState)
}
func getStateVersionAndPayload(st state.BeaconState) (version.ForkVersion, *ethpb.ExecutionPayloadHeader, error) {
func getStateVersionAndPayload(st state.BeaconState) (int, *ethpb.ExecutionPayloadHeader, error) {
if st == nil {
return 0, nil, errors.New("nil state")
}
var preStateHeader *ethpb.ExecutionPayloadHeader
var err error
preStateVersion := st.Version()
switch {
case preStateVersion.IsPreBellatrix():
switch preStateVersion {
case version.Phase0, version.Altair:
default:
preStateHeader, err = st.LatestExecutionPayloadHeader()
if err != nil {
@@ -378,7 +380,7 @@ func (s *Service) onBlockBatch(ctx context.Context, blks []interfaces.SignedBeac
Messages: [][32]byte{},
}
type versionAndHeader struct {
version version.ForkVersion
version int
header *ethpb.ExecutionPayloadHeader
}
preVersionAndHeaders := make([]*versionAndHeader, len(blks))
@@ -441,8 +443,8 @@ func (s *Service) onBlockBatch(ctx context.Context, blks []interfaces.SignedBeac
}
}
args := &forkchoicetypes.BlockAndCheckpoints{Block: b.Block(),
JustifiedEpoch: jCheckpoints[i].Epoch,
FinalizedEpoch: fCheckpoints[i].Epoch}
JustifiedCheckpoint: jCheckpoints[i],
FinalizedCheckpoint: fCheckpoints[i]}
pendingNodes[len(blks)-i-1] = args
s.saveInitSyncBlock(blockRoots[i], b)
if err = s.handleBlockAfterBatchVerify(ctx, b, blockRoots[i], fCheckpoints[i], jCheckpoints[i]); err != nil {
@@ -461,7 +463,7 @@ func (s *Service) onBlockBatch(ctx context.Context, blks []interfaces.SignedBeac
}
// Prune forkchoice store only if the new finalized checkpoint is higher
// than the finalized checkpoint in forkchoice store.
if fCheckpoints[len(blks)-1].Epoch > s.cfg.ForkChoiceStore.FinalizedEpoch() {
if fCheckpoints[len(blks)-1].Epoch > s.cfg.ForkChoiceStore.FinalizedCheckpoint().Epoch {
if err := s.cfg.ForkChoiceStore.Prune(ctx, s.ensureRootNotZeros(bytesutil.ToBytes32(fCheckpoints[len(blks)-1].Root))); err != nil {
return errors.Wrap(err, "could not prune fork choice nodes")
}
@@ -543,7 +545,8 @@ func (s *Service) handleBlockAfterBatchVerify(ctx context.Context, signed interf
return err
}
s.store.SetFinalizedCheckptAndPayloadHash(fCheckpoint, h)
if err := s.cfg.ForkChoiceStore.UpdateFinalizedCheckpoint(fCheckpoint); err != nil {
if err := s.cfg.ForkChoiceStore.UpdateFinalizedCheckpoint(&forkchoicetypes.Checkpoint{
Epoch: fCheckpoint.Epoch, Root: bytesutil.ToBytes32(fCheckpoint.Root)}); err != nil {
return err
}
}
@@ -684,9 +687,9 @@ func (s *Service) pruneCanonicalAttsFromPool(ctx context.Context, r [32]byte, b
}
// validateMergeTransitionBlock validates the merge transition block.
func (s *Service) validateMergeTransitionBlock(ctx context.Context, stateVersion version.ForkVersion, stateHeader *ethpb.ExecutionPayloadHeader, blk interfaces.SignedBeaconBlock) error {
func (s *Service) validateMergeTransitionBlock(ctx context.Context, stateVersion int, stateHeader *ethpb.ExecutionPayloadHeader, blk interfaces.SignedBeaconBlock) error {
// Skip validation if block is older than Bellatrix.
if blk.Block().Version().IsPreBellatrix() {
if blocks.IsPreBellatrixVersion(blk.Block().Version()) {
return nil
}
@@ -701,7 +704,7 @@ func (s *Service) validateMergeTransitionBlock(ctx context.Context, stateVersion
// Handle case where pre-state is Altair but block contains payload.
// To reach here, the block must have contained a valid payload.
if stateVersion.IsPreBellatrix() {
if blocks.IsPreBellatrixVersion(stateVersion) {
return s.validateMergeBlock(ctx, blk)
}

View File

@@ -218,7 +218,8 @@ func (s *Service) updateJustified(ctx context.Context, state state.ReadOnlyBeaco
}
s.store.SetJustifiedCheckptAndPayloadHash(cpt, h)
// Update forkchoice's justified checkpoint
if err := s.cfg.ForkChoiceStore.UpdateJustifiedCheckpoint(cpt); err != nil {
if err := s.cfg.ForkChoiceStore.UpdateJustifiedCheckpoint(&forkchoicetypes.Checkpoint{
Epoch: cpt.Epoch, Root: bytesutil.ToBytes32(cpt.Root)}); err != nil {
return err
}
}
@@ -244,7 +245,8 @@ func (s *Service) updateJustifiedInitSync(ctx context.Context, cp *ethpb.Checkpo
return err
}
s.store.SetJustifiedCheckptAndPayloadHash(cp, h)
return s.cfg.ForkChoiceStore.UpdateJustifiedCheckpoint(cp)
return s.cfg.ForkChoiceStore.UpdateJustifiedCheckpoint(&forkchoicetypes.Checkpoint{
Epoch: cp.Epoch, Root: bytesutil.ToBytes32(cp.Root)})
}
func (s *Service) updateFinalized(ctx context.Context, cp *ethpb.Checkpoint) error {
@@ -360,7 +362,7 @@ func (s *Service) fillInForkChoiceMissingBlocks(ctx context.Context, blk interfa
return err
}
pendingNodes = append(pendingNodes, &forkchoicetypes.BlockAndCheckpoints{Block: blk,
JustifiedEpoch: jCheckpoint.Epoch, FinalizedEpoch: fCheckpoint.Epoch})
JustifiedCheckpoint: jCheckpoint, FinalizedCheckpoint: fCheckpoint})
// As long as parent node is not in fork choice store, and parent node is in DB.
root := bytesutil.ToBytes32(blk.ParentRoot())
for !s.cfg.ForkChoiceStore.HasNode(root) && s.cfg.BeaconDB.HasBlock(ctx, root) {
@@ -373,8 +375,8 @@ func (s *Service) fillInForkChoiceMissingBlocks(ctx context.Context, blk interfa
}
root = bytesutil.ToBytes32(b.Block().ParentRoot())
args := &forkchoicetypes.BlockAndCheckpoints{Block: b.Block(),
JustifiedEpoch: jCheckpoint.Epoch,
FinalizedEpoch: fCheckpoint.Epoch}
JustifiedCheckpoint: jCheckpoint,
FinalizedCheckpoint: fCheckpoint}
pendingNodes = append(pendingNodes, args)
}
if len(pendingNodes) == 1 {

View File

@@ -47,7 +47,7 @@ func TestStore_OnBlock_ProtoArray(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0)
fcs := protoarray.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -150,7 +150,7 @@ func TestStore_OnBlock_DoublyLinkedTree(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := doublylinkedtree.New(0, 0)
fcs := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -253,7 +253,7 @@ func TestStore_OnBlock_ProposerBoostEarly(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := doublylinkedtree.New(0, 0)
fcs := doublylinkedtree.New()
opts := []Option{
WithStateGen(stategen.New(beaconDB)),
WithForkChoiceStore(fcs),
@@ -268,7 +268,7 @@ func TestStore_OnBlock_ProposerBoostEarly(t *testing.T) {
SecondsIntoSlot: 0,
}
require.NoError(t, service.cfg.ForkChoiceStore.BoostProposerRoot(ctx, args))
_, err = service.cfg.ForkChoiceStore.Head(ctx, params.BeaconConfig().ZeroHash, []uint64{})
_, err = service.cfg.ForkChoiceStore.Head(ctx, []uint64{})
require.ErrorContains(t, "could not apply proposer boost score: invalid proposer boost root", err)
}
@@ -293,7 +293,7 @@ func TestStore_OnBlockBatch_ProtoArray(t *testing.T) {
service.store.SetFinalizedCheckptAndPayloadHash(&ethpb.Checkpoint{Root: gRoot[:]}, [32]byte{'a'})
service.store.SetJustifiedCheckptAndPayloadHash(&ethpb.Checkpoint{Root: gRoot[:]}, [32]byte{'b'})
service.cfg.ForkChoiceStore = protoarray.New(0, 0)
service.cfg.ForkChoiceStore = protoarray.New()
wsb, err = wrapper.WrappedSignedBeaconBlock(genesis)
require.NoError(t, err)
service.saveInitSyncBlock(gRoot, wsb)
@@ -340,7 +340,7 @@ func TestStore_OnBlockBatch_ProtoArray(t *testing.T) {
require.NoError(t, err)
jroot := bytesutil.ToBytes32(jcp.Root)
require.Equal(t, blkRoots[63], jroot)
require.Equal(t, types.Epoch(2), service.cfg.ForkChoiceStore.JustifiedEpoch())
require.Equal(t, types.Epoch(2), service.cfg.ForkChoiceStore.JustifiedCheckpoint().Epoch)
}
func TestStore_OnBlockBatch_PruneOK(t *testing.T) {
@@ -362,7 +362,7 @@ func TestStore_OnBlockBatch_PruneOK(t *testing.T) {
gRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err)
service.cfg.ForkChoiceStore = protoarray.New(0, 0)
service.cfg.ForkChoiceStore = protoarray.New()
wsb, err = wrapper.WrappedSignedBeaconBlock(genesis)
require.NoError(t, err)
service.saveInitSyncBlock(gRoot, wsb)
@@ -427,7 +427,7 @@ func TestStore_OnBlockBatch_DoublyLinkedTree(t *testing.T) {
service.store.SetFinalizedCheckptAndPayloadHash(&ethpb.Checkpoint{Root: gRoot[:]}, [32]byte{'a'})
service.store.SetJustifiedCheckptAndPayloadHash(&ethpb.Checkpoint{Root: gRoot[:]}, [32]byte{'b'})
service.cfg.ForkChoiceStore = doublylinkedtree.New(0, 0)
service.cfg.ForkChoiceStore = doublylinkedtree.New()
wsb, err = wrapper.WrappedSignedBeaconBlock(genesis)
require.NoError(t, err)
service.saveInitSyncBlock(gRoot, wsb)
@@ -474,7 +474,7 @@ func TestStore_OnBlockBatch_DoublyLinkedTree(t *testing.T) {
require.NoError(t, err)
jroot := bytesutil.ToBytes32(jcp.Root)
require.Equal(t, blkRoots[63], jroot)
require.Equal(t, types.Epoch(2), service.cfg.ForkChoiceStore.JustifiedEpoch())
require.Equal(t, types.Epoch(2), service.cfg.ForkChoiceStore.JustifiedCheckpoint().Epoch)
}
func TestStore_OnBlockBatch_NotifyNewPayload(t *testing.T) {
@@ -496,7 +496,7 @@ func TestStore_OnBlockBatch_NotifyNewPayload(t *testing.T) {
service.store.SetFinalizedCheckptAndPayloadHash(&ethpb.Checkpoint{Root: gRoot[:]}, [32]byte{'a'})
service.store.SetJustifiedCheckptAndPayloadHash(&ethpb.Checkpoint{Root: gRoot[:]}, [32]byte{'b'})
service.cfg.ForkChoiceStore = doublylinkedtree.New(0, 0)
service.cfg.ForkChoiceStore = doublylinkedtree.New()
service.saveInitSyncBlock(gRoot, wsb)
st, keys := util.DeterministicGenesisState(t, 64)
bState := st.Copy()
@@ -577,7 +577,7 @@ func TestShouldUpdateJustified_ReturnFalse_ProtoArray(t *testing.T) {
opts := testServiceOptsWithDB(t)
service, err := NewService(ctx, opts...)
require.NoError(t, err)
service.cfg.ForkChoiceStore = protoarray.New(0, 0)
service.cfg.ForkChoiceStore = protoarray.New()
lastJustifiedBlk := util.NewBeaconBlock()
lastJustifiedBlk.Block.ParentRoot = bytesutil.PadTo([]byte{'G'}, 32)
lastJustifiedRoot, err := lastJustifiedBlk.Block.HashTreeRoot()
@@ -610,7 +610,7 @@ func TestShouldUpdateJustified_ReturnFalse_DoublyLinkedTree(t *testing.T) {
opts := testServiceOptsWithDB(t)
service, err := NewService(ctx, opts...)
require.NoError(t, err)
service.cfg.ForkChoiceStore = doublylinkedtree.New(0, 0)
service.cfg.ForkChoiceStore = doublylinkedtree.New()
lastJustifiedBlk := util.NewBeaconBlock()
lastJustifiedBlk.Block.ParentRoot = bytesutil.PadTo([]byte{'G'}, 32)
lastJustifiedRoot, err := lastJustifiedBlk.Block.HashTreeRoot()
@@ -657,7 +657,7 @@ func TestCachedPreState_CanGetFromStateSummary_ProtoArray(t *testing.T) {
gRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err)
service.store.SetFinalizedCheckptAndPayloadHash(&ethpb.Checkpoint{Root: gRoot[:]}, [32]byte{})
service.cfg.ForkChoiceStore = protoarray.New(0, 0)
service.cfg.ForkChoiceStore = protoarray.New()
wsb, err = wrapper.WrappedSignedBeaconBlock(genesis)
require.NoError(t, err)
service.saveInitSyncBlock(gRoot, wsb)
@@ -694,7 +694,7 @@ func TestCachedPreState_CanGetFromStateSummary_DoublyLinkedTree(t *testing.T) {
gRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err)
service.store.SetFinalizedCheckptAndPayloadHash(&ethpb.Checkpoint{Root: gRoot[:]}, [32]byte{})
service.cfg.ForkChoiceStore = doublylinkedtree.New(0, 0)
service.cfg.ForkChoiceStore = doublylinkedtree.New()
wsb, err = wrapper.WrappedSignedBeaconBlock(genesis)
require.NoError(t, err)
service.saveInitSyncBlock(gRoot, wsb)
@@ -728,7 +728,7 @@ func TestCachedPreState_CanGetFromDB(t *testing.T) {
gRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err)
service.store.SetFinalizedCheckptAndPayloadHash(&ethpb.Checkpoint{Root: gRoot[:]}, [32]byte{})
service.cfg.ForkChoiceStore = protoarray.New(0, 0)
service.cfg.ForkChoiceStore = protoarray.New()
wsb, err = wrapper.WrappedSignedBeaconBlock(genesis)
require.NoError(t, err)
service.saveInitSyncBlock(gRoot, wsb)
@@ -759,7 +759,7 @@ func TestUpdateJustified_CouldUpdateBest(t *testing.T) {
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
WithForkChoiceStore(protoarray.New(0, 0)),
WithForkChoiceStore(protoarray.New()),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
@@ -805,7 +805,7 @@ func TestFillForkChoiceMissingBlocks_CanSave_ProtoArray(t *testing.T) {
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
service.cfg.ForkChoiceStore = protoarray.New(0, 0)
service.cfg.ForkChoiceStore = protoarray.New()
genesisStateRoot := [32]byte{}
genesis := blocks.NewGenesisBlock(genesisStateRoot[:])
@@ -851,7 +851,7 @@ func TestFillForkChoiceMissingBlocks_CanSave_DoublyLinkedTree(t *testing.T) {
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
service.cfg.ForkChoiceStore = doublylinkedtree.New(0, 0)
service.cfg.ForkChoiceStore = doublylinkedtree.New()
genesisStateRoot := [32]byte{}
genesis := blocks.NewGenesisBlock(genesisStateRoot[:])
@@ -898,7 +898,7 @@ func TestFillForkChoiceMissingBlocks_RootsMatch_ProtoArray(t *testing.T) {
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
service.cfg.ForkChoiceStore = protoarray.New(0, 0)
service.cfg.ForkChoiceStore = protoarray.New()
genesisStateRoot := [32]byte{}
genesis := blocks.NewGenesisBlock(genesisStateRoot[:])
@@ -947,7 +947,7 @@ func TestFillForkChoiceMissingBlocks_RootsMatch_DoublyLinkedTree(t *testing.T) {
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
service.cfg.ForkChoiceStore = doublylinkedtree.New(0, 0)
service.cfg.ForkChoiceStore = doublylinkedtree.New()
genesisStateRoot := [32]byte{}
genesis := blocks.NewGenesisBlock(genesisStateRoot[:])
@@ -996,7 +996,7 @@ func TestFillForkChoiceMissingBlocks_FilterFinalized_ProtoArray(t *testing.T) {
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
service.cfg.ForkChoiceStore = protoarray.New(0, 0)
service.cfg.ForkChoiceStore = protoarray.New()
genesisStateRoot := [32]byte{}
genesis := blocks.NewGenesisBlock(genesisStateRoot[:])
@@ -1063,7 +1063,7 @@ func TestFillForkChoiceMissingBlocks_FilterFinalized_DoublyLinkedTree(t *testing
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
service.cfg.ForkChoiceStore = doublylinkedtree.New(0, 0)
service.cfg.ForkChoiceStore = doublylinkedtree.New()
genesisStateRoot := [32]byte{}
genesis := blocks.NewGenesisBlock(genesisStateRoot[:])
@@ -1131,7 +1131,7 @@ func TestFillForkChoiceMissingBlocks_FinalizedSibling_DoublyLinkedTree(t *testin
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
service.cfg.ForkChoiceStore = doublylinkedtree.New(0, 0)
service.cfg.ForkChoiceStore = doublylinkedtree.New()
genesisStateRoot := [32]byte{}
genesis := blocks.NewGenesisBlock(genesisStateRoot[:])
@@ -1272,7 +1272,7 @@ func TestAncestor_HandleSkipSlot(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0)
fcs := protoarray.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -1363,7 +1363,7 @@ func TestAncestor_CanUseDB(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0)
fcs := protoarray.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -1425,7 +1425,7 @@ func TestVerifyBlkDescendant(t *testing.T) {
beaconDB := testDB.SetupDB(t)
ctx := context.Background()
fcs := protoarray.New(0, 0)
fcs := protoarray.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -1570,7 +1570,7 @@ func TestHandleEpochBoundary_UpdateFirstSlot(t *testing.T) {
func TestOnBlock_CanFinalize(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0)
fcs := protoarray.New()
depositCache, err := depositcache.New()
require.NoError(t, err)
opts := []Option{
@@ -1626,7 +1626,7 @@ func TestOnBlock_CanFinalize(t *testing.T) {
func TestOnBlock_NilBlock(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0)
fcs := protoarray.New()
depositCache, err := depositcache.New()
require.NoError(t, err)
opts := []Option{
@@ -1645,7 +1645,7 @@ func TestOnBlock_NilBlock(t *testing.T) {
func TestOnBlock_InvalidSignature(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0)
fcs := protoarray.New()
depositCache, err := depositcache.New()
require.NoError(t, err)
opts := []Option{
@@ -1686,7 +1686,7 @@ func TestOnBlock_CallNewPayloadAndForkchoiceUpdated(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0)
fcs := protoarray.New()
depositCache, err := depositcache.New()
require.NoError(t, err)
opts := []Option{
@@ -1924,7 +1924,7 @@ func Test_validateMergeTransitionBlock(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0)
fcs := protoarray.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -2052,7 +2052,7 @@ func Test_validateMergeTransitionBlock(t *testing.T) {
func TestService_insertSlashingsToForkChoiceStore(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0)
fcs := protoarray.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -2103,7 +2103,7 @@ func TestService_insertSlashingsToForkChoiceStore(t *testing.T) {
func TestOnBlock_ProcessBlocksParallel(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0)
fcs := protoarray.New()
depositCache, err := depositcache.New()
require.NoError(t, err)
opts := []Option{
@@ -2175,7 +2175,7 @@ func TestOnBlock_ProcessBlocksParallel(t *testing.T) {
require.NoError(t, service.cfg.BeaconDB.DeleteBlock(ctx, r2))
require.NoError(t, service.cfg.BeaconDB.DeleteBlock(ctx, r3))
require.NoError(t, service.cfg.BeaconDB.DeleteBlock(ctx, r4))
service.cfg.ForkChoiceStore = protoarray.New(0, 0)
service.cfg.ForkChoiceStore = protoarray.New()
}
}
@@ -2183,7 +2183,7 @@ func Test_verifyBlkFinalizedSlot_invalidBlock(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0)
fcs := protoarray.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),

View File

@@ -127,7 +127,7 @@ func TestService_ReceiveBlock(t *testing.T) {
opts := []Option{
WithDatabase(beaconDB),
WithForkChoiceStore(protoarray.New(0, 0)),
WithForkChoiceStore(protoarray.New()),
WithAttestationPool(attestations.NewPool()),
WithExitPool(voluntaryexits.NewPool()),
WithStateNotifier(&blockchainTesting.MockStateNotifier{RecordEvents: true}),
@@ -168,7 +168,7 @@ func TestService_ReceiveBlockUpdateHead(t *testing.T) {
require.NoError(t, beaconDB.SaveState(ctx, genesis, genesisBlockRoot))
opts := []Option{
WithDatabase(beaconDB),
WithForkChoiceStore(protoarray.New(0, 0)),
WithForkChoiceStore(protoarray.New()),
WithAttestationPool(attestations.NewPool()),
WithExitPool(voluntaryexits.NewPool()),
WithStateNotifier(&blockchainTesting.MockStateNotifier{RecordEvents: true}),
@@ -248,7 +248,7 @@ func TestService_ReceiveBlockBatch(t *testing.T) {
beaconDB := testDB.SetupDB(t)
opts := []Option{
WithDatabase(beaconDB),
WithForkChoiceStore(protoarray.New(0, 0)),
WithForkChoiceStore(protoarray.New()),
WithStateNotifier(&blockchainTesting.MockStateNotifier{RecordEvents: true}),
WithStateGen(stategen.New(beaconDB)),
}

View File

@@ -23,6 +23,7 @@ import (
f "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice"
doublylinkedtree "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/doubly-linked-tree"
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
forkchoicetypes "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/types"
"github.com/prysmaticlabs/prysm/beacon-chain/operations/attestations"
"github.com/prysmaticlabs/prysm/beacon-chain/operations/slashings"
"github.com/prysmaticlabs/prysm/beacon-chain/operations/voluntaryexits"
@@ -208,11 +209,20 @@ func (s *Service) StartFromSavedState(saved state.BeaconState) error {
var forkChoicer f.ForkChoicer
fRoot := s.ensureRootNotZeros(bytesutil.ToBytes32(finalized.Root))
if features.Get().EnableForkChoiceDoublyLinkedTree {
forkChoicer = doublylinkedtree.New(justified.Epoch, finalized.Epoch)
forkChoicer = doublylinkedtree.New()
} else {
forkChoicer = protoarray.New(justified.Epoch, finalized.Epoch)
forkChoicer = protoarray.New()
}
s.cfg.ForkChoiceStore = forkChoicer
if err := forkChoicer.UpdateJustifiedCheckpoint(&forkchoicetypes.Checkpoint{Epoch: justified.Epoch,
Root: bytesutil.ToBytes32(justified.Root)}); err != nil {
return errors.Wrap(err, "could not update forkchoice's justified checkpoint")
}
if err := forkChoicer.UpdateFinalizedCheckpoint(&forkchoicetypes.Checkpoint{Epoch: finalized.Epoch,
Root: bytesutil.ToBytes32(finalized.Root)}); err != nil {
return errors.Wrap(err, "could not update forkchoice's finalized checkpoint")
}
st, err := s.cfg.StateGen.StateByRoot(s.ctx, fRoot)
if err != nil {
return errors.Wrap(err, "could not get finalized checkpoint state")

View File

@@ -130,7 +130,7 @@ func setupBeaconChain(t *testing.T, beaconDB db.Database) *Service {
WithAttestationPool(attestations.NewPool()),
WithP2PBroadcaster(&mockBroadcaster{}),
WithStateNotifier(&mockBeaconNode{}),
WithForkChoiceStore(protoarray.New(0, 0)),
WithForkChoiceStore(protoarray.New()),
WithAttestationService(attService),
WithStateGen(stateGen),
}
@@ -505,7 +505,7 @@ func TestHasBlock_ForkChoiceAndDB_ProtoArray(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
s := &Service{
cfg: &config{ForkChoiceStore: protoarray.New(0, 0), BeaconDB: beaconDB},
cfg: &config{ForkChoiceStore: protoarray.New(), BeaconDB: beaconDB},
store: &store.Store{},
}
s.store.SetFinalizedCheckptAndPayloadHash(&ethpb.Checkpoint{Epoch: 0, Root: params.BeaconConfig().ZeroHash[:]}, [32]byte{})
@@ -526,7 +526,7 @@ func TestHasBlock_ForkChoiceAndDB_DoublyLinkedTree(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
s := &Service{
cfg: &config{ForkChoiceStore: doublylinkedtree.New(0, 0), BeaconDB: beaconDB},
cfg: &config{ForkChoiceStore: doublylinkedtree.New(), BeaconDB: beaconDB},
store: &store.Store{},
}
s.store.SetFinalizedCheckptAndPayloadHash(&ethpb.Checkpoint{Epoch: 0, Root: params.BeaconConfig().ZeroHash[:]}, [32]byte{})
@@ -599,7 +599,7 @@ func BenchmarkHasBlockForkChoiceStore_ProtoArray(b *testing.B) {
ctx := context.Background()
beaconDB := testDB.SetupDB(b)
s := &Service{
cfg: &config{ForkChoiceStore: protoarray.New(0, 0), BeaconDB: beaconDB},
cfg: &config{ForkChoiceStore: protoarray.New(), BeaconDB: beaconDB},
store: &store.Store{},
}
s.store.SetFinalizedCheckptAndPayloadHash(&ethpb.Checkpoint{Epoch: 0, Root: params.BeaconConfig().ZeroHash[:]}, [32]byte{})
@@ -622,7 +622,7 @@ func BenchmarkHasBlockForkChoiceStore_DoublyLinkedTree(b *testing.B) {
ctx := context.Background()
beaconDB := testDB.SetupDB(b)
s := &Service{
cfg: &config{ForkChoiceStore: doublylinkedtree.New(0, 0), BeaconDB: beaconDB},
cfg: &config{ForkChoiceStore: doublylinkedtree.New(), BeaconDB: beaconDB},
store: &store.Store{},
}
s.store.SetFinalizedCheckptAndPayloadHash(&ethpb.Checkpoint{Epoch: 0, Root: params.BeaconConfig().ZeroHash[:]}, [32]byte{})

View File

@@ -32,7 +32,7 @@ func (c *SyncCommitteeHeadStateCache) Put(slot types.Slot, st state.BeaconState)
return ErrNilValueProvided
}
if st.Version().IsPhase0Compatible() {
if st.Version() == version.Phase0 {
return ErrIncorrectType
}

View File

@@ -13,6 +13,7 @@ import (
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/attestation"
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/slashings"
"github.com/prysmaticlabs/prysm/runtime/version"
"github.com/prysmaticlabs/prysm/time/slots"
)
@@ -78,11 +79,11 @@ func ProcessAttesterSlashing(
cfg := params.BeaconConfig()
var slashingQuotient uint64
switch {
case beaconState.Version().IsPhase0Compatible():
case beaconState.Version() == version.Phase0:
slashingQuotient = cfg.MinSlashingPenaltyQuotient
case beaconState.Version().IsAltairCompatible():
case beaconState.Version() == version.Altair:
slashingQuotient = cfg.MinSlashingPenaltyQuotientAltair
case beaconState.Version().IsBellatrixCompatible():
case beaconState.Version() == version.Bellatrix:
slashingQuotient = cfg.MinSlashingPenaltyQuotientBellatrix
default:
return nil, errors.New("unknown state version")

View File

@@ -13,6 +13,7 @@ import (
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/runtime/version"
"github.com/prysmaticlabs/prysm/time/slots"
)
@@ -32,7 +33,7 @@ func IsMergeTransitionComplete(st state.BeaconState) (bool, error) {
if st == nil {
return false, errors.New("nil state")
}
if st.Version().IsPreBellatrix() {
if IsPreBellatrixVersion(st.Version()) {
return false, nil
}
h, err := st.LatestExecutionPayloadHeader()
@@ -85,7 +86,7 @@ func IsExecutionEnabled(st state.BeaconState, body interfaces.BeaconBlockBody) (
if st == nil || body == nil {
return false, errors.New("nil state or block body")
}
if st.Version().IsPreBellatrix() {
if IsPreBellatrixVersion(st.Version()) {
return false, nil
}
header, err := st.LatestExecutionPayloadHeader()
@@ -104,6 +105,11 @@ func IsExecutionEnabledUsingHeader(header *ethpb.ExecutionPayloadHeader, body in
return IsExecutionBlock(body)
}
// IsPreBellatrixVersion returns true if input version is before bellatrix fork.
func IsPreBellatrixVersion(v int) bool {
return v < version.Bellatrix
}
// ValidatePayloadWhenMergeCompletes validates if payload is valid versus input beacon state.
// These validation steps ONLY apply to post merge.
//
@@ -270,7 +276,7 @@ func ProcessPayloadHeader(st state.BeaconState, header *ethpb.ExecutionPayloadHe
// GetBlockPayloadHash returns the hash of the execution payload of the block
func GetBlockPayloadHash(blk interfaces.BeaconBlock) ([32]byte, error) {
payloadHash := [32]byte{}
if blk.Version().IsPreBellatrix() {
if IsPreBellatrixVersion(blk.Version()) {
return payloadHash, nil
}
payload, err := blk.Body().ExecutionPayload()

View File

@@ -12,6 +12,7 @@ import (
"github.com/prysmaticlabs/prysm/config/params"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/runtime/version"
"github.com/prysmaticlabs/prysm/time/slots"
"google.golang.org/protobuf/proto"
)
@@ -76,11 +77,11 @@ func ProcessProposerSlashing(
cfg := params.BeaconConfig()
var slashingQuotient uint64
switch {
case beaconState.Version().IsPhase0Compatible():
case beaconState.Version() == version.Phase0:
slashingQuotient = cfg.MinSlashingPenaltyQuotient
case beaconState.Version().IsAltairCompatible():
case beaconState.Version() == version.Altair:
slashingQuotient = cfg.MinSlashingPenaltyQuotientAltair
case beaconState.Version().IsBellatrixCompatible():
case beaconState.Version() == version.Bellatrix:
slashingQuotient = cfg.MinSlashingPenaltyQuotientBellatrix
default:
return nil, errors.New("unknown state version")

View File

@@ -171,7 +171,7 @@ func UpdateValidator(vp []*Validator, record *Validator, indices []uint64, a *et
}
// UpdateBalance updates pre computed balance store.
func UpdateBalance(vp []*Validator, bBal *Balance, stateVersion version.ForkVersion) *Balance {
func UpdateBalance(vp []*Validator, bBal *Balance, stateVersion int) *Balance {
for _, v := range vp {
if !v.IsSlashed {
if v.IsCurrentEpochAttester {
@@ -180,10 +180,10 @@ func UpdateBalance(vp []*Validator, bBal *Balance, stateVersion version.ForkVers
if v.IsCurrentEpochTargetAttester {
bBal.CurrentEpochTargetAttested += v.CurrentEpochEffectiveBalance
}
if stateVersion.IsPhase0Compatible() && v.IsPrevEpochAttester {
if stateVersion == version.Phase0 && v.IsPrevEpochAttester {
bBal.PrevEpochAttested += v.CurrentEpochEffectiveBalance
}
if stateVersion.IsHigherOrEqualToAltair() && v.IsPrevEpochSourceAttester {
if (stateVersion == version.Altair || stateVersion == version.Bellatrix) && v.IsPrevEpochSourceAttester {
bBal.PrevEpochAttested += v.CurrentEpochEffectiveBalance
}
if v.IsPrevEpochTargetAttester {

View File

@@ -9,6 +9,7 @@ go_library(
"//beacon-chain/state:go_default_library",
"//config/params:go_default_library",
"//consensus-types/primitives:go_default_library",
"//runtime/version:go_default_library",
"//time/slots:go_default_library",
],
)

View File

@@ -4,6 +4,7 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/config/params"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/runtime/version"
"github.com/prysmaticlabs/prysm/time/slots"
)
@@ -47,7 +48,7 @@ func NextEpoch(state state.ReadOnlyBeaconState) types.Epoch {
// HigherEqualThanAltairVersionAndEpoch returns if the input state `s` has a higher version number than Altair state and input epoch `e` is higher equal than fork epoch.
func HigherEqualThanAltairVersionAndEpoch(s state.BeaconState, e types.Epoch) bool {
return s.Version().IsHigherOrEqualToAltair() && e >= params.BeaconConfig().AltairForkEpoch
return s.Version() >= version.Altair && e >= params.BeaconConfig().AltairForkEpoch
}
// CanUpgradeToAltair returns true if the input `slot` can upgrade to Altair.

View File

@@ -22,6 +22,7 @@ import (
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
"github.com/prysmaticlabs/prysm/math"
"github.com/prysmaticlabs/prysm/monitoring/tracing"
"github.com/prysmaticlabs/prysm/runtime/version"
"go.opencensus.io/trace"
)
@@ -247,14 +248,14 @@ func ProcessSlots(ctx context.Context, state state.BeaconState, slot types.Slot)
return nil, errors.Wrap(err, "could not process slot")
}
if time.CanProcessEpoch(state) {
switch {
case state.Version().IsPhase0Compatible():
switch state.Version() {
case version.Phase0:
state, err = ProcessEpochPrecompute(ctx, state)
if err != nil {
tracing.AnnotateError(span, err)
return nil, errors.Wrap(err, "could not process epoch with optimizations")
}
case state.Version().IsHigherOrEqualToAltair():
case version.Altair, version.Bellatrix:
state, err = altair.ProcessEpoch(ctx, state)
if err != nil {
tracing.AnnotateError(span, err)

View File

@@ -15,6 +15,7 @@ import (
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
"github.com/prysmaticlabs/prysm/crypto/bls"
"github.com/prysmaticlabs/prysm/monitoring/tracing"
"github.com/prysmaticlabs/prysm/runtime/version"
"go.opencensus.io/trace"
)
@@ -231,13 +232,13 @@ func ProcessOperationsNoVerifyAttsSigs(
}
var err error
switch {
case signedBeaconBlock.Version().IsPhase0Compatible():
switch signedBeaconBlock.Version() {
case version.Phase0:
state, err = phase0Operations(ctx, state, signedBeaconBlock)
if err != nil {
return nil, err
}
case signedBeaconBlock.Version().IsHigherOrEqualToAltair():
case version.Altair, version.Bellatrix:
state, err = altairOperations(ctx, state, signedBeaconBlock)
if err != nil {
return nil, err
@@ -328,7 +329,7 @@ func ProcessBlockForStateRoot(
return nil, errors.Wrap(err, "could not process block operation")
}
if signed.Block().Version().IsPhase0Compatible() {
if signed.Block().Version() == version.Phase0 {
return state, nil
}

View File

@@ -17,6 +17,7 @@ import (
"github.com/prysmaticlabs/prysm/container/slice"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/runtime/version"
"github.com/prysmaticlabs/prysm/time/slots"
bolt "go.etcd.io/bbolt"
"go.opencensus.io/trace"
@@ -793,14 +794,14 @@ func marshalBlock(_ context.Context, blk interfaces.SignedBeaconBlock) ([]byte,
if err != nil {
return nil, err
}
switch {
case blk.Version().IsBlindedBlockCompatible():
switch blk.Version() {
case version.BellatrixBlind:
return snappy.Encode(nil, append(bellatrixBlindKey, obj...)), nil
case blk.Version().IsBellatrixCompatible():
case version.Bellatrix:
return snappy.Encode(nil, append(bellatrixKey, obj...)), nil
case blk.Version().IsAltairCompatible():
case version.Altair:
return snappy.Encode(nil, append(altairKey, obj...)), nil
case blk.Version().IsPhase0Compatible():
case version.Phase0:
return snappy.Encode(nil, obj), nil
default:
return nil, errors.New("Unknown block version")

View File

@@ -9,6 +9,7 @@ import (
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/encoding/ssz/detect"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/runtime/version"
)
// SaveOrigin loads an ssz serialized Block & BeaconState from an io.Reader
@@ -37,7 +38,7 @@ func (s *Store) SaveOrigin(ctx context.Context, serState, serBlock []byte) error
return fmt.Errorf("config mismatch, beacon node configured to connect to %s, detected state is for %s", params.BeaconConfig().ConfigName, cf.Config.ConfigName)
}
log.Infof("detected supported config for state & block version, config name=%s, fork name=%s", cf.Config.ConfigName, cf.Fork.String())
log.Infof("detected supported config for state & block version, config name=%s, fork name=%s", cf.Config.ConfigName, version.String(cf.Fork))
state, err := cf.UnmarshalBeaconState(serState)
if err != nil {
return errors.Wrap(err, "failed to initialize origin state w/ bytes + config+fork")

View File

@@ -21,6 +21,8 @@ go_library(
],
deps = [
"//beacon-chain/core/blocks:go_default_library",
"//beacon-chain/core/epoch/precompute:go_default_library",
"//beacon-chain/core/transition:go_default_library",
"//beacon-chain/forkchoice:go_default_library",
"//beacon-chain/forkchoice/types:go_default_library",
"//beacon-chain/state:go_default_library",

View File

@@ -4,6 +4,7 @@ import (
"context"
"testing"
forkchoicetypes "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/types"
"github.com/prysmaticlabs/prysm/config/params"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/testing/assert"
@@ -16,7 +17,7 @@ func TestFFGUpdates_OneBranch(t *testing.T) {
ctx := context.Background()
// The head should always start at the finalized block.
r, err := f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err := f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, params.BeaconConfig().ZeroHash, r, "Incorrect head with genesis")
@@ -46,7 +47,7 @@ func TestFFGUpdates_OneBranch(t *testing.T) {
// 2
// |
// 3 <- head
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(3), r, "Incorrect head for with justified epoch at 0")
@@ -58,8 +59,8 @@ func TestFFGUpdates_OneBranch(t *testing.T) {
// 2 <- head
// |
// 3
f.store.justifiedEpoch = 1
r, err = f.Head(context.Background(), indexToHash(2), balances)
f.store.justifiedCheckpoint = &forkchoicetypes.Checkpoint{Root: indexToHash(2), Epoch: 1}
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head with justified epoch at 1")
@@ -71,8 +72,8 @@ func TestFFGUpdates_OneBranch(t *testing.T) {
// 2 <- start
// |
// 3 <- head
f.store.justifiedEpoch = 2
r, err = f.Head(context.Background(), indexToHash(3), balances)
f.store.justifiedCheckpoint = &forkchoicetypes.Checkpoint{Root: indexToHash(3), Epoch: 2}
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(3), r, "Incorrect head with justified epoch at 2")
}
@@ -82,7 +83,7 @@ func TestFFGUpdates_TwoBranches(t *testing.T) {
f := setup(0, 0)
ctx := context.Background()
r, err := f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err := f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, params.BeaconConfig().ZeroHash, r, "Incorrect head with genesis")
@@ -143,7 +144,7 @@ func TestFFGUpdates_TwoBranches(t *testing.T) {
// 7 8
// | |
// 9 10 <-- head
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(10), r, "Incorrect head with justified epoch at 0")
@@ -173,7 +174,7 @@ func TestFFGUpdates_TwoBranches(t *testing.T) {
// 7 8
// | |
// head -> 9 10
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(9), r, "Incorrect head with justified epoch at 0")
@@ -203,19 +204,21 @@ func TestFFGUpdates_TwoBranches(t *testing.T) {
// 7 8
// | |
// 9 10 <-- head
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(10), r, "Incorrect head with justified epoch at 0")
f.store.justifiedEpoch = 1
r, err = f.Head(context.Background(), indexToHash(1), balances)
f.store.justifiedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: 1, Root: indexToHash(1)}
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(7), r, "Incorrect head with justified epoch at 0")
}
func setup(justifiedEpoch, finalizedEpoch types.Epoch) *ForkChoice {
ctx := context.Background()
f := New(justifiedEpoch, finalizedEpoch)
f := New()
f.store.justifiedCheckpoint = &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 {
return nil

View File

@@ -3,9 +3,12 @@ package doublylinkedtree
import (
"context"
"fmt"
"time"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute"
"github.com/prysmaticlabs/prysm/beacon-chain/core/transition"
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice"
forkchoicetypes "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/types"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
@@ -13,22 +16,22 @@ import (
"github.com/prysmaticlabs/prysm/config/params"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
pbrpc "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/runtime/version"
"github.com/sirupsen/logrus"
"go.opencensus.io/trace"
)
// New initializes a new fork choice store.
func New(justifiedEpoch, finalizedEpoch types.Epoch) *ForkChoice {
func New() *ForkChoice {
s := &Store{
justifiedEpoch: justifiedEpoch,
finalizedEpoch: finalizedEpoch,
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{},
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)
@@ -47,7 +50,6 @@ func (f *ForkChoice) NodeCount() int {
// It firsts computes validator's balance changes then recalculates block tree from leaves to root.
func (f *ForkChoice) Head(
ctx context.Context,
justifiedRoot [32]byte,
justifiedStateBalances []uint64,
) ([32]byte, error) {
ctx, span := trace.StartSpan(ctx, "doublyLinkedForkchoice.Head")
@@ -73,10 +75,12 @@ func (f *ForkChoice) Head(
return [32]byte{}, errors.Wrap(err, "could not apply weight changes")
}
if err := f.store.treeRootNode.updateBestDescendant(ctx, f.store.justifiedEpoch, f.store.finalizedEpoch); err != nil {
jc := f.JustifiedCheckpoint()
fc := f.FinalizedCheckpoint()
if err := f.store.treeRootNode.updateBestDescendant(ctx, jc.Epoch, fc.Epoch); err != nil {
return [32]byte{}, errors.Wrap(err, "could not update best descendant")
}
return f.store.head(ctx, justifiedRoot)
return f.store.head(ctx)
}
// ProcessAttestation processes attestation for vote accounting, it iterates around validator indices
@@ -108,7 +112,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()
@@ -138,6 +142,32 @@ func (f *ForkChoice) InsertNode(ctx context.Context, state state.ReadOnlyBeaconS
return errInvalidNilCheckpoint
}
finalizedEpoch := fc.Epoch
go func() {
// compute unrealized checkpoints at N+2
start := time.Now()
stCopy := state.Copy()
copyTime := time.Since(start)
nextStart := stCopy.Slot() + params.BeaconConfig().SlotsPerEpoch
nextStart = nextStart - nextStart%params.BeaconConfig().SlotsPerEpoch
stCopy, err := transition.ProcessSlots(ctx, stCopy, nextStart)
_ = err
transitionTime := time.Since(start)
ujc, ufc, err := precompute.UnrealizedCheckpoints(stCopy)
_ = err
elapsed := time.Since(start)
log.WithFields(logrus.Fields{
"copyTime": copyTime,
"epochTransTime": transitionTime - copyTime,
"unrealizedJustTime": elapsed - transitionTime,
"totalElapsed": elapsed,
"CurrentJustification": jc.Epoch,
"UnrealizedJustification": ujc.Epoch,
"UnrealizedFinalization": ufc.Epoch,
}).Info("Pulled block to N+2")
}()
return f.store.insert(ctx, slot, root, parentRoot, payloadHash, justifiedEpoch, finalizedEpoch)
}
@@ -326,20 +356,24 @@ func (f *ForkChoice) SetOptimisticToValid(ctx context.Context, root [fieldparams
return node.setNodeAndParentValidated(ctx)
}
// JustifiedEpoch of fork choice store.
func (f *ForkChoice) JustifiedEpoch() types.Epoch {
return f.store.justifiedEpoch
// JustifiedCheckpoint of fork choice store.
func (f *ForkChoice) JustifiedCheckpoint() *forkchoicetypes.Checkpoint {
f.store.checkpointsLock.RLock()
defer f.store.checkpointsLock.RUnlock()
return f.store.justifiedCheckpoint
}
// FinalizedEpoch of fork choice store.
func (f *ForkChoice) FinalizedEpoch() types.Epoch {
return f.store.finalizedEpoch
// FinalizedCheckpoint of fork choice store.
func (f *ForkChoice) FinalizedCheckpoint() *forkchoicetypes.Checkpoint {
f.store.checkpointsLock.RLock()
defer f.store.checkpointsLock.RUnlock()
return f.store.finalizedCheckpoint
}
func (f *ForkChoice) ForkChoiceNodes() []*pbrpc.ForkChoiceNode {
func (f *ForkChoice) ForkChoiceNodes() []*ethpb.ForkChoiceNode {
f.store.nodesLock.RLock()
defer f.store.nodesLock.RUnlock()
ret := make([]*pbrpc.ForkChoiceNode, len(f.store.nodeByRoot))
ret := make([]*ethpb.ForkChoiceNode, len(f.store.nodeByRoot))
return f.store.treeRootNode.rpcNodes(ret)
}
@@ -384,25 +418,25 @@ func (f *ForkChoice) InsertSlashedIndex(_ context.Context, index types.Validator
}
}
// UpdateJustifiedCheckpoint sets the justified epoch to the given one
func (f *ForkChoice) UpdateJustifiedCheckpoint(jc *pbrpc.Checkpoint) error {
// UpdateJustifiedCheckpoint sets the justified checkpoint to the given one
func (f *ForkChoice) UpdateJustifiedCheckpoint(jc *forkchoicetypes.Checkpoint) error {
if jc == nil {
return errInvalidNilCheckpoint
}
f.store.nodesLock.Lock()
defer f.store.nodesLock.Unlock()
f.store.justifiedEpoch = jc.Epoch
f.store.checkpointsLock.Lock()
defer f.store.checkpointsLock.Unlock()
f.store.justifiedCheckpoint = jc
return nil
}
// UpdateFinalizedCheckpoint sets the finalized epoch to the given one
func (f *ForkChoice) UpdateFinalizedCheckpoint(fc *pbrpc.Checkpoint) error {
// UpdateFinalizedCheckpoint sets the finalized checkpoint to the given one
func (f *ForkChoice) UpdateFinalizedCheckpoint(fc *forkchoicetypes.Checkpoint) error {
if fc == nil {
return errInvalidNilCheckpoint
}
f.store.nodesLock.Lock()
defer f.store.nodesLock.Unlock()
f.store.finalizedEpoch = fc.Epoch
f.store.checkpointsLock.Lock()
defer f.store.checkpointsLock.Unlock()
f.store.finalizedCheckpoint = fc
return nil
}
@@ -473,7 +507,7 @@ func (f *ForkChoice) InsertOptimisticChain(ctx context.Context, chain []*forkcho
}
if err := f.store.insert(ctx,
b.Slot(), r, parentRoot, payloadHash,
chain[i].JustifiedEpoch, chain[i].FinalizedEpoch); err != nil {
chain[i].JustifiedCheckpoint.Epoch, chain[i].FinalizedCheckpoint.Epoch); err != nil {
return err
}
}

View File

@@ -211,7 +211,9 @@ func TestForkChoice_IsCanonicalReorg(t *testing.T) {
require.DeepEqual(t, [32]byte{'3'}, f.store.treeRootNode.bestDescendant.root)
f.store.nodesLock.Unlock()
h, err := f.store.head(ctx, [32]byte{'1'})
r1 := [32]byte{'1'}
f.store.justifiedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: 1, Root: r1}
h, err := f.store.head(ctx)
require.NoError(t, err)
require.DeepEqual(t, [32]byte{'3'}, h)
require.DeepEqual(t, h, f.store.headNode.root)
@@ -296,7 +298,7 @@ func TestForkChoice_RemoveEquivocating(t *testing.T) {
state, blkRoot, err := prepareForkchoiceState(ctx, 1, [32]byte{'a'}, params.BeaconConfig().ZeroHash, [32]byte{'A'}, 1, 1)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
head, err := f.Head(ctx, params.BeaconConfig().ZeroHash, []uint64{})
head, err := f.Head(ctx, []uint64{})
require.NoError(t, err)
require.Equal(t, [32]byte{'a'}, head)
@@ -307,21 +309,21 @@ func TestForkChoice_RemoveEquivocating(t *testing.T) {
state, blkRoot, err = prepareForkchoiceState(ctx, 3, [32]byte{'c'}, [32]byte{'a'}, [32]byte{'C'}, 1, 1)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
head, err = f.Head(ctx, params.BeaconConfig().ZeroHash, []uint64{})
head, err = f.Head(ctx, []uint64{})
require.NoError(t, err)
require.Equal(t, [32]byte{'c'}, head)
// Insert two attestations for block b, one for c it becomes head
f.ProcessAttestation(ctx, []uint64{1, 2}, [32]byte{'b'}, 1)
f.ProcessAttestation(ctx, []uint64{3}, [32]byte{'c'}, 1)
head, err = f.Head(ctx, params.BeaconConfig().ZeroHash, []uint64{100, 200, 200, 300})
head, err = f.Head(ctx, []uint64{100, 200, 200, 300})
require.NoError(t, err)
require.Equal(t, [32]byte{'b'}, head)
// Process b's slashing, c is now head
f.InsertSlashedIndex(ctx, 1)
require.Equal(t, uint64(200), f.store.nodeByRoot[[32]byte{'b'}].balance)
head, err = f.Head(ctx, params.BeaconConfig().ZeroHash, []uint64{100, 200, 200, 300})
head, err = f.Head(ctx, []uint64{100, 200, 200, 300})
require.Equal(t, uint64(200), f.store.nodeByRoot[[32]byte{'b'}].weight)
require.Equal(t, uint64(300), f.store.nodeByRoot[[32]byte{'c'}].weight)
require.NoError(t, err)
@@ -330,7 +332,7 @@ func TestForkChoice_RemoveEquivocating(t *testing.T) {
// Process b's slashing again, should be a noop
f.InsertSlashedIndex(ctx, 1)
require.Equal(t, uint64(200), f.store.nodeByRoot[[32]byte{'b'}].balance)
head, err = f.Head(ctx, params.BeaconConfig().ZeroHash, []uint64{100, 200, 200, 300})
head, err = f.Head(ctx, []uint64{100, 200, 200, 300})
require.Equal(t, uint64(200), f.store.nodeByRoot[[32]byte{'b'}].weight)
require.Equal(t, uint64(300), f.store.nodeByRoot[[32]byte{'c'}].weight)
require.NoError(t, err)
@@ -352,12 +354,14 @@ func TestStore_UpdateCheckpoints(t *testing.T) {
f := setup(1, 1)
jr := [32]byte{'j'}
fr := [32]byte{'f'}
jc := &ethpb.Checkpoint{Root: jr[:], Epoch: 3}
fc := &ethpb.Checkpoint{Root: fr[:], Epoch: 2}
jc := &forkchoicetypes.Checkpoint{Root: jr, Epoch: 3}
fc := &forkchoicetypes.Checkpoint{Root: fr, Epoch: 2}
require.NoError(t, f.UpdateJustifiedCheckpoint(jc))
require.NoError(t, f.UpdateFinalizedCheckpoint(fc))
require.Equal(t, f.store.justifiedEpoch, jc.Epoch)
require.Equal(t, f.store.finalizedEpoch, fc.Epoch)
require.Equal(t, f.store.justifiedCheckpoint.Epoch, jc.Epoch)
require.Equal(t, f.store.justifiedCheckpoint.Root, jc.Root)
require.Equal(t, f.store.finalizedCheckpoint.Epoch, fc.Epoch)
require.Equal(t, f.store.finalizedCheckpoint.Root, fc.Root)
}
func TestStore_CommonAncestor(t *testing.T) {
@@ -562,8 +566,10 @@ func TestStore_InsertOptimisticChain(t *testing.T) {
require.NoError(t, err)
wsb, err := wrapper.WrappedSignedBeaconBlock(blk)
require.NoError(t, err)
blks = append(blks, &forkchoicetypes.BlockAndCheckpoints{Block: wsb.Block(), JustifiedEpoch: 1,
FinalizedEpoch: 1})
blks = append(blks, &forkchoicetypes.BlockAndCheckpoints{Block: wsb.Block(),
JustifiedCheckpoint: &ethpb.Checkpoint{Epoch: 1, Root: params.BeaconConfig().ZeroHash[:]},
FinalizedCheckpoint: &ethpb.Checkpoint{Epoch: 1, Root: params.BeaconConfig().ZeroHash[:]},
})
for i := uint64(2); i < 11; i++ {
blk := util.NewBeaconBlock()
blk.Block.Slot = types.Slot(i)
@@ -571,8 +577,10 @@ func TestStore_InsertOptimisticChain(t *testing.T) {
blk.Block.ParentRoot = copiedRoot[:]
wsb, err = wrapper.WrappedSignedBeaconBlock(blk)
require.NoError(t, err)
blks = append(blks, &forkchoicetypes.BlockAndCheckpoints{Block: wsb.Block(), JustifiedEpoch: 1,
FinalizedEpoch: 1})
blks = append(blks, &forkchoicetypes.BlockAndCheckpoints{Block: wsb.Block(),
JustifiedCheckpoint: &ethpb.Checkpoint{Epoch: 1, Root: params.BeaconConfig().ZeroHash[:]},
FinalizedCheckpoint: &ethpb.Checkpoint{Epoch: 1, Root: params.BeaconConfig().ZeroHash[:]},
})
root, err = blk.Block.HashTreeRoot()
require.NoError(t, err)
}

View File

@@ -15,7 +15,7 @@ func TestNoVote_CanFindHead(t *testing.T) {
ctx := context.Background()
// The head should always start at the finalized block.
r, err := f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err := f.Head(context.Background(), balances)
require.NoError(t, err)
if r != params.BeaconConfig().ZeroHash {
t.Errorf("Incorrect head with genesis")
@@ -28,7 +28,7 @@ func TestNoVote_CanFindHead(t *testing.T) {
state, blkRoot, err := prepareForkchoiceState(context.Background(), 0, indexToHash(2), params.BeaconConfig().ZeroHash, params.BeaconConfig().ZeroHash, 1, 1)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -39,7 +39,7 @@ func TestNoVote_CanFindHead(t *testing.T) {
state, blkRoot, err = prepareForkchoiceState(context.Background(), 0, indexToHash(1), params.BeaconConfig().ZeroHash, params.BeaconConfig().ZeroHash, 1, 1)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -52,7 +52,7 @@ func TestNoVote_CanFindHead(t *testing.T) {
state, blkRoot, err = prepareForkchoiceState(context.Background(), 0, indexToHash(3), indexToHash(1), params.BeaconConfig().ZeroHash, 1, 1)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -65,7 +65,7 @@ func TestNoVote_CanFindHead(t *testing.T) {
state, blkRoot, err = prepareForkchoiceState(context.Background(), 0, indexToHash(4), indexToHash(2), params.BeaconConfig().ZeroHash, 1, 1)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(4), r, "Incorrect head for with justified epoch at 1")
@@ -80,7 +80,7 @@ func TestNoVote_CanFindHead(t *testing.T) {
state, blkRoot, err = prepareForkchoiceState(context.Background(), 0, indexToHash(5), indexToHash(4), params.BeaconConfig().ZeroHash, 2, 1)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(4), r, "Incorrect head for with justified epoch at 1")
@@ -92,7 +92,8 @@ func TestNoVote_CanFindHead(t *testing.T) {
// head -> 4 3
// |
// 5 <- starting from 5 with justified epoch 0 should error
_, err = f.Head(context.Background(), indexToHash(5), balances)
f.store.justifiedCheckpoint.Root = indexToHash(5)
_, err = f.Head(context.Background(), balances)
wanted := "head at slot 0 with weight 0 is not eligible, finalizedEpoch 1 != 1, justifiedEpoch 2 != 1"
require.ErrorContains(t, wanted, err)
@@ -104,8 +105,8 @@ func TestNoVote_CanFindHead(t *testing.T) {
// 4 3
// |
// 5 <- head
f.store.justifiedEpoch = 2
r, err = f.Head(context.Background(), indexToHash(5), balances)
f.store.justifiedCheckpoint.Epoch = 2
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(5), r, "Incorrect head for with justified epoch at 2")
@@ -122,7 +123,7 @@ func TestNoVote_CanFindHead(t *testing.T) {
state, blkRoot, err = prepareForkchoiceState(context.Background(), 0, indexToHash(6), indexToHash(5), params.BeaconConfig().ZeroHash, 2, 1)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
r, err = f.Head(context.Background(), indexToHash(5), balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(6), r, "Incorrect head for with justified epoch at 2")
}

View File

@@ -35,7 +35,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
f := setup(jEpoch, fEpoch)
// The head should always start at the finalized block.
headRoot, err := f.Head(ctx, zeroHash, balances)
headRoot, err := f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, zeroHash, headRoot, "Incorrect head with genesis")
@@ -58,7 +58,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
f.ProcessAttestation(ctx, []uint64{0}, newRoot, fEpoch)
headRoot, err = f.Head(ctx, zeroHash, balances)
headRoot, err = f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, newRoot, headRoot, "Incorrect head for justified epoch at slot 1")
@@ -82,7 +82,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
f.ProcessAttestation(ctx, []uint64{1}, newRoot, fEpoch)
headRoot, err = f.Head(ctx, zeroHash, balances)
headRoot, err = f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, newRoot, headRoot, "Incorrect head for justified epoch at slot 2")
@@ -108,7 +108,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
f.ProcessAttestation(ctx, []uint64{2}, newRoot, fEpoch)
headRoot, err = f.Head(ctx, zeroHash, balances)
headRoot, err = f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, newRoot, headRoot, "Incorrect head for justified epoch at slot 3")
@@ -144,7 +144,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
}
require.NoError(t, f.BoostProposerRoot(ctx, args))
headRoot, err = f.Head(ctx, zeroHash, balances)
headRoot, err = f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, newRoot, headRoot, "Incorrect head for justified epoch at slot 3")
@@ -186,7 +186,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
// Regression: process attestations for C, check that it
// becomes head, we need two attestations to have C.weight = 30 > 24 = D.weight
f.ProcessAttestation(ctx, []uint64{4, 5}, indexToHash(3), fEpoch)
headRoot, err = f.Head(ctx, zeroHash, balances)
headRoot, err = f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(3), headRoot, "Incorrect head for justified epoch at slot 4")
@@ -195,7 +195,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
f := setup(jEpoch, fEpoch)
// The head should always start at the finalized block.
r, err := f.Head(ctx, zeroHash, balances)
r, err := f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, zeroHash, r, "Incorrect head with genesis")
@@ -220,7 +220,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
r, err = f.Head(ctx, zeroHash, balances)
r, err = f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, honestBlock, r, "Incorrect head for justified epoch at slot 2")
@@ -239,7 +239,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
// Ensure the head is C, the honest block.
r, err = f.Head(ctx, zeroHash, balances)
r, err = f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, honestBlock, r, "Incorrect head for justified epoch at slot 2")
@@ -260,7 +260,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
f.ProcessAttestation(ctx, votes, honestBlock, fEpoch)
// Ensure the head is STILL C, the honest block, as the honest block had proposer boost.
r, err = f.Head(ctx, zeroHash, balances)
r, err = f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, honestBlock, r, "Incorrect head for justified epoch at slot 2")
})
@@ -268,7 +268,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
f := setup(jEpoch, fEpoch)
// The head should always start at the finalized block.
r, err := f.Head(ctx, zeroHash, balances)
r, err := f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, zeroHash, r, "Incorrect head with genesis")
@@ -295,7 +295,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
// Ensure C is the head.
r, err = f.Head(ctx, zeroHash, balances)
r, err = f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, honestBlock, r, "Incorrect head for justified epoch at slot 2")
@@ -314,7 +314,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
// Ensure C is still the head after the malicious proposer reveals their block.
r, err = f.Head(ctx, zeroHash, balances)
r, err = f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, honestBlock, r, "Incorrect head for justified epoch at slot 2")
@@ -333,7 +333,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
f.ProcessAttestation(ctx, votes, maliciouslyWithheldBlock, fEpoch)
// Expect the head to have switched to B.
r, err = f.Head(ctx, zeroHash, balances)
r, err = f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, maliciouslyWithheldBlock, r, "Expected B to become the head")
})
@@ -355,7 +355,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
a := zeroHash
// The head should always start at the finalized block.
r, err := f.Head(ctx, zeroHash, balances)
r, err := f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, zeroHash, r, "Incorrect head with genesis")
@@ -374,7 +374,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
// Ensure C is the head.
r, err = f.Head(ctx, zeroHash, balances)
r, err = f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, c, r, "Incorrect head for justified epoch at slot 2")
@@ -402,7 +402,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
// Ensure C is still the head.
r, err = f.Head(ctx, zeroHash, balances)
r, err = f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, c, r, "Incorrect head for justified epoch at slot 2")
@@ -426,7 +426,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
// D cannot win without a boost.
r, err = f.Head(ctx, zeroHash, balances)
r, err = f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, c, r, "Expected C to remain the head")
@@ -442,7 +442,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
require.NoError(t, f.BoostProposerRoot(ctx, args))
// Ensure D becomes the head thanks to boosting.
r, err = f.Head(ctx, zeroHash, balances)
r, err = f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, d, r, "Expected D to become the head")
})

View File

@@ -60,12 +60,12 @@ func (s *Store) PruneThreshold() uint64 {
// head starts from justified root and then follows the best descendant links
// to find the best block for head. This function assumes a lock on s.nodesLock
func (s *Store) head(ctx context.Context, justifiedRoot [32]byte) ([32]byte, error) {
func (s *Store) head(ctx context.Context) ([32]byte, error) {
_, span := trace.StartSpan(ctx, "doublyLinkedForkchoice.head")
defer span.End()
// JustifiedRoot has to be known
justifiedNode, ok := s.nodeByRoot[justifiedRoot]
justifiedNode, ok := s.nodeByRoot[s.justifiedCheckpoint.Root]
if !ok || justifiedNode == nil {
return [32]byte{}, errUnknownJustifiedRoot
}
@@ -77,9 +77,9 @@ func (s *Store) head(ctx context.Context, justifiedRoot [32]byte) ([32]byte, err
bestDescendant = justifiedNode
}
if !bestDescendant.viableForHead(s.justifiedEpoch, s.finalizedEpoch) {
if !bestDescendant.viableForHead(s.justifiedCheckpoint.Epoch, s.finalizedCheckpoint.Epoch) {
return [32]byte{}, fmt.Errorf("head at slot %d with weight %d is not eligible, finalizedEpoch %d != %d, justifiedEpoch %d != %d",
bestDescendant.slot, bestDescendant.weight/10e9, bestDescendant.finalizedEpoch, s.finalizedEpoch, bestDescendant.justifiedEpoch, s.justifiedEpoch)
bestDescendant.slot, bestDescendant.weight/10e9, bestDescendant.finalizedEpoch, s.finalizedCheckpoint.Epoch, bestDescendant.justifiedEpoch, s.justifiedCheckpoint.Epoch)
}
// Update metrics.
@@ -134,7 +134,8 @@ func (s *Store) insert(ctx context.Context,
}
} else {
parent.children = append(parent.children, n)
if err := s.treeRootNode.updateBestDescendant(ctx, s.justifiedEpoch, s.finalizedEpoch); err != nil {
if err := s.treeRootNode.updateBestDescendant(ctx,
s.justifiedCheckpoint.Epoch, s.finalizedCheckpoint.Epoch); err != nil {
return err
}
}

View File

@@ -4,6 +4,7 @@ import (
"context"
"testing"
forkchoicetypes "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/types"
"github.com/prysmaticlabs/prysm/config/params"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/testing/assert"
@@ -22,13 +23,13 @@ func TestStore_PruneThreshold(t *testing.T) {
func TestStore_JustifiedEpoch(t *testing.T) {
j := types.Epoch(100)
f := setup(j, j)
require.Equal(t, j, f.JustifiedEpoch())
require.Equal(t, j, f.JustifiedCheckpoint().Epoch)
}
func TestStore_FinalizedEpoch(t *testing.T) {
j := types.Epoch(50)
f := setup(j, j)
require.Equal(t, j, f.FinalizedEpoch())
require.Equal(t, j, f.FinalizedCheckpoint().Epoch)
}
func TestStore_NodeCount(t *testing.T) {
@@ -78,7 +79,8 @@ func TestForkChoice_HasNode(t *testing.T) {
func TestStore_Head_UnknownJustifiedRoot(t *testing.T) {
f := setup(0, 0)
_, err := f.store.head(context.Background(), [32]byte{'a'})
f.store.justifiedCheckpoint.Root = [32]byte{'a'}
_, err := f.store.head(context.Background())
assert.ErrorContains(t, errUnknownJustifiedRoot.Error(), err)
}
@@ -90,7 +92,8 @@ func TestStore_Head_Itself(t *testing.T) {
// Since the justified node does not have a best descendant so the best node
// is itself.
h, err := f.store.head(context.Background(), indexToHash(1))
f.store.justifiedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: 0, Root: indexToHash(1)}
h, err := f.store.head(context.Background())
require.NoError(t, err)
assert.Equal(t, indexToHash(1), h)
}
@@ -110,7 +113,8 @@ func TestStore_Head_BestDescendant(t *testing.T) {
state, blkRoot, err = prepareForkchoiceState(context.Background(), 4, indexToHash(4), indexToHash(2), params.BeaconConfig().ZeroHash, 0, 0)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
h, err := f.store.head(context.Background(), indexToHash(1))
f.store.justifiedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: 0, Root: indexToHash(1)}
h, err := f.store.head(context.Background())
require.NoError(t, err)
require.Equal(t, h, indexToHash(4))
}
@@ -133,7 +137,9 @@ func TestStore_Insert(t *testing.T) {
treeRootNode := &Node{slot: 0, root: indexToHash(0)}
nodeByRoot := map[[32]byte]*Node{indexToHash(0): treeRootNode}
nodeByPayload := map[[32]byte]*Node{indexToHash(0): treeRootNode}
s := &Store{nodeByRoot: nodeByRoot, treeRootNode: treeRootNode, nodeByPayload: nodeByPayload}
jc := &forkchoicetypes.Checkpoint{Epoch: 0}
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))
assert.Equal(t, 2, len(s.nodeByRoot), "Did not insert block")

View File

@@ -3,6 +3,7 @@ package doublylinkedtree
import (
"sync"
forkchoicetypes "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/types"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
)
@@ -17,8 +18,8 @@ type ForkChoice struct {
// Store defines the fork choice store which includes block nodes and the last view of checkpoint information.
type Store struct {
justifiedEpoch types.Epoch // latest justified epoch in store.
finalizedEpoch types.Epoch // latest finalized epoch in store.
justifiedCheckpoint *forkchoicetypes.Checkpoint // latest justified epoch 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.
@@ -30,6 +31,7 @@ type Store struct {
slashedIndices map[types.ValidatorIndex]bool // the list of equivocating validator indices
nodesLock sync.RWMutex
proposerBoostLock sync.RWMutex
checkpointsLock sync.RWMutex
}
// Node defines the individual block which includes its block parent, ancestor and how much weight accounted for it.

View File

@@ -44,11 +44,11 @@ func (f *ForkChoice) UpdateUnrealizedCheckpoints() {
for _, node := range f.store.nodeByRoot {
node.justifiedEpoch = node.unrealizedJustifiedEpoch
node.finalizedEpoch = node.unrealizedFinalizedEpoch
if node.justifiedEpoch > f.store.justifiedEpoch {
f.store.justifiedEpoch = node.justifiedEpoch
if node.justifiedEpoch > f.store.justifiedCheckpoint.Epoch {
f.store.justifiedCheckpoint.Epoch = node.justifiedEpoch
}
if node.finalizedEpoch > f.store.finalizedEpoch {
f.store.finalizedEpoch = node.finalizedEpoch
if node.finalizedEpoch > f.store.finalizedCheckpoint.Epoch {
f.store.finalizedCheckpoint.Epoch = node.finalizedEpoch
}
}
}

View File

@@ -4,9 +4,9 @@ import (
"context"
"testing"
forkchoicetypes "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/types"
"github.com/prysmaticlabs/prysm/config/params"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/testing/require"
)
@@ -80,17 +80,17 @@ func TestStore_LongFork(t *testing.T) {
// Add an attestation to c, it is head
f.ProcessAttestation(ctx, []uint64{0}, [32]byte{'c'}, 1)
headRoot, err := f.Head(ctx, [32]byte{}, []uint64{100})
headRoot, err := f.Head(ctx, []uint64{100})
require.NoError(t, err)
require.Equal(t, [32]byte{'c'}, headRoot)
// D is head even though its weight is lower.
hr := [32]byte{'d'}
state, blkRoot, err = prepareForkchoiceState(ctx, 103, hr, [32]byte{'b'}, [32]byte{'D'}, 2, 1)
ha := [32]byte{'a'}
state, blkRoot, err = prepareForkchoiceState(ctx, 103, [32]byte{'d'}, [32]byte{'b'}, [32]byte{'D'}, 2, 1)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
require.NoError(t, f.UpdateJustifiedCheckpoint(&ethpb.Checkpoint{Epoch: 2, Root: hr[:]}))
headRoot, err = f.Head(ctx, [32]byte{}, []uint64{100})
require.NoError(t, f.UpdateJustifiedCheckpoint(&forkchoicetypes.Checkpoint{Epoch: 2, Root: ha}))
headRoot, err = f.Head(ctx, []uint64{100})
require.NoError(t, err)
require.Equal(t, [32]byte{'d'}, headRoot)
require.Equal(t, uint64(0), f.store.nodeByRoot[[32]byte{'d'}].weight)
@@ -98,7 +98,7 @@ func TestStore_LongFork(t *testing.T) {
// Update unrealized justification, c becomes head
f.UpdateUnrealizedCheckpoints()
headRoot, err = f.Head(ctx, [32]byte{}, []uint64{100})
headRoot, err = f.Head(ctx, []uint64{100})
require.NoError(t, err)
require.Equal(t, [32]byte{'c'}, headRoot)
}
@@ -157,30 +157,31 @@ func TestStore_NoDeadLock(t *testing.T) {
// Epoch 3
// Current Head is H
headRoot, err := f.Head(ctx, [32]byte{}, []uint64{100})
headRoot, err := f.Head(ctx, []uint64{100})
require.NoError(t, err)
require.Equal(t, [32]byte{'h'}, headRoot)
require.Equal(t, types.Epoch(0), f.JustifiedEpoch())
require.Equal(t, types.Epoch(0), f.JustifiedCheckpoint().Epoch)
// Insert Block I, it becomes Head
hr := [32]byte{'i'}
state, blkRoot, err = prepareForkchoiceState(ctx, 108, hr, [32]byte{'f'}, [32]byte{'I'}, 1, 0)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
require.NoError(t, f.UpdateJustifiedCheckpoint(&ethpb.Checkpoint{Epoch: 1, Root: hr[:]}))
headRoot, err = f.Head(ctx, [32]byte{}, []uint64{100})
ha := [32]byte{'a'}
require.NoError(t, f.UpdateJustifiedCheckpoint(&forkchoicetypes.Checkpoint{Epoch: 1, Root: ha}))
headRoot, err = f.Head(ctx, []uint64{100})
require.NoError(t, err)
require.Equal(t, [32]byte{'i'}, headRoot)
require.Equal(t, types.Epoch(1), f.JustifiedEpoch())
require.Equal(t, types.Epoch(0), f.FinalizedEpoch())
require.Equal(t, types.Epoch(1), f.JustifiedCheckpoint().Epoch)
require.Equal(t, types.Epoch(0), f.FinalizedCheckpoint().Epoch)
// Realized Justified checkpoints, H becomes head
f.UpdateUnrealizedCheckpoints()
headRoot, err = f.Head(ctx, [32]byte{}, []uint64{100})
headRoot, err = f.Head(ctx, []uint64{100})
require.NoError(t, err)
require.Equal(t, [32]byte{'h'}, headRoot)
require.Equal(t, types.Epoch(2), f.JustifiedEpoch())
require.Equal(t, types.Epoch(1), f.FinalizedEpoch())
require.Equal(t, types.Epoch(2), f.JustifiedCheckpoint().Epoch)
require.Equal(t, types.Epoch(1), f.FinalizedCheckpoint().Epoch)
}
// Epoch 1 | Epoch 2
@@ -225,10 +226,10 @@ func TestStore_ForkNextEpoch(t *testing.T) {
// Insert an attestation to H, H is head
f.ProcessAttestation(ctx, []uint64{0}, [32]byte{'h'}, 1)
headRoot, err := f.Head(ctx, [32]byte{}, []uint64{100})
headRoot, err := f.Head(ctx, []uint64{100})
require.NoError(t, err)
require.Equal(t, [32]byte{'h'}, headRoot)
require.Equal(t, types.Epoch(0), f.JustifiedEpoch())
require.Equal(t, types.Epoch(0), f.JustifiedCheckpoint().Epoch)
// D arrives late, D is head
state, blkRoot, err = prepareForkchoiceState(ctx, 103, [32]byte{'d'}, [32]byte{'c'}, [32]byte{'D'}, 0, 0)
@@ -236,10 +237,10 @@ func TestStore_ForkNextEpoch(t *testing.T) {
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
require.NoError(t, f.store.setUnrealizedJustifiedEpoch([32]byte{'d'}, 1))
f.UpdateUnrealizedCheckpoints()
headRoot, err = f.Head(ctx, [32]byte{}, []uint64{100})
headRoot, err = f.Head(ctx, []uint64{100})
require.NoError(t, err)
require.Equal(t, [32]byte{'d'}, headRoot)
require.Equal(t, types.Epoch(1), f.JustifiedEpoch())
require.Equal(t, types.Epoch(1), f.JustifiedCheckpoint().Epoch)
require.Equal(t, uint64(0), f.store.nodeByRoot[[32]byte{'d'}].weight)
require.Equal(t, uint64(100), f.store.nodeByRoot[[32]byte{'h'}].weight)
}

View File

@@ -4,6 +4,7 @@ import (
"context"
"testing"
forkchoicetypes "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/types"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/testing/assert"
"github.com/prysmaticlabs/prysm/testing/require"
@@ -15,7 +16,7 @@ func TestVotes_CanFindHead(t *testing.T) {
ctx := context.Background()
// The head should always start at the finalized block.
r, err := f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err := f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, params.BeaconConfig().ZeroHash, r, "Incorrect head with genesis")
@@ -27,7 +28,7 @@ func TestVotes_CanFindHead(t *testing.T) {
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -39,7 +40,7 @@ func TestVotes_CanFindHead(t *testing.T) {
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -48,7 +49,7 @@ func TestVotes_CanFindHead(t *testing.T) {
// / \
// 2 1 <- +vote, new head
f.ProcessAttestation(context.Background(), []uint64{0}, indexToHash(1), 2)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(1), r, "Incorrect head for with justified epoch at 1")
@@ -57,7 +58,7 @@ func TestVotes_CanFindHead(t *testing.T) {
// / \
// vote, new head -> 2 1
f.ProcessAttestation(context.Background(), []uint64{1}, indexToHash(2), 2)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -71,7 +72,7 @@ func TestVotes_CanFindHead(t *testing.T) {
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -82,7 +83,7 @@ func TestVotes_CanFindHead(t *testing.T) {
// |
// 3 <- new vote
f.ProcessAttestation(context.Background(), []uint64{0}, indexToHash(3), 3)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -93,7 +94,7 @@ func TestVotes_CanFindHead(t *testing.T) {
// |
// 3 <- head
f.ProcessAttestation(context.Background(), []uint64{1}, indexToHash(1), 3)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(3), r, "Incorrect head for with justified epoch at 1")
@@ -109,7 +110,7 @@ func TestVotes_CanFindHead(t *testing.T) {
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(4), r, "Incorrect head for with justified epoch at 1")
@@ -127,7 +128,7 @@ func TestVotes_CanFindHead(t *testing.T) {
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(4), r, "Incorrect head for with justified epoch at 1")
@@ -188,7 +189,7 @@ func TestVotes_CanFindHead(t *testing.T) {
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(6), r, "Incorrect head for with justified epoch at 1")
@@ -209,9 +210,9 @@ func TestVotes_CanFindHead(t *testing.T) {
// 8
// |
// 9 <- head
f.store.justifiedEpoch = 2
f.store.finalizedEpoch = 2
r, err = f.Head(context.Background(), indexToHash(5), balances)
f.store.justifiedCheckpoint = &forkchoicetypes.Checkpoint{Root: indexToHash(5), Epoch: 2}
f.store.finalizedCheckpoint = &forkchoicetypes.Checkpoint{Root: indexToHash(5), Epoch: 2}
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(9), r, "Incorrect head for with justified epoch at 2")
@@ -237,7 +238,7 @@ func TestVotes_CanFindHead(t *testing.T) {
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
r, err = f.Head(context.Background(), indexToHash(5), balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(9), r, "Incorrect head for with justified epoch at 2")
@@ -246,28 +247,28 @@ func TestVotes_CanFindHead(t *testing.T) {
// The new validators voted for 10.
f.ProcessAttestation(context.Background(), []uint64{2, 3, 4}, indexToHash(10), 5)
// The new head should be 10.
r, err = f.Head(context.Background(), indexToHash(5), balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(10), r, "Incorrect head for with justified epoch at 2")
// Set the balances of the last 2 validators to 0.
balances = []uint64{1, 1, 1, 0, 0}
// The head should be back to 9.
r, err = f.Head(context.Background(), indexToHash(5), balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(9), r, "Incorrect head for with justified epoch at 1")
// Set the balances back to normal.
balances = []uint64{1, 1, 1, 1, 1}
// The head should be back to 10.
r, err = f.Head(context.Background(), indexToHash(5), balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(10), r, "Incorrect head for with justified epoch at 2")
// Remove the last 2 validators.
balances = []uint64{1, 1, 1}
// The head should be back to 9.
r, err = f.Head(context.Background(), indexToHash(5), balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(9), r, "Incorrect head for with justified epoch at 1")
@@ -276,7 +277,7 @@ func TestVotes_CanFindHead(t *testing.T) {
require.NoError(t, f.store.prune(context.Background(), indexToHash(5)))
assert.Equal(t, 11, len(f.store.nodeByRoot), "Incorrect nodes length after prune")
r, err = f.Head(context.Background(), indexToHash(5), balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(9), r, "Incorrect head for with justified epoch at 2")
@@ -300,7 +301,7 @@ func TestVotes_CanFindHead(t *testing.T) {
require.NoError(t, f.store.prune(context.Background(), indexToHash(5)))
assert.Equal(t, 5, len(f.store.nodeByRoot), "Incorrect nodes length after prune")
r, err = f.Head(context.Background(), indexToHash(5), balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(9), r, "Incorrect head for with justified epoch at 2")
@@ -318,7 +319,7 @@ func TestVotes_CanFindHead(t *testing.T) {
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
r, err = f.Head(context.Background(), indexToHash(5), balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(11), r, "Incorrect head for with justified epoch at 2")
}

View File

@@ -23,14 +23,14 @@ type ForkChoicer interface {
// HeadRetriever retrieves head root and optimistic info of the current chain.
type HeadRetriever interface {
Head(context.Context, [32]byte, []uint64) ([32]byte, error)
Head(context.Context, []uint64) ([32]byte, error)
Tips() ([][32]byte, []types.Slot)
IsOptimistic(root [32]byte) (bool, error)
}
// 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
}
@@ -59,8 +59,8 @@ type Getter interface {
AncestorRoot(ctx context.Context, root [32]byte, slot types.Slot) ([]byte, error)
CommonAncestorRoot(ctx context.Context, root1 [32]byte, root2 [32]byte) ([32]byte, error)
IsCanonical(root [32]byte) bool
FinalizedEpoch() types.Epoch
JustifiedEpoch() types.Epoch
FinalizedCheckpoint() *forkchoicetypes.Checkpoint
JustifiedCheckpoint() *forkchoicetypes.Checkpoint
ForkChoiceNodes() []*ethpb.ForkChoiceNode
NodeCount() int
}
@@ -69,6 +69,6 @@ type Getter interface {
type Setter interface {
SetOptimisticToValid(context.Context, [fieldparams.RootLength]byte) error
SetOptimisticToInvalid(context.Context, [fieldparams.RootLength]byte, [fieldparams.RootLength]byte, [fieldparams.RootLength]byte) ([][32]byte, error)
UpdateJustifiedCheckpoint(*ethpb.Checkpoint) error
UpdateFinalizedCheckpoint(*ethpb.Checkpoint) error
UpdateJustifiedCheckpoint(*forkchoicetypes.Checkpoint) error
UpdateFinalizedCheckpoint(*forkchoicetypes.Checkpoint) error
}

View File

@@ -4,6 +4,7 @@ import (
"context"
"testing"
forkchoicetypes "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/types"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
v3 "github.com/prysmaticlabs/prysm/beacon-chain/state/v3"
"github.com/prysmaticlabs/prysm/config/params"
@@ -61,7 +62,7 @@ func TestFFGUpdates_OneBranch(t *testing.T) {
ctx := context.Background()
// The head should always start at the finalized block.
r, err := f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err := f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, params.BeaconConfig().ZeroHash, r, "Incorrect head with genesis")
@@ -91,7 +92,7 @@ func TestFFGUpdates_OneBranch(t *testing.T) {
// 2
// |
// 3 <- head
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(3), r, "Incorrect head for with justified epoch at 0")
@@ -103,8 +104,9 @@ func TestFFGUpdates_OneBranch(t *testing.T) {
// 2 <- head
// |
// 3
f.store.justifiedEpoch = 1
r, err = f.Head(context.Background(), indexToHash(2), balances)
jc := &forkchoicetypes.Checkpoint{Epoch: 1, Root: indexToHash(2)}
f.store.justifiedCheckpoint = jc
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head with justified epoch at 1")
@@ -116,8 +118,9 @@ func TestFFGUpdates_OneBranch(t *testing.T) {
// 2 <- start
// |
// 3 <- head
f.store.justifiedEpoch = 2
r, err = f.Head(context.Background(), indexToHash(3), balances)
jc = &forkchoicetypes.Checkpoint{Epoch: 2, Root: indexToHash(3)}
f.store.justifiedCheckpoint = jc
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(3), r, "Incorrect head with justified epoch at 2")
}
@@ -127,7 +130,7 @@ func TestFFGUpdates_TwoBranches(t *testing.T) {
f := setup(0, 0)
ctx := context.Background()
r, err := f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err := f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, params.BeaconConfig().ZeroHash, r, "Incorrect head with genesis")
@@ -188,7 +191,7 @@ func TestFFGUpdates_TwoBranches(t *testing.T) {
// 7 8
// | |
// 9 10 <-- head
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(10), r, "Incorrect head with justified epoch at 0")
@@ -218,7 +221,7 @@ func TestFFGUpdates_TwoBranches(t *testing.T) {
// 7 8
// | |
// head -> 9 10
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(9), r, "Incorrect head with justified epoch at 0")
@@ -248,19 +251,22 @@ func TestFFGUpdates_TwoBranches(t *testing.T) {
// 7 8
// | |
// 9 10 <-- head
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(10), r, "Incorrect head with justified epoch at 0")
f.store.justifiedEpoch = 1
r, err = f.Head(context.Background(), indexToHash(1), balances)
jc := &forkchoicetypes.Checkpoint{Epoch: 1, Root: indexToHash(1)}
f.store.justifiedCheckpoint = jc
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(7), r, "Incorrect head with justified epoch at 0")
}
func setup(justifiedEpoch, finalizedEpoch types.Epoch) *ForkChoice {
f := New(justifiedEpoch, finalizedEpoch)
f := New()
f.store.nodesIndices[params.BeaconConfig().ZeroHash] = 0
f.store.justifiedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: justifiedEpoch, Root: params.BeaconConfig().ZeroHash}
f.store.finalizedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: finalizedEpoch, Root: params.BeaconConfig().ZeroHash}
f.store.nodes = append(f.store.nodes, &Node{
slot: 0,
root: params.BeaconConfig().ZeroHash,
@@ -271,6 +277,5 @@ func setup(justifiedEpoch, finalizedEpoch types.Epoch) *ForkChoice {
bestDescendant: NonExistentNode,
weight: 0,
})
return f
}

View File

@@ -15,7 +15,7 @@ func TestNoVote_CanFindHead(t *testing.T) {
ctx := context.Background()
// The head should always start at the finalized block.
r, err := f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err := f.Head(context.Background(), balances)
require.NoError(t, err)
if r != params.BeaconConfig().ZeroHash {
t.Errorf("Incorrect head with genesis")
@@ -28,7 +28,7 @@ func TestNoVote_CanFindHead(t *testing.T) {
state, blkRoot, err := prepareForkchoiceState(context.Background(), 0, indexToHash(2), params.BeaconConfig().ZeroHash, params.BeaconConfig().ZeroHash, 1, 1)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -39,7 +39,7 @@ func TestNoVote_CanFindHead(t *testing.T) {
state, blkRoot, err = prepareForkchoiceState(context.Background(), 0, indexToHash(1), params.BeaconConfig().ZeroHash, params.BeaconConfig().ZeroHash, 1, 1)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -52,7 +52,7 @@ func TestNoVote_CanFindHead(t *testing.T) {
state, blkRoot, err = prepareForkchoiceState(context.Background(), 0, indexToHash(3), indexToHash(1), params.BeaconConfig().ZeroHash, 1, 1)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -65,7 +65,7 @@ func TestNoVote_CanFindHead(t *testing.T) {
state, blkRoot, err = prepareForkchoiceState(context.Background(), 0, indexToHash(4), indexToHash(2), params.BeaconConfig().ZeroHash, 1, 1)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(4), r, "Incorrect head for with justified epoch at 1")
@@ -80,7 +80,7 @@ func TestNoVote_CanFindHead(t *testing.T) {
state, blkRoot, err = prepareForkchoiceState(context.Background(), 0, indexToHash(5), indexToHash(4), params.BeaconConfig().ZeroHash, 2, 1)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(4), r, "Incorrect head for with justified epoch at 1")
@@ -92,7 +92,8 @@ func TestNoVote_CanFindHead(t *testing.T) {
// head -> 4 3
// |
// 5 <- starting from 5 with justified epoch 0 should error
_, err = f.Head(context.Background(), indexToHash(5), balances)
f.store.justifiedCheckpoint.Root = indexToHash(5)
_, err = f.Head(context.Background(), balances)
wanted := "head at slot 0 with weight 0 is not eligible, finalizedEpoch 1 != 1, justifiedEpoch 2 != 1"
require.ErrorContains(t, wanted, err)
@@ -104,8 +105,8 @@ func TestNoVote_CanFindHead(t *testing.T) {
// 4 3
// |
// 5 <- head
f.store.justifiedEpoch = 2
r, err = f.Head(context.Background(), indexToHash(5), balances)
f.store.justifiedCheckpoint.Epoch = 2
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(5), r, "Incorrect head for with justified epoch at 2")
@@ -122,7 +123,7 @@ func TestNoVote_CanFindHead(t *testing.T) {
state, blkRoot, err = prepareForkchoiceState(context.Background(), 0, indexToHash(6), indexToHash(5), params.BeaconConfig().ZeroHash, 2, 1)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
r, err = f.Head(context.Background(), indexToHash(5), balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(6), r, "Incorrect head for with justified epoch at 2")
}

View File

@@ -35,7 +35,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
f := setup(jEpoch, fEpoch)
// The head should always start at the finalized block.
headRoot, err := f.Head(ctx, zeroHash, balances)
headRoot, err := f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, zeroHash, headRoot, "Incorrect head with genesis")
@@ -57,7 +57,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
f.ProcessAttestation(ctx, []uint64{0}, newRoot, fEpoch)
headRoot, err = f.Head(ctx, zeroHash, balances)
headRoot, err = f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, newRoot, headRoot, "Incorrect head for justified epoch at slot 1")
@@ -81,7 +81,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
f.ProcessAttestation(ctx, []uint64{1}, newRoot, fEpoch)
headRoot, err = f.Head(ctx, zeroHash, balances)
headRoot, err = f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, newRoot, headRoot, "Incorrect head for justified epoch at slot 2")
@@ -107,7 +107,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
f.ProcessAttestation(ctx, []uint64{2}, newRoot, fEpoch)
headRoot, err = f.Head(ctx, zeroHash, balances)
headRoot, err = f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, newRoot, headRoot, "Incorrect head for justified epoch at slot 3")
@@ -142,7 +142,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
SecondsIntoSlot: 0,
}
require.NoError(t, f.BoostProposerRoot(ctx, args))
headRoot, err = f.Head(ctx, zeroHash, balances)
headRoot, err = f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, newRoot, headRoot, "Incorrect head for justified epoch at slot 3")
@@ -180,7 +180,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
// Regression: process attestations for C, check that it
// becomes head, we need two attestations to have C.weight = 30 > 24 = D.weight
f.ProcessAttestation(ctx, []uint64{4, 5}, indexToHash(3), fEpoch)
headRoot, err = f.Head(ctx, zeroHash, balances)
headRoot, err = f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(3), headRoot, "Incorrect head for justified epoch at slot 4")
})
@@ -188,7 +188,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
f := setup(jEpoch, fEpoch)
// The head should always start at the finalized block.
r, err := f.Head(ctx, zeroHash, balances)
r, err := f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, zeroHash, r, "Incorrect head with genesis")
@@ -213,7 +213,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
r, err = f.Head(ctx, zeroHash, balances)
r, err = f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, honestBlock, r, "Incorrect head for justified epoch at slot 2")
@@ -232,7 +232,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
// Ensure the head is C, the honest block.
r, err = f.Head(ctx, zeroHash, balances)
r, err = f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, honestBlock, r, "Incorrect head for justified epoch at slot 2")
@@ -253,7 +253,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
f.ProcessAttestation(ctx, votes, honestBlock, fEpoch)
// Ensure the head is STILL C, the honest block, as the honest block had proposer boost.
r, err = f.Head(ctx, zeroHash, balances)
r, err = f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, honestBlock, r, "Incorrect head for justified epoch at slot 2")
})
@@ -261,7 +261,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
f := setup(jEpoch, fEpoch)
// The head should always start at the finalized block.
r, err := f.Head(ctx, zeroHash, balances)
r, err := f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, zeroHash, r, "Incorrect head with genesis")
@@ -288,7 +288,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
// Ensure C is the head.
r, err = f.Head(ctx, zeroHash, balances)
r, err = f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, honestBlock, r, "Incorrect head for justified epoch at slot 2")
@@ -307,7 +307,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
// Ensure C is still the head after the malicious proposer reveals their block.
r, err = f.Head(ctx, zeroHash, balances)
r, err = f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, honestBlock, r, "Incorrect head for justified epoch at slot 2")
@@ -326,7 +326,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
f.ProcessAttestation(ctx, votes, maliciouslyWithheldBlock, fEpoch)
// Expect the head to have switched to B.
r, err = f.Head(ctx, zeroHash, balances)
r, err = f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, maliciouslyWithheldBlock, r, "Expected B to become the head")
})
@@ -348,7 +348,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
a := zeroHash
// The head should always start at the finalized block.
r, err := f.Head(ctx, zeroHash, balances)
r, err := f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, zeroHash, r, "Incorrect head with genesis")
@@ -367,7 +367,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
// Ensure C is the head.
r, err = f.Head(ctx, zeroHash, balances)
r, err = f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, c, r, "Incorrect head for justified epoch at slot 2")
@@ -395,7 +395,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
// Ensure C is still the head.
r, err = f.Head(ctx, zeroHash, balances)
r, err = f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, c, r, "Incorrect head for justified epoch at slot 2")
@@ -419,7 +419,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
// D cannot win without a boost.
r, err = f.Head(ctx, zeroHash, balances)
r, err = f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, c, r, "Expected C to remain the head")
@@ -435,7 +435,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
require.NoError(t, f.BoostProposerRoot(ctx, args))
// Ensure D becomes the head thanks to boosting.
r, err = f.Head(ctx, zeroHash, balances)
r, err = f.Head(ctx, balances)
require.NoError(t, err)
assert.Equal(t, d, r, "Expected D to become the head")
})

View File

@@ -29,17 +29,17 @@ const defaultPruneThreshold = 256
var lastHeadRoot [32]byte
// New initializes a new fork choice store.
func New(justifiedEpoch, finalizedEpoch types.Epoch) *ForkChoice {
func New() *ForkChoice {
s := &Store{
justifiedEpoch: justifiedEpoch,
finalizedEpoch: finalizedEpoch,
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{},
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,
}
b := make([]uint64, 0)
@@ -49,11 +49,7 @@ func New(justifiedEpoch, finalizedEpoch types.Epoch) *ForkChoice {
// Head returns the head root from fork choice store.
// It firsts computes validator's balance changes then recalculates block tree from leaves to root.
func (f *ForkChoice) Head(
ctx context.Context,
justifiedRoot [32]byte,
justifiedStateBalances []uint64,
) ([32]byte, error) {
func (f *ForkChoice) Head(ctx context.Context, justifiedStateBalances []uint64) ([32]byte, error) {
ctx, span := trace.StartSpan(ctx, "protoArrayForkChoice.Head")
defer span.End()
f.votesLock.Lock()
@@ -76,7 +72,7 @@ func (f *ForkChoice) Head(
}
f.balances = newBalances
return f.store.head(ctx, justifiedRoot)
return f.store.head(ctx)
}
// ProcessAttestation processes attestation for vote accounting, it iterates around validator indices
@@ -120,7 +116,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()
@@ -273,14 +269,18 @@ func (s *Store) PruneThreshold() uint64 {
return s.pruneThreshold
}
// JustifiedEpoch of fork choice store.
func (f *ForkChoice) JustifiedEpoch() types.Epoch {
return f.store.justifiedEpoch
// JustifiedCheckpoint of fork choice store.
func (f *ForkChoice) JustifiedCheckpoint() *forkchoicetypes.Checkpoint {
f.store.checkpointsLock.RLock()
defer f.store.checkpointsLock.RUnlock()
return f.store.justifiedCheckpoint
}
// FinalizedEpoch of fork choice store.
func (f *ForkChoice) FinalizedEpoch() types.Epoch {
return f.store.finalizedEpoch
// FinalizedCheckpoint of fork choice store.
func (f *ForkChoice) FinalizedCheckpoint() *forkchoicetypes.Checkpoint {
f.store.checkpointsLock.RLock()
defer f.store.checkpointsLock.RUnlock()
return f.store.finalizedCheckpoint
}
// proposerBoost of fork choice store.
@@ -291,20 +291,23 @@ func (s *Store) proposerBoost() [fieldparams.RootLength]byte {
}
// head starts from justified root and then follows the best descendant links
// to find the best block for head.
func (s *Store) head(ctx context.Context, justifiedRoot [32]byte) ([32]byte, error) {
// to find the best block for head. It assumes the caller has a lock on nodes.
func (s *Store) head(ctx context.Context) ([32]byte, error) {
ctx, span := trace.StartSpan(ctx, "protoArrayForkChoice.head")
defer span.End()
// Justified index has to be valid in node indices map, and can not be out of bound.
justifiedIndex, ok := s.nodesIndices[justifiedRoot]
if s.justifiedCheckpoint == nil {
return [32]byte{}, errInvalidNilCheckpoint
}
justifiedIndex, ok := s.nodesIndices[s.justifiedCheckpoint.Root]
if !ok {
return [32]byte{}, errUnknownJustifiedRoot
}
if justifiedIndex >= uint64(len(s.nodes)) {
return [32]byte{}, errInvalidJustifiedIndex
}
justifiedNode := s.nodes[justifiedIndex]
bestDescendantIndex := justifiedNode.bestDescendant
// If the justified node doesn't have a best descendant,
@@ -315,12 +318,11 @@ func (s *Store) head(ctx context.Context, justifiedRoot [32]byte) ([32]byte, err
if bestDescendantIndex >= uint64(len(s.nodes)) {
return [32]byte{}, errInvalidBestDescendantIndex
}
bestNode := s.nodes[bestDescendantIndex]
if !s.viableForHead(bestNode) {
return [32]byte{}, fmt.Errorf("head at slot %d with weight %d is not eligible, finalizedEpoch %d != %d, justifiedEpoch %d != %d",
bestNode.slot, bestNode.weight/10e9, bestNode.finalizedEpoch, s.finalizedEpoch, bestNode.justifiedEpoch, s.justifiedEpoch)
bestNode.slot, bestNode.weight/10e9, bestNode.finalizedEpoch, s.finalizedCheckpoint.Epoch, bestNode.justifiedEpoch, s.justifiedCheckpoint.Epoch)
}
// Update metrics.
@@ -743,10 +745,12 @@ func (s *Store) leadsToViableHead(node *Node) (bool, error) {
// Any node with diff finalized or justified epoch than the ones in fork choice store
// should not be viable to head.
func (s *Store) viableForHead(node *Node) bool {
s.checkpointsLock.RLock()
defer s.checkpointsLock.RUnlock()
// `node` is viable if its justified epoch and finalized epoch are the same as the one in `Store`.
// It's also viable if we are in genesis epoch.
justified := s.justifiedEpoch == node.justifiedEpoch || s.justifiedEpoch == 0
finalized := s.finalizedEpoch == node.finalizedEpoch || s.finalizedEpoch == 0
justified := s.justifiedCheckpoint.Epoch == node.justifiedEpoch || s.justifiedCheckpoint.Epoch == 0
finalized := s.finalizedCheckpoint.Epoch == node.finalizedEpoch || s.finalizedCheckpoint.Epoch == 0
return justified && finalized
}
@@ -857,25 +861,25 @@ func (f *ForkChoice) InsertSlashedIndex(ctx context.Context, index types.Validat
}
}
// UpdateJustifiedCheckpoint sets the justified epoch to the given one
func (f *ForkChoice) UpdateJustifiedCheckpoint(jc *pbrpc.Checkpoint) error {
// UpdateJustifiedCheckpoint sets the justified checkpoint to the given one
func (f *ForkChoice) UpdateJustifiedCheckpoint(jc *forkchoicetypes.Checkpoint) error {
if jc == nil {
return errInvalidNilCheckpoint
}
f.store.nodesLock.Lock()
defer f.store.nodesLock.Unlock()
f.store.justifiedEpoch = jc.Epoch
f.store.checkpointsLock.Lock()
defer f.store.checkpointsLock.Unlock()
f.store.justifiedCheckpoint = jc
return nil
}
// UpdateFinalizedCheckpoint sets the finalized epoch to the given one
func (f *ForkChoice) UpdateFinalizedCheckpoint(fc *pbrpc.Checkpoint) error {
// UpdateFinalizedCheckpoint sets the finalized checkpoint to the given one
func (f *ForkChoice) UpdateFinalizedCheckpoint(fc *forkchoicetypes.Checkpoint) error {
if fc == nil {
return errInvalidNilCheckpoint
}
f.store.nodesLock.Lock()
defer f.store.nodesLock.Unlock()
f.store.finalizedEpoch = fc.Epoch
f.store.checkpointsLock.Lock()
defer f.store.checkpointsLock.Unlock()
f.store.finalizedCheckpoint = fc
return nil
}
@@ -895,7 +899,7 @@ func (f *ForkChoice) InsertOptimisticChain(ctx context.Context, chain []*forkcho
}
if err := f.store.insert(ctx,
b.Slot(), r, parentRoot, payloadHash,
chain[i].JustifiedEpoch, chain[i].FinalizedEpoch); err != nil {
chain[i].JustifiedCheckpoint.Epoch, chain[i].FinalizedCheckpoint.Epoch); err != nil {
return err
}
}

View File

@@ -28,13 +28,13 @@ func TestStore_PruneThreshold(t *testing.T) {
func TestStore_JustifiedEpoch(t *testing.T) {
j := types.Epoch(100)
f := setup(j, j)
require.Equal(t, j, f.JustifiedEpoch())
require.Equal(t, j, f.JustifiedCheckpoint().Epoch)
}
func TestStore_FinalizedEpoch(t *testing.T) {
j := types.Epoch(50)
f := setup(j, j)
require.Equal(t, j, f.FinalizedEpoch())
require.Equal(t, j, f.FinalizedCheckpoint().Epoch)
}
func TestForkChoice_HasNode(t *testing.T) {
@@ -51,8 +51,9 @@ func TestForkChoice_HasNode(t *testing.T) {
func TestStore_Head_UnknownJustifiedRoot(t *testing.T) {
s := &Store{nodesIndices: make(map[[32]byte]uint64)}
s.justifiedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: 0, Root: [32]byte{'a'}}
_, err := s.head(context.Background(), [32]byte{})
_, err := s.head(context.Background())
assert.ErrorContains(t, errUnknownJustifiedRoot.Error(), err)
}
@@ -61,8 +62,9 @@ func TestStore_Head_UnknownJustifiedIndex(t *testing.T) {
indices := make(map[[32]byte]uint64)
indices[r] = 1
s := &Store{nodesIndices: indices}
s.justifiedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: 0, Root: r}
_, err := s.head(context.Background(), r)
_, err := s.head(context.Background())
assert.ErrorContains(t, errInvalidJustifiedIndex.Error(), err)
}
@@ -73,7 +75,9 @@ func TestStore_Head_Itself(t *testing.T) {
// Since the justified node does not have a best descendant so the best node
// is itself.
s := &Store{nodesIndices: indices, nodes: []*Node{{root: r, parent: NonExistentNode, bestDescendant: NonExistentNode}}, canonicalNodes: make(map[[32]byte]bool)}
h, err := s.head(context.Background(), r)
s.justifiedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: 0, Root: r}
s.finalizedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: 0, Root: r}
h, err := s.head(context.Background())
require.NoError(t, err)
assert.Equal(t, r, h)
}
@@ -86,7 +90,9 @@ func TestStore_Head_BestDescendant(t *testing.T) {
// Since the justified node's best descendant is at index 1, and its root is `best`,
// the head should be `best`.
s := &Store{nodesIndices: indices, nodes: []*Node{{root: r, bestDescendant: 1, parent: NonExistentNode}, {root: best, parent: 0}}, canonicalNodes: make(map[[32]byte]bool)}
h, err := s.head(context.Background(), r)
s.justifiedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: 0, Root: r}
s.finalizedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: 0, Root: r}
h, err := s.head(context.Background())
require.NoError(t, err)
assert.Equal(t, best, h)
}
@@ -99,7 +105,9 @@ func TestStore_Head_ContextCancelled(t *testing.T) {
s := &Store{nodesIndices: indices, nodes: []*Node{{root: r, parent: NonExistentNode, bestDescendant: 1}, {root: best, parent: 0}}, canonicalNodes: make(map[[32]byte]bool)}
cancel()
_, err := s.head(ctx, r)
s.justifiedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: 0, Root: r}
s.finalizedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: 0, Root: r}
_, err := s.head(ctx)
require.ErrorContains(t, "context canceled", err)
}
@@ -123,6 +131,8 @@ func TestStore_Insert_KnownParent(t *testing.T) {
p := [32]byte{'B'}
s.nodesIndices[p] = 0
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))
assert.Equal(t, 2, len(s.nodes), "Did not insert block")
assert.Equal(t, 2, len(s.nodesIndices), "Did not insert block")
@@ -150,6 +160,8 @@ func TestStore_ApplyScoreChanges_UpdateWeightsPositiveDelta(t *testing.T) {
// Each node gets one unique vote. The weight should look like 103 <- 102 <- 101 because
// they get propagated back.
s.justifiedCheckpoint = &forkchoicetypes.Checkpoint{}
s.finalizedCheckpoint = &forkchoicetypes.Checkpoint{}
require.NoError(t, s.applyWeightChanges(context.Background(), []uint64{}, []int{1, 1, 1}))
assert.Equal(t, uint64(103), s.nodes[0].weight)
assert.Equal(t, uint64(102), s.nodes[1].weight)
@@ -165,6 +177,8 @@ func TestStore_ApplyScoreChanges_UpdateWeightsNegativeDelta(t *testing.T) {
// Each node gets one unique vote which contributes to negative delta.
// The weight should look like 97 <- 98 <- 99 because they get propagated back.
s.justifiedCheckpoint = &forkchoicetypes.Checkpoint{}
s.finalizedCheckpoint = &forkchoicetypes.Checkpoint{}
require.NoError(t, s.applyWeightChanges(context.Background(), []uint64{}, []int{-1, -1, -1}))
assert.Equal(t, uint64(97), s.nodes[0].weight)
assert.Equal(t, uint64(98), s.nodes[1].weight)
@@ -179,6 +193,8 @@ func TestStore_ApplyScoreChanges_UpdateWeightsMixedDelta(t *testing.T) {
{parent: 1, root: [32]byte{'A'}, weight: 100}}}
// Each node gets one mixed vote. The weight should look like 100 <- 200 <- 250.
s.justifiedCheckpoint = &forkchoicetypes.Checkpoint{}
s.finalizedCheckpoint = &forkchoicetypes.Checkpoint{}
require.NoError(t, s.applyWeightChanges(context.Background(), []uint64{}, []int{-100, -50, 150}))
assert.Equal(t, uint64(100), s.nodes[0].weight)
assert.Equal(t, uint64(200), s.nodes[1].weight)
@@ -187,7 +203,9 @@ func TestStore_ApplyScoreChanges_UpdateWeightsMixedDelta(t *testing.T) {
func TestStore_UpdateBestChildAndDescendant_RemoveChild(t *testing.T) {
// Make parent's best child equal's to input child index and child is not viable.
s := &Store{nodes: []*Node{{bestChild: 1}, {}}, justifiedEpoch: 1, finalizedEpoch: 1}
jc := &forkchoicetypes.Checkpoint{Epoch: 1}
fc := &forkchoicetypes.Checkpoint{Epoch: 1}
s := &Store{nodes: []*Node{{bestChild: 1}, {}}, justifiedCheckpoint: jc, finalizedCheckpoint: fc}
require.NoError(t, s.updateBestChildAndDescendant(0, 1))
// Verify parent's best child and best descendant are `none`.
@@ -198,6 +216,8 @@ func TestStore_UpdateBestChildAndDescendant_RemoveChild(t *testing.T) {
func TestStore_UpdateBestChildAndDescendant_UpdateDescendant(t *testing.T) {
// Make parent's best child equal to child index and child is viable.
s := &Store{nodes: []*Node{{bestChild: 1}, {bestDescendant: NonExistentNode}}}
s.justifiedCheckpoint = &forkchoicetypes.Checkpoint{}
s.finalizedCheckpoint = &forkchoicetypes.Checkpoint{}
require.NoError(t, s.updateBestChildAndDescendant(0, 1))
// Verify parent's best child is the same and best descendant is not set to child index.
@@ -208,9 +228,11 @@ func TestStore_UpdateBestChildAndDescendant_UpdateDescendant(t *testing.T) {
func TestStore_UpdateBestChildAndDescendant_ChangeChildByViability(t *testing.T) {
// Make parent's best child not equal to child index, child leads to viable index and
// parent's best child doesn't lead to viable index.
jc := &forkchoicetypes.Checkpoint{Epoch: 1}
fc := &forkchoicetypes.Checkpoint{Epoch: 1}
s := &Store{
justifiedEpoch: 1,
finalizedEpoch: 1,
justifiedCheckpoint: jc,
finalizedCheckpoint: fc,
nodes: []*Node{{bestChild: 1, justifiedEpoch: 1, finalizedEpoch: 1},
{bestDescendant: NonExistentNode},
{bestDescendant: NonExistentNode, justifiedEpoch: 1, finalizedEpoch: 1}}}
@@ -224,9 +246,11 @@ func TestStore_UpdateBestChildAndDescendant_ChangeChildByViability(t *testing.T)
func TestStore_UpdateBestChildAndDescendant_ChangeChildByWeight(t *testing.T) {
// Make parent's best child not equal to child index, child leads to viable index and
// parents best child leads to viable index but child has more weight than parent's best child.
jc := &forkchoicetypes.Checkpoint{Epoch: 1}
fc := &forkchoicetypes.Checkpoint{Epoch: 1}
s := &Store{
justifiedEpoch: 1,
finalizedEpoch: 1,
justifiedCheckpoint: jc,
finalizedCheckpoint: fc,
nodes: []*Node{{bestChild: 1, justifiedEpoch: 1, finalizedEpoch: 1},
{bestDescendant: NonExistentNode, justifiedEpoch: 1, finalizedEpoch: 1},
{bestDescendant: NonExistentNode, justifiedEpoch: 1, finalizedEpoch: 1, weight: 1}}}
@@ -239,9 +263,11 @@ func TestStore_UpdateBestChildAndDescendant_ChangeChildByWeight(t *testing.T) {
func TestStore_UpdateBestChildAndDescendant_ChangeChildAtLeaf(t *testing.T) {
// Make parent's best child to none and input child leads to viable index.
jc := &forkchoicetypes.Checkpoint{Epoch: 1}
fc := &forkchoicetypes.Checkpoint{Epoch: 1}
s := &Store{
justifiedEpoch: 1,
finalizedEpoch: 1,
justifiedCheckpoint: jc,
finalizedCheckpoint: fc,
nodes: []*Node{{bestChild: NonExistentNode, justifiedEpoch: 1, finalizedEpoch: 1},
{bestDescendant: NonExistentNode, justifiedEpoch: 1, finalizedEpoch: 1},
{bestDescendant: NonExistentNode, justifiedEpoch: 1, finalizedEpoch: 1}}}
@@ -255,9 +281,11 @@ func TestStore_UpdateBestChildAndDescendant_ChangeChildAtLeaf(t *testing.T) {
func TestStore_UpdateBestChildAndDescendant_NoChangeByViability(t *testing.T) {
// Make parent's best child not equal to child index, child leads to not viable index and
// parents best child leads to viable index.
jc := &forkchoicetypes.Checkpoint{Epoch: 1}
fc := &forkchoicetypes.Checkpoint{Epoch: 1}
s := &Store{
justifiedEpoch: 1,
finalizedEpoch: 1,
justifiedCheckpoint: jc,
finalizedCheckpoint: fc,
nodes: []*Node{{bestChild: 1, justifiedEpoch: 1, finalizedEpoch: 1},
{bestDescendant: NonExistentNode, justifiedEpoch: 1, finalizedEpoch: 1},
{bestDescendant: NonExistentNode}}}
@@ -271,9 +299,11 @@ func TestStore_UpdateBestChildAndDescendant_NoChangeByViability(t *testing.T) {
func TestStore_UpdateBestChildAndDescendant_NoChangeByWeight(t *testing.T) {
// Make parent's best child not equal to child index, child leads to viable index and
// parents best child leads to viable index but parent's best child has more weight.
jc := &forkchoicetypes.Checkpoint{Epoch: 1}
fc := &forkchoicetypes.Checkpoint{Epoch: 1}
s := &Store{
justifiedEpoch: 1,
finalizedEpoch: 1,
justifiedCheckpoint: jc,
finalizedCheckpoint: fc,
nodes: []*Node{{bestChild: 1, justifiedEpoch: 1, finalizedEpoch: 1},
{bestDescendant: NonExistentNode, justifiedEpoch: 1, finalizedEpoch: 1, weight: 1},
{bestDescendant: NonExistentNode, justifiedEpoch: 1, finalizedEpoch: 1}}}
@@ -286,9 +316,11 @@ func TestStore_UpdateBestChildAndDescendant_NoChangeByWeight(t *testing.T) {
func TestStore_UpdateBestChildAndDescendant_NoChangeAtLeaf(t *testing.T) {
// Make parent's best child to none and input child does not lead to viable index.
jc := &forkchoicetypes.Checkpoint{Epoch: 1}
fc := &forkchoicetypes.Checkpoint{Epoch: 1}
s := &Store{
justifiedEpoch: 1,
finalizedEpoch: 1,
justifiedCheckpoint: jc,
finalizedCheckpoint: fc,
nodes: []*Node{{bestChild: NonExistentNode, justifiedEpoch: 1, finalizedEpoch: 1},
{bestDescendant: NonExistentNode, justifiedEpoch: 1, finalizedEpoch: 1},
{bestDescendant: NonExistentNode}}}
@@ -786,10 +818,12 @@ func TestStore_LeadsToViableHead(t *testing.T) {
{&Node{finalizedEpoch: 3, justifiedEpoch: 4}, 4, 3, true},
}
for _, tc := range tests {
jc := &forkchoicetypes.Checkpoint{Epoch: tc.justifiedEpoch}
fc := &forkchoicetypes.Checkpoint{Epoch: tc.finalizedEpoch}
s := &Store{
justifiedEpoch: tc.justifiedEpoch,
finalizedEpoch: tc.finalizedEpoch,
nodes: []*Node{tc.n},
justifiedCheckpoint: jc,
finalizedCheckpoint: fc,
nodes: []*Node{tc.n},
}
got, err := s.leadsToViableHead(tc.n)
require.NoError(t, err)
@@ -812,9 +846,11 @@ func TestStore_ViableForHead(t *testing.T) {
{&Node{finalizedEpoch: 3, justifiedEpoch: 4}, 4, 3, true},
}
for _, tc := range tests {
jc := &forkchoicetypes.Checkpoint{Epoch: tc.justifiedEpoch}
fc := &forkchoicetypes.Checkpoint{Epoch: tc.finalizedEpoch}
s := &Store{
justifiedEpoch: tc.justifiedEpoch,
finalizedEpoch: tc.finalizedEpoch,
justifiedCheckpoint: jc,
finalizedCheckpoint: fc,
}
assert.Equal(t, tc.want, s.viableForHead(tc.n))
}
@@ -984,7 +1020,7 @@ func TestStore_RemoveEquivocating(t *testing.T) {
state, blkRoot, err := prepareForkchoiceState(ctx, 1, [32]byte{'a'}, params.BeaconConfig().ZeroHash, [32]byte{'A'}, 1, 1)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
head, err := f.Head(ctx, params.BeaconConfig().ZeroHash, []uint64{})
head, err := f.Head(ctx, []uint64{})
require.NoError(t, err)
require.Equal(t, [32]byte{'a'}, head)
@@ -995,20 +1031,20 @@ func TestStore_RemoveEquivocating(t *testing.T) {
state, blkRoot, err = prepareForkchoiceState(ctx, 3, [32]byte{'c'}, [32]byte{'a'}, [32]byte{'C'}, 1, 1)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
head, err = f.Head(ctx, params.BeaconConfig().ZeroHash, []uint64{})
head, err = f.Head(ctx, []uint64{})
require.NoError(t, err)
require.Equal(t, [32]byte{'c'}, head)
// Insert two attestations for block b, it becomes head
f.ProcessAttestation(ctx, []uint64{1, 2}, [32]byte{'b'}, 1)
f.ProcessAttestation(ctx, []uint64{3}, [32]byte{'c'}, 1)
head, err = f.Head(ctx, params.BeaconConfig().ZeroHash, []uint64{100, 200, 200, 300})
head, err = f.Head(ctx, []uint64{100, 200, 200, 300})
require.NoError(t, err)
require.Equal(t, [32]byte{'b'}, head)
// Process b's slashing, c is now head
f.InsertSlashedIndex(ctx, 1)
head, err = f.Head(ctx, params.BeaconConfig().ZeroHash, []uint64{100, 200, 200, 300})
head, err = f.Head(ctx, []uint64{100, 200, 200, 300})
require.NoError(t, err)
require.Equal(t, [32]byte{'c'}, head)
require.Equal(t, uint64(200), f.store.nodes[2].weight)
@@ -1016,7 +1052,7 @@ func TestStore_RemoveEquivocating(t *testing.T) {
// Process the same slashing again, should be a noop
f.InsertSlashedIndex(ctx, 1)
head, err = f.Head(ctx, params.BeaconConfig().ZeroHash, []uint64{100, 200, 200, 300})
head, err = f.Head(ctx, []uint64{100, 200, 200, 300})
require.NoError(t, err)
require.Equal(t, [32]byte{'c'}, head)
require.Equal(t, uint64(200), f.store.nodes[2].weight)
@@ -1032,12 +1068,12 @@ func TestStore_UpdateCheckpoints(t *testing.T) {
f := setup(1, 1)
jr := [32]byte{'j'}
fr := [32]byte{'f'}
jc := &ethpb.Checkpoint{Root: jr[:], Epoch: 3}
fc := &ethpb.Checkpoint{Root: fr[:], Epoch: 2}
jc := &forkchoicetypes.Checkpoint{Root: jr, Epoch: 3}
fc := &forkchoicetypes.Checkpoint{Root: fr, Epoch: 2}
require.NoError(t, f.UpdateJustifiedCheckpoint(jc))
require.NoError(t, f.UpdateFinalizedCheckpoint(fc))
require.Equal(t, f.store.justifiedEpoch, jc.Epoch)
require.Equal(t, f.store.finalizedEpoch, fc.Epoch)
require.Equal(t, f.store.justifiedCheckpoint, jc)
require.Equal(t, f.store.finalizedCheckpoint, fc)
}
func TestStore_InsertOptimisticChain(t *testing.T) {
@@ -1051,8 +1087,10 @@ func TestStore_InsertOptimisticChain(t *testing.T) {
require.NoError(t, err)
wsb, err := wrapper.WrappedSignedBeaconBlock(blk)
require.NoError(t, err)
blks = append(blks, &forkchoicetypes.BlockAndCheckpoints{Block: wsb.Block(), JustifiedEpoch: 1,
FinalizedEpoch: 1})
blks = append(blks, &forkchoicetypes.BlockAndCheckpoints{Block: wsb.Block(),
JustifiedCheckpoint: &ethpb.Checkpoint{Epoch: 1, Root: params.BeaconConfig().ZeroHash[:]},
FinalizedCheckpoint: &ethpb.Checkpoint{Epoch: 1, Root: params.BeaconConfig().ZeroHash[:]},
})
for i := uint64(2); i < 11; i++ {
blk := util.NewBeaconBlock()
blk.Block.Slot = types.Slot(i)
@@ -1060,8 +1098,10 @@ func TestStore_InsertOptimisticChain(t *testing.T) {
blk.Block.ParentRoot = copiedRoot[:]
wsb, err = wrapper.WrappedSignedBeaconBlock(blk)
require.NoError(t, err)
blks = append(blks, &forkchoicetypes.BlockAndCheckpoints{Block: wsb.Block(), JustifiedEpoch: 1,
FinalizedEpoch: 1})
blks = append(blks, &forkchoicetypes.BlockAndCheckpoints{Block: wsb.Block(),
JustifiedCheckpoint: &ethpb.Checkpoint{Epoch: 1, Root: params.BeaconConfig().ZeroHash[:]},
FinalizedCheckpoint: &ethpb.Checkpoint{Epoch: 1, Root: params.BeaconConfig().ZeroHash[:]},
})
root, err = blk.Block.HashTreeRoot()
require.NoError(t, err)
}

View File

@@ -3,6 +3,7 @@ package protoarray
import (
"sync"
forkchoicetypes "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/types"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
)
@@ -18,8 +19,8 @@ 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.
justifiedEpoch types.Epoch // latest justified epoch in store.
finalizedEpoch types.Epoch // latest finalized epoch in store.
justifiedCheckpoint *forkchoicetypes.Checkpoint // latest 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.
@@ -30,6 +31,7 @@ type Store struct {
slashedIndices map[types.ValidatorIndex]bool // The list of equivocating validators
nodesLock sync.RWMutex
proposerBoostLock sync.RWMutex
checkpointsLock sync.RWMutex
}
// Node defines the individual block which includes its block parent, ancestor and how much weight accounted for it.

View File

@@ -55,11 +55,11 @@ func (f *ForkChoice) UpdateUnrealizedCheckpoints() {
for _, node := range f.store.nodes {
node.justifiedEpoch = node.unrealizedJustifiedEpoch
node.finalizedEpoch = node.unrealizedFinalizedEpoch
if node.justifiedEpoch > f.store.justifiedEpoch {
f.store.justifiedEpoch = node.justifiedEpoch
if node.justifiedEpoch > f.store.justifiedCheckpoint.Epoch {
f.store.justifiedCheckpoint.Epoch = node.justifiedEpoch
}
if node.finalizedEpoch > f.store.finalizedEpoch {
f.store.finalizedEpoch = node.finalizedEpoch
if node.finalizedEpoch > f.store.finalizedCheckpoint.Epoch {
f.store.finalizedCheckpoint.Epoch = node.finalizedEpoch
}
}
}

View File

@@ -5,9 +5,9 @@ import (
"context"
forkchoicetypes "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/types"
"github.com/prysmaticlabs/prysm/config/params"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/testing/require"
)
@@ -81,25 +81,25 @@ func TestStore_LongFork(t *testing.T) {
// Add an attestation to c, it is head
f.ProcessAttestation(ctx, []uint64{0}, [32]byte{'c'}, 1)
headRoot, err := f.Head(ctx, [32]byte{}, []uint64{100})
headRoot, err := f.Head(ctx, []uint64{100})
require.NoError(t, err)
require.Equal(t, [32]byte{'c'}, headRoot)
// D is head even though its weight is lower.
hr := [32]byte{'d'}
state, blkRoot, err = prepareForkchoiceState(ctx, 103, hr, [32]byte{'b'}, [32]byte{'D'}, 2, 1)
ha := [32]byte{'a'}
state, blkRoot, err = prepareForkchoiceState(ctx, 103, [32]byte{'d'}, [32]byte{'b'}, [32]byte{'D'}, 2, 1)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
require.NoError(t, f.UpdateJustifiedCheckpoint(&ethpb.Checkpoint{Epoch: 2, Root: hr[:]}))
headRoot, err = f.Head(ctx, [32]byte{}, []uint64{100})
require.NoError(t, f.UpdateJustifiedCheckpoint(&forkchoicetypes.Checkpoint{Epoch: 2, Root: ha}))
headRoot, err = f.Head(ctx, []uint64{100})
require.NoError(t, err)
require.Equal(t, hr, headRoot)
require.Equal(t, [32]byte{'d'}, headRoot)
require.Equal(t, uint64(0), f.store.nodes[4].weight)
require.Equal(t, uint64(100), f.store.nodes[3].weight)
// Update unrealized justification, c becomes head
f.UpdateUnrealizedCheckpoints()
headRoot, err = f.Head(ctx, [32]byte{}, []uint64{100})
headRoot, err = f.Head(ctx, []uint64{100})
require.NoError(t, err)
require.Equal(t, [32]byte{'c'}, headRoot)
}
@@ -158,30 +158,31 @@ func TestStore_NoDeadLock(t *testing.T) {
// Epoch 3
// Current Head is H
headRoot, err := f.Head(ctx, [32]byte{}, []uint64{100})
headRoot, err := f.Head(ctx, []uint64{100})
require.NoError(t, err)
require.Equal(t, [32]byte{'h'}, headRoot)
require.Equal(t, types.Epoch(0), f.JustifiedEpoch())
require.Equal(t, types.Epoch(0), f.JustifiedCheckpoint().Epoch)
// Insert Block I, it becomes Head
hr := [32]byte{'i'}
state, blkRoot, err = prepareForkchoiceState(ctx, 108, hr, [32]byte{'f'}, [32]byte{'I'}, 1, 0)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
require.NoError(t, f.UpdateJustifiedCheckpoint(&ethpb.Checkpoint{Epoch: 1, Root: hr[:]}))
headRoot, err = f.Head(ctx, [32]byte{}, []uint64{100})
ha := [32]byte{'a'}
require.NoError(t, f.UpdateJustifiedCheckpoint(&forkchoicetypes.Checkpoint{Epoch: 1, Root: ha}))
headRoot, err = f.Head(ctx, []uint64{100})
require.NoError(t, err)
require.Equal(t, hr, headRoot)
require.Equal(t, types.Epoch(1), f.JustifiedEpoch())
require.Equal(t, types.Epoch(0), f.FinalizedEpoch())
require.Equal(t, types.Epoch(1), f.JustifiedCheckpoint().Epoch)
require.Equal(t, types.Epoch(0), f.FinalizedCheckpoint().Epoch)
// Realized Justified checkpoints, H becomes head
f.UpdateUnrealizedCheckpoints()
headRoot, err = f.Head(ctx, [32]byte{}, []uint64{100})
headRoot, err = f.Head(ctx, []uint64{100})
require.NoError(t, err)
require.Equal(t, [32]byte{'h'}, headRoot)
require.Equal(t, types.Epoch(2), f.JustifiedEpoch())
require.Equal(t, types.Epoch(1), f.FinalizedEpoch())
require.Equal(t, types.Epoch(2), f.JustifiedCheckpoint().Epoch)
require.Equal(t, types.Epoch(1), f.FinalizedCheckpoint().Epoch)
}
// Epoch 1 | Epoch 2
@@ -226,10 +227,10 @@ func TestStore_ForkNextEpoch(t *testing.T) {
// Insert an attestation to H, H is head
f.ProcessAttestation(ctx, []uint64{0}, [32]byte{'h'}, 1)
headRoot, err := f.Head(ctx, [32]byte{}, []uint64{100})
headRoot, err := f.Head(ctx, []uint64{100})
require.NoError(t, err)
require.Equal(t, [32]byte{'h'}, headRoot)
require.Equal(t, types.Epoch(0), f.JustifiedEpoch())
require.Equal(t, types.Epoch(0), f.JustifiedCheckpoint().Epoch)
// D arrives late, D is head
state, blkRoot, err = prepareForkchoiceState(ctx, 103, [32]byte{'d'}, [32]byte{'c'}, [32]byte{'D'}, 0, 0)
@@ -237,10 +238,10 @@ func TestStore_ForkNextEpoch(t *testing.T) {
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
require.NoError(t, f.store.setUnrealizedJustifiedEpoch([32]byte{'d'}, 1))
f.UpdateUnrealizedCheckpoints()
headRoot, err = f.Head(ctx, [32]byte{}, []uint64{100})
headRoot, err = f.Head(ctx, []uint64{100})
require.NoError(t, err)
require.Equal(t, [32]byte{'d'}, headRoot)
require.Equal(t, types.Epoch(1), f.JustifiedEpoch())
require.Equal(t, types.Epoch(1), f.JustifiedCheckpoint().Epoch)
// nodes[8] = D since it's late!
require.Equal(t, uint64(0), f.store.nodes[8].weight)
require.Equal(t, uint64(100), f.store.nodes[7].weight)

View File

@@ -4,6 +4,7 @@ import (
"context"
"testing"
forkchoicetypes "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/types"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/testing/assert"
"github.com/prysmaticlabs/prysm/testing/require"
@@ -15,7 +16,7 @@ func TestVotes_CanFindHead(t *testing.T) {
ctx := context.Background()
// The head should always start at the finalized block.
r, err := f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err := f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, params.BeaconConfig().ZeroHash, r, "Incorrect head with genesis")
@@ -27,7 +28,7 @@ func TestVotes_CanFindHead(t *testing.T) {
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -39,7 +40,7 @@ func TestVotes_CanFindHead(t *testing.T) {
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -48,7 +49,7 @@ func TestVotes_CanFindHead(t *testing.T) {
// / \
// 2 1 <- +vote, new head
f.ProcessAttestation(context.Background(), []uint64{0}, indexToHash(1), 2)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(1), r, "Incorrect head for with justified epoch at 1")
@@ -57,7 +58,7 @@ func TestVotes_CanFindHead(t *testing.T) {
// / \
// vote, new head -> 2 1
f.ProcessAttestation(context.Background(), []uint64{1}, indexToHash(2), 2)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -71,7 +72,7 @@ func TestVotes_CanFindHead(t *testing.T) {
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -82,7 +83,7 @@ func TestVotes_CanFindHead(t *testing.T) {
// |
// 3 <- new vote
f.ProcessAttestation(context.Background(), []uint64{0}, indexToHash(3), 3)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -93,7 +94,7 @@ func TestVotes_CanFindHead(t *testing.T) {
// |
// 3 <- head
f.ProcessAttestation(context.Background(), []uint64{1}, indexToHash(1), 3)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(3), r, "Incorrect head for with justified epoch at 1")
@@ -109,7 +110,7 @@ func TestVotes_CanFindHead(t *testing.T) {
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(4), r, "Incorrect head for with justified epoch at 1")
@@ -127,7 +128,7 @@ func TestVotes_CanFindHead(t *testing.T) {
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(4), r, "Incorrect head for with justified epoch at 1")
@@ -188,7 +189,7 @@ func TestVotes_CanFindHead(t *testing.T) {
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(6), r, "Incorrect head for with justified epoch at 1")
@@ -209,9 +210,11 @@ func TestVotes_CanFindHead(t *testing.T) {
// 8
// |
// 9 <- head
f.store.justifiedEpoch = 2
f.store.finalizedEpoch = 2
r, err = f.Head(context.Background(), indexToHash(5), balances)
jc := &forkchoicetypes.Checkpoint{Epoch: 2, Root: indexToHash(5)}
fc := &forkchoicetypes.Checkpoint{Epoch: 2, Root: indexToHash(5)}
f.store.justifiedCheckpoint = jc
f.store.finalizedCheckpoint = fc
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(9), r, "Incorrect head for with justified epoch at 2")
@@ -237,7 +240,7 @@ func TestVotes_CanFindHead(t *testing.T) {
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
r, err = f.Head(context.Background(), indexToHash(5), balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(9), r, "Incorrect head for with justified epoch at 2")
@@ -246,28 +249,28 @@ func TestVotes_CanFindHead(t *testing.T) {
// The new validators voted for 10.
f.ProcessAttestation(context.Background(), []uint64{2, 3, 4}, indexToHash(10), 5)
// The new head should be 10.
r, err = f.Head(context.Background(), indexToHash(5), balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(10), r, "Incorrect head for with justified epoch at 2")
// Set the balances of the last 2 validators to 0.
balances = []uint64{1, 1, 1, 0, 0}
// The head should be back to 9.
r, err = f.Head(context.Background(), indexToHash(5), balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(9), r, "Incorrect head for with justified epoch at 1")
// Set the balances back to normal.
balances = []uint64{1, 1, 1, 1, 1}
// The head should be back to 10.
r, err = f.Head(context.Background(), indexToHash(5), balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(10), r, "Incorrect head for with justified epoch at 2")
// Remove the last 2 validators.
balances = []uint64{1, 1, 1}
// The head should be back to 9.
r, err = f.Head(context.Background(), indexToHash(5), balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(9), r, "Incorrect head for with justified epoch at 1")
@@ -276,7 +279,7 @@ func TestVotes_CanFindHead(t *testing.T) {
require.NoError(t, f.store.prune(context.Background(), indexToHash(5)))
assert.Equal(t, 11, len(f.store.nodes), "Incorrect nodes length after prune")
r, err = f.Head(context.Background(), indexToHash(5), balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(9), r, "Incorrect head for with justified epoch at 2")
@@ -300,7 +303,7 @@ func TestVotes_CanFindHead(t *testing.T) {
require.NoError(t, f.store.prune(context.Background(), indexToHash(5)))
assert.Equal(t, 5, len(f.store.nodes), "Incorrect nodes length after prune")
r, err = f.Head(context.Background(), indexToHash(5), balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(9), r, "Incorrect head for with justified epoch at 2")
@@ -318,7 +321,7 @@ func TestVotes_CanFindHead(t *testing.T) {
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
r, err = f.Head(context.Background(), indexToHash(5), balances)
r, err = f.Head(context.Background(), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(11), r, "Incorrect head for with justified epoch at 2")
}

View File

@@ -6,7 +6,9 @@ go_library(
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/types",
visibility = ["//visibility:public"],
deps = [
"//config/fieldparams:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//consensus-types/primitives:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
],
)

View File

@@ -1,8 +1,10 @@
package types
import (
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
// ProposerBoostRootArgs to call the BoostProposerRoot function.
@@ -13,9 +15,17 @@ type ProposerBoostRootArgs struct {
SecondsIntoSlot uint64
}
// Checkpoint is an array version of ethpb.Checkpoint. It is used internally in
// forkchoice, while the slice version is used in the interface to legagy code
// in other packages
type Checkpoint struct {
Epoch types.Epoch
Root [fieldparams.RootLength]byte
}
// BlockAndCheckpoints to call the InsertOptimisticChain function
type BlockAndCheckpoints struct {
Block interfaces.BeaconBlock
JustifiedEpoch types.Epoch
FinalizedEpoch types.Epoch
Block interfaces.BeaconBlock
JustifiedCheckpoint *ethpb.Checkpoint
FinalizedCheckpoint *ethpb.Checkpoint
}

View File

@@ -348,9 +348,9 @@ func (b *BeaconNode) Close() {
func (b *BeaconNode) startForkChoice() {
if features.Get().EnableForkChoiceDoublyLinkedTree {
b.forkChoiceStore = doublylinkedtree.New(0, 0)
b.forkChoiceStore = doublylinkedtree.New()
} else {
b.forkChoiceStore = protoarray.New(0, 0)
b.forkChoiceStore = protoarray.New()
}
}

View File

@@ -10,21 +10,21 @@ var (
prometheus.HistogramOpts{
Name: "new_payload_v1_latency_milliseconds",
Help: "Captures RPC latency for newPayloadV1 in milliseconds",
Buckets: []float64{25, 50, 100, 200, 500, 1000, 2000, 4000},
Buckets: []float64{1, 2, 5, 10, 20, 50, 100, 200, 500, 1000},
},
)
getPayloadLatency = promauto.NewHistogram(
prometheus.HistogramOpts{
Name: "get_payload_v1_latency_milliseconds",
Help: "Captures RPC latency for getPayloadV1 in milliseconds",
Buckets: []float64{25, 50, 100, 200, 500, 1000, 2000, 4000},
Buckets: []float64{1, 2, 5, 10, 20, 50, 100, 200, 500, 1000},
},
)
forkchoiceUpdatedLatency = promauto.NewHistogram(
prometheus.HistogramOpts{
Name: "forkchoice_updated_v1_latency_milliseconds",
Help: "Captures RPC latency for forkchoiceUpdatedV1 in milliseconds",
Buckets: []float64{25, 50, 100, 200, 500, 1000, 2000, 4000},
Buckets: []float64{1, 2, 5, 10, 20, 50, 100, 200, 500, 1000},
},
)
)

View File

@@ -7,6 +7,7 @@ import (
ethpbv1 "github.com/prysmaticlabs/prysm/proto/eth/v1"
ethpbv2 "github.com/prysmaticlabs/prysm/proto/eth/v2"
"github.com/prysmaticlabs/prysm/proto/migration"
"github.com/prysmaticlabs/prysm/runtime/version"
"go.opencensus.io/trace"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
@@ -23,7 +24,7 @@ func (ds *Server) GetBeaconState(ctx context.Context, req *ethpbv1.StateRequest)
return nil, helpers.PrepareStateFetchGRPCError(err)
}
if beaconSt.Version().IsHigherOrEqualToAltair() {
if beaconSt.Version() != version.Phase0 {
return nil, status.Error(codes.Internal, "State has incorrect type")
}
protoSt, err := migration.BeaconStateToProto(beaconSt)
@@ -68,8 +69,8 @@ func (ds *Server) GetBeaconStateV2(ctx context.Context, req *ethpbv2.StateReques
return nil, status.Errorf(codes.Internal, "Could not check if slot's block is optimistic: %v", err)
}
switch {
case beaconSt.Version().IsAltairCompatible():
switch beaconSt.Version() {
case version.Phase0:
protoSt, err := migration.BeaconStateToProto(beaconSt)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not convert state to proto: %v", err)
@@ -81,7 +82,7 @@ func (ds *Server) GetBeaconStateV2(ctx context.Context, req *ethpbv2.StateReques
},
ExecutionOptimistic: isOptimistic,
}, nil
case beaconSt.Version().IsAltairCompatible():
case version.Altair:
protoState, err := migration.BeaconStateAltairToProto(beaconSt)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not convert state to proto: %v", err)
@@ -93,7 +94,7 @@ func (ds *Server) GetBeaconStateV2(ctx context.Context, req *ethpbv2.StateReques
},
ExecutionOptimistic: isOptimistic,
}, nil
case beaconSt.Version().IsBellatrixCompatible():
case version.Bellatrix:
protoState, err := migration.BeaconStateBellatrixToProto(beaconSt)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not convert state to proto: %v", err)
@@ -125,12 +126,12 @@ func (ds *Server) GetBeaconStateSSZV2(ctx context.Context, req *ethpbv2.StateReq
return nil, status.Errorf(codes.Internal, "Could not marshal state into SSZ: %v", err)
}
var ver ethpbv2.Version
switch {
case st.Version().IsPhase0Compatible():
switch st.Version() {
case version.Phase0:
ver = ethpbv2.Version_PHASE0
case st.Version().IsAltairCompatible():
case version.Altair:
ver = ethpbv2.Version_ALTAIR
case st.Version().IsBellatrixCompatible():
case version.Bellatrix:
ver = ethpbv2.Version_BELLATRIX
default:
return nil, status.Error(codes.Internal, "Unsupported state version")

View File

@@ -12,8 +12,8 @@ func (ds *Server) GetForkChoice(_ context.Context, _ *empty.Empty) (*pbrpc.ForkC
store := ds.ForkFetcher.ForkChoicer()
return &pbrpc.ForkChoiceResponse{
JustifiedEpoch: store.JustifiedEpoch(),
FinalizedEpoch: store.FinalizedEpoch(),
JustifiedEpoch: store.JustifiedCheckpoint().Epoch,
FinalizedEpoch: store.FinalizedCheckpoint().Epoch,
ForkchoiceNodes: store.ForkChoiceNodes(),
}, nil
}

View File

@@ -12,10 +12,10 @@ import (
)
func TestServer_GetForkChoice_ProtoArray(t *testing.T) {
store := protoarray.New(0, 0)
store := protoarray.New()
bs := &Server{ForkFetcher: &mock.ChainService{ForkChoiceStore: store}}
res, err := bs.GetForkChoice(context.Background(), &empty.Empty{})
require.NoError(t, err)
assert.Equal(t, store.JustifiedEpoch(), res.JustifiedEpoch, "Did not get wanted justified epoch")
assert.Equal(t, store.FinalizedEpoch(), res.FinalizedEpoch, "Did not get wanted finalized epoch")
assert.Equal(t, store.JustifiedCheckpoint().Epoch, res.JustifiedEpoch, "Did not get wanted justified epoch")
assert.Equal(t, store.FinalizedCheckpoint().Epoch, res.FinalizedEpoch, "Did not get wanted finalized epoch")
}

View File

@@ -13,7 +13,6 @@ go_library(
"//config/fieldparams:go_default_library",
"//consensus-types/primitives:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//runtime/version:go_default_library",
"@com_github_prometheus_client_golang//prometheus:go_default_library",
"@com_github_prometheus_client_golang//prometheus/promauto:go_default_library",
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",

View File

@@ -10,7 +10,6 @@ import (
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/runtime/version"
)
// BeaconState has read and write access to beacon state methods.
@@ -60,7 +59,7 @@ type ReadOnlyBeaconState interface {
FieldReferencesCount() map[string]uint64
MarshalSSZ() ([]byte, error)
IsNil() bool
Version() version.ForkVersion
Version() int
LatestExecutionPayloadHeader() (*ethpb.ExecutionPayloadHeader, error)
}

View File

@@ -13,13 +13,12 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
eth2types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/runtime/version"
)
// BeaconState defines a struct containing utilities for the Ethereum Beacon Chain state, defining
// getters and setters for its respective values and helpful functions such as HashTreeRoot().
type BeaconState struct {
version version.ForkVersion
version int
genesisTime uint64 `ssz-gen:"true"`
genesisValidatorsRoot customtypes.Byte32 `ssz-gen:"true" ssz-size:"32"`
slot eth2types.Slot `ssz-gen:"true"`

View File

@@ -13,13 +13,12 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
eth2types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/runtime/version"
)
// BeaconState defines a struct containing utilities for the Ethereum Beacon Chain state, defining
// getters and setters for its respective values and helpful functions such as HashTreeRoot().
type BeaconState struct {
version version.ForkVersion
version int
genesisTime uint64 `ssz-gen:"true"`
genesisValidatorsRoot customtypes.Byte32 `ssz-gen:"true" ssz-size:"32"`
slot eth2types.Slot `ssz-gen:"true"`

View File

@@ -2,11 +2,12 @@ package state_native
import (
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/runtime/version"
)
// PreviousEpochAttestations corresponding to blocks on the beacon chain.
func (b *BeaconState) PreviousEpochAttestations() ([]*ethpb.PendingAttestation, error) {
if !b.version.IsPhase0Compatible() {
if b.version != version.Phase0 {
return nil, errNotSupported("PreviousEpochAttestations", b.version)
}
@@ -28,7 +29,7 @@ func (b *BeaconState) previousEpochAttestationsVal() []*ethpb.PendingAttestation
// CurrentEpochAttestations corresponding to blocks on the beacon chain.
func (b *BeaconState) CurrentEpochAttestations() ([]*ethpb.PendingAttestation, error) {
if !b.version.IsPhase0Compatible() {
if b.version != version.Phase0 {
return nil, errNotSupported("CurrentEpochAttestations", b.version)
}

View File

@@ -3,7 +3,6 @@ package state_native
import (
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/runtime/version"
)
// GenesisTime of the beacon state as a uint64.
@@ -25,7 +24,7 @@ func (b *BeaconState) GenesisValidatorsRoot() []byte {
// Version of the beacon state. This method
// is strictly meant to be used without a lock
// internally.
func (b *BeaconState) Version() version.ForkVersion {
func (b *BeaconState) Version() int {
return b.version
}

View File

@@ -3,11 +3,12 @@ package state_native
import (
"github.com/prysmaticlabs/prysm/beacon-chain/core/time"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
"github.com/prysmaticlabs/prysm/runtime/version"
)
// CurrentEpochParticipation corresponding to participation bits on the beacon chain.
func (b *BeaconState) CurrentEpochParticipation() ([]byte, error) {
if !b.version.IsParticipationBitsCompatible() {
if b.version == version.Phase0 {
return nil, errNotSupported("CurrentEpochParticipation", b.version)
}
@@ -23,7 +24,7 @@ func (b *BeaconState) CurrentEpochParticipation() ([]byte, error) {
// PreviousEpochParticipation corresponding to participation bits on the beacon chain.
func (b *BeaconState) PreviousEpochParticipation() ([]byte, error) {
if !b.version.IsParticipationBitsCompatible() {
if b.version == version.Phase0 {
return nil, errNotSupported("PreviousEpochParticipation", b.version)
}
@@ -41,7 +42,7 @@ func (b *BeaconState) PreviousEpochParticipation() ([]byte, error) {
// current epoch and target attested in previous epoch. This function is used to
// compute the "unrealized justification" that a synced Beacon Block will have.
func (b *BeaconState) UnrealizedCheckpointBalances() (uint64, uint64, uint64, error) {
if !b.version.IsParticipationBitsCompatible() {
if b.version == version.Phase0 {
return 0, 0, 0, errNotSupported("UnrealizedCheckpointBalances", b.version)
}

View File

@@ -2,11 +2,12 @@ package state_native
import (
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/runtime/version"
)
// LatestExecutionPayloadHeader of the beacon state.
func (b *BeaconState) LatestExecutionPayloadHeader() (*ethpb.ExecutionPayloadHeader, error) {
if !b.version.IsExecutionPayloadCompatible() {
if b.version == version.Phase0 || b.version == version.Altair {
return nil, errNotSupported("LatestExecutionPayloadHeader", b.version)
}

View File

@@ -17,8 +17,8 @@ func (b *BeaconState) ToProtoUnsafe() interface{} {
gvrCopy := b.genesisValidatorsRoot
switch {
case b.version.IsPhase0Compatible():
switch b.version {
case version.Phase0:
return &ethpb.BeaconState{
GenesisTime: b.genesisTime,
GenesisValidatorsRoot: gvrCopy[:],
@@ -42,7 +42,7 @@ func (b *BeaconState) ToProtoUnsafe() interface{} {
CurrentJustifiedCheckpoint: b.currentJustifiedCheckpoint,
FinalizedCheckpoint: b.finalizedCheckpoint,
}
case b.version.IsAltairCompatible():
case version.Altair:
return &ethpb.BeaconStateAltair{
GenesisTime: b.genesisTime,
GenesisValidatorsRoot: gvrCopy[:],
@@ -69,7 +69,7 @@ func (b *BeaconState) ToProtoUnsafe() interface{} {
CurrentSyncCommittee: b.currentSyncCommittee,
NextSyncCommittee: b.nextSyncCommittee,
}
case b.version.IsBellatrixCompatible():
case version.Bellatrix:
return &ethpb.BeaconStateBellatrix{
GenesisTime: b.genesisTime,
GenesisValidatorsRoot: gvrCopy[:],

View File

@@ -31,6 +31,6 @@ func init() {
// to its corresponding data type.
var fieldMap map[nativetypes.FieldIndex]types.DataType
func errNotSupported(funcName string, ver version.ForkVersion) error {
return fmt.Errorf("%s is not supported for %s", funcName, ver.String())
func errNotSupported(funcName string, ver int) error {
return fmt.Errorf("%s is not supported for %s", funcName, version.String(ver))
}

View File

@@ -5,8 +5,5 @@ go_library(
srcs = ["types.go"],
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types",
visibility = ["//visibility:public"],
deps = [
"//runtime/version:go_default_library",
"@com_github_pkg_errors//:go_default_library",
],
deps = ["@com_github_pkg_errors//:go_default_library"],
)

View File

@@ -2,7 +2,6 @@ package types
import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/runtime/version"
)
// FieldIndex represents the relevant field position in the
@@ -10,7 +9,7 @@ import (
type FieldIndex int
// String returns the name of the field index.
func (f FieldIndex) String(_ version.ForkVersion) string {
func (f FieldIndex) String(_ int) string {
switch f {
case GenesisTime:
return "genesisTime"

View File

@@ -211,7 +211,7 @@ func ReplayProcessSlots(ctx context.Context, state state.BeaconState, slot types
return nil, errors.Wrap(err, "could not process epoch")
}
default:
return nil, fmt.Errorf("unsupported beacon state version: %s", state.Version().String())
return nil, fmt.Errorf("unsupported beacon state version: %s", version.String(state.Version()))
}
}
if err := state.SetSlot(state.Slot() + 1); err != nil {

View File

@@ -27,14 +27,14 @@ const (
// BeaconStateField represents a field of the beacon state.
type BeaconStateField interface {
String(stateVersion version.ForkVersion) string
String(stateVersion int) string
RealPosition() int
ElemsInChunk() (uint64, error)
Native() bool
}
// String returns the name of the field index.
func (f FieldIndex) String(stateVersion version.ForkVersion) string {
func (f FieldIndex) String(stateVersion int) string {
switch f {
case GenesisTime:
return "genesisTime"
@@ -67,12 +67,12 @@ func (f FieldIndex) String(stateVersion version.ForkVersion) string {
case Slashings:
return "slashings"
case PreviousEpochAttestations:
if stateVersion.IsParticipationBitsCompatible() {
if version.Altair == stateVersion || version.Bellatrix == stateVersion {
return "previousEpochParticipationBits"
}
return "previousEpochAttestations"
case CurrentEpochAttestations:
if stateVersion.IsParticipationBitsCompatible() {
if version.Altair == stateVersion || version.Bellatrix == stateVersion {
return "currentEpochParticipationBits"
}
return "currentEpochAttestations"

View File

@@ -63,7 +63,7 @@ func (b *BeaconState) genesisValidatorsRoot() []byte {
// Version of the beacon state. This method
// is strictly meant to be used without a lock
// internally.
func (_ *BeaconState) Version() version.ForkVersion {
func (_ *BeaconState) Version() int {
return version.Phase0
}

View File

@@ -64,7 +64,7 @@ func (b *BeaconState) genesisValidatorsRoot() []byte {
// Version of the beacon state. This method
// is strictly meant to be used without a lock
// internally.
func (_ *BeaconState) Version() version.ForkVersion {
func (_ *BeaconState) Version() int {
return version.Altair
}

View File

@@ -63,7 +63,7 @@ func (b *BeaconState) genesisValidatorsRoot() []byte {
// Version of the beacon state. This method
// is strictly meant to be used without a lock
// internally.
func (_ *BeaconState) Version() version.ForkVersion {
func (_ *BeaconState) Version() int {
return version.Bellatrix
}

View File

@@ -122,12 +122,6 @@ func configureTestnet(ctx *cli.Context) error {
if err := params.SetActive(params.RopstenConfig().Copy()); err != nil {
return err
}
if err := ctx.Set(enableVecHTR.Names()[0], "true"); err != nil {
log.WithError(err).Debug("error enabling vectorized HTR flag")
}
if err := ctx.Set(enableForkChoiceDoublyLinkedTree.Names()[0], "true"); err != nil {
log.WithError(err).Debug("error enabling doubly linked tree forkchoice flag")
}
params.UseRopstenNetworkConfig()
} else {
log.Warn("Running on Ethereum Consensus Mainnet")

View File

@@ -3,11 +3,11 @@ package bellatrix
import (
"bytes"
field_params "github.com/prysmaticlabs/prysm/config/fieldparams"
"github.com/prysmaticlabs/prysm/config/fieldparams"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/encoding/ssz"
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
eth "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/proto/engine/v1"
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
// PayloadToHeader converts `payload` into execution payload header format.

View File

@@ -13,7 +13,6 @@ go_library(
"//proto/engine/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/validator-client:go_default_library",
"//runtime/version:go_default_library",
"@com_github_ferranbt_fastssz//:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@org_golang_google_protobuf//proto:go_default_library",

View File

@@ -6,7 +6,6 @@ import (
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
validatorpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/validator-client"
"github.com/prysmaticlabs/prysm/runtime/version"
"google.golang.org/protobuf/proto"
)
@@ -25,7 +24,7 @@ type SignedBeaconBlock interface {
PbBlindedBellatrixBlock() (*ethpb.SignedBlindedBeaconBlockBellatrix, error)
ssz.Marshaler
ssz.Unmarshaler
Version() version.ForkVersion
Version() int
Header() (*ethpb.SignedBeaconBlockHeader, error)
}
@@ -44,7 +43,7 @@ type BeaconBlock interface {
ssz.Marshaler
ssz.Unmarshaler
ssz.HashRoot
Version() version.ForkVersion
Version() int
AsSignRequestObject() validatorpb.SignRequestObject
}

View File

@@ -114,7 +114,7 @@ func (altairSignedBeaconBlock) PbBlindedBellatrixBlock() (*eth.SignedBlindedBeac
}
// Version of the underlying protobuf object.
func (altairSignedBeaconBlock) Version() version.ForkVersion {
func (altairSignedBeaconBlock) Version() int {
return version.Altair
}
@@ -226,7 +226,7 @@ func (w altairBeaconBlock) Proto() proto.Message {
}
// Version of the underlying protobuf object.
func (altairBeaconBlock) Version() version.ForkVersion {
func (altairBeaconBlock) Version() int {
return version.Altair
}

View File

@@ -109,7 +109,7 @@ func (bellatrixSignedBeaconBlock) PbAltairBlock() (*eth.SignedBeaconBlockAltair,
}
// Version of the underlying protobuf object.
func (bellatrixSignedBeaconBlock) Version() version.ForkVersion {
func (bellatrixSignedBeaconBlock) Version() int {
return version.Bellatrix
}
@@ -221,7 +221,7 @@ func (w bellatrixBeaconBlock) Proto() proto.Message {
}
// Version of the underlying protobuf object.
func (bellatrixBeaconBlock) Version() version.ForkVersion {
func (bellatrixBeaconBlock) Version() int {
return version.Bellatrix
}

View File

@@ -110,7 +110,7 @@ func (Phase0SignedBeaconBlock) PbBlindedBellatrixBlock() (*eth.SignedBlindedBeac
}
// Version of the underlying protobuf object.
func (Phase0SignedBeaconBlock) Version() version.ForkVersion {
func (Phase0SignedBeaconBlock) Version() int {
return version.Phase0
}
@@ -218,7 +218,7 @@ func (w Phase0BeaconBlock) Proto() proto.Message {
}
// Version of the underlying protobuf object.
func (Phase0BeaconBlock) Version() version.ForkVersion {
func (Phase0BeaconBlock) Version() int {
return version.Phase0
}

View File

@@ -109,7 +109,7 @@ func (signedBlindedBeaconBlockBellatrix) PbAltairBlock() (*eth.SignedBeaconBlock
}
// Version of the underlying protobuf object.
func (signedBlindedBeaconBlockBellatrix) Version() version.ForkVersion {
func (signedBlindedBeaconBlockBellatrix) Version() int {
return version.BellatrixBlind
}
@@ -222,7 +222,7 @@ func (w blindedBeaconBlockBellatrix) Proto() proto.Message {
}
// Version of the underlying protobuf object.
func (blindedBeaconBlockBellatrix) Version() version.ForkVersion {
func (blindedBeaconBlockBellatrix) Version() int {
return version.BellatrixBlind
}

View File

@@ -79,7 +79,7 @@ func (_ MetadataV0) MetadataObjV1() *pb.MetaDataV1 {
}
// Version returns the fork version of the underlying object.
func (_ MetadataV0) Version() version.ForkVersion {
func (_ MetadataV0) Version() int {
return version.Phase0
}
@@ -154,6 +154,6 @@ func (m MetadataV1) MetadataObjV1() *pb.MetaDataV1 {
}
// Version returns the fork version of the underlying object.
func (_ MetadataV1) Version() version.ForkVersion {
func (_ MetadataV1) Version() int {
return version.Altair
}

View File

@@ -40,7 +40,7 @@ func (m BlockMutator) Apply(b interfaces.SignedBeaconBlock) error {
m.Bellatrix(bb)
return nil
}
msg := fmt.Sprintf("version %d = %s", b.Version(), b.Version().String())
msg := fmt.Sprintf("version %d = %s", b.Version(), version.String(b.Version()))
return errors.Wrap(ErrUnsupportedSignedBeaconBlock, msg)
}

View File

@@ -28,7 +28,7 @@ import (
type VersionedUnmarshaler struct {
Config *params.BeaconChainConfig
// Fork aligns with the fork names in config/params/values.go
Fork version.ForkVersion
Fork int
// Version corresponds to the Version type defined in the beacon-chain spec, aka a "fork version number":
// https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#custom-types
Version [fieldparams.VersionLength]byte
@@ -60,7 +60,7 @@ func FromForkVersion(cv [fieldparams.VersionLength]byte) (*VersionedUnmarshaler,
if err != nil {
return nil, err
}
var fork version.ForkVersion
var fork int
switch cv {
case bytesutil.ToBytes4(cfg.GenesisForkVersion):
fork = version.Phase0
@@ -81,10 +81,9 @@ func FromForkVersion(cv [fieldparams.VersionLength]byte) (*VersionedUnmarshaler,
// UnmarshalBeaconState uses internal knowledge in the VersionedUnmarshaler to pick the right concrete BeaconState type,
// then Unmarshal()s the type and returns an instance of state.BeaconState if successful.
func (cf *VersionedUnmarshaler) UnmarshalBeaconState(marshaled []byte) (s state.BeaconState, err error) {
forkName := cf.Fork.String()
fork := cf.Fork
switch {
case fork.IsPhase0Compatible():
forkName := version.String(cf.Fork)
switch fork := cf.Fork; fork {
case version.Phase0:
st := &ethpb.BeaconState{}
err = st.UnmarshalSSZ(marshaled)
if err != nil {
@@ -94,7 +93,7 @@ func (cf *VersionedUnmarshaler) UnmarshalBeaconState(marshaled []byte) (s state.
if err != nil {
return nil, errors.Wrapf(err, "failed to init state trie from state, detected fork=%s", forkName)
}
case fork.IsAltairCompatible():
case version.Altair:
st := &ethpb.BeaconStateAltair{}
err = st.UnmarshalSSZ(marshaled)
if err != nil {
@@ -104,7 +103,7 @@ func (cf *VersionedUnmarshaler) UnmarshalBeaconState(marshaled []byte) (s state.
if err != nil {
return nil, errors.Wrapf(err, "failed to init state trie from state, detected fork=%s", forkName)
}
case fork.IsBellatrixCompatible():
case version.Bellatrix:
st := &ethpb.BeaconStateBellatrix{}
err = st.UnmarshalSSZ(marshaled)
if err != nil {
@@ -159,7 +158,7 @@ func (cf *VersionedUnmarshaler) UnmarshalBeaconBlock(marshaled []byte) (interfac
case version.Bellatrix:
blk = &ethpb.SignedBeaconBlockBellatrix{}
default:
forkName := cf.Fork.String()
forkName := version.String(cf.Fork)
return nil, fmt.Errorf("unable to initialize BeaconBlock for fork version=%s at slot=%d", forkName, slot)
}
err = blk.UnmarshalSSZ(marshaled)
@@ -190,7 +189,7 @@ func (cf *VersionedUnmarshaler) UnmarshalBlindedBeaconBlock(marshaled []byte) (i
case version.Bellatrix:
blk = &ethpb.SignedBlindedBeaconBlockBellatrix{}
default:
forkName := cf.Fork.String()
forkName := version.String(cf.Fork)
return nil, fmt.Errorf("unable to initialize BeaconBlock for fork version=%s at slot=%d", forkName, slot)
}
err = blk.UnmarshalSSZ(marshaled)

View File

@@ -7,7 +7,6 @@ go_library(
visibility = ["//visibility:public"],
deps = [
"//proto/prysm/v1alpha1:go_default_library",
"//runtime/version:go_default_library",
"@com_github_ferranbt_fastssz//:go_default_library",
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
],

View File

@@ -4,7 +4,6 @@ import (
ssz "github.com/ferranbt/fastssz"
"github.com/prysmaticlabs/go-bitfield"
pb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/runtime/version"
)
// Metadata returns the interface of a p2p metadata type.
@@ -18,5 +17,5 @@ type Metadata interface {
ssz.Unmarshaler
MetadataObjV0() *pb.MetaDataV0
MetadataObjV1() *pb.MetaDataV1
Version() version.ForkVersion
Version() int
}

View File

@@ -1,16 +1,14 @@
package version
type ForkVersion int
const (
Phase0 ForkVersion = iota
Phase0 = iota
Altair
Bellatrix
BellatrixBlind
)
func (v ForkVersion) String() string {
switch v {
func String(version int) string {
switch version {
case Phase0:
return "phase0"
case Altair:
@@ -23,39 +21,3 @@ func (v ForkVersion) String() string {
return "unknown version"
}
}
func (v ForkVersion) IsPhase0Compatible() bool {
return v == Phase0
}
func (v ForkVersion) IsAltairCompatible() bool {
return v == Altair
}
func (v ForkVersion) IsHigherOrEqualToAltair() bool {
return v >= Altair
}
func (v ForkVersion) IsPreBellatrix() bool {
return v < Bellatrix
}
func (v ForkVersion) IsBellatrixCompatible() bool {
return v == Bellatrix || v == BellatrixBlind
}
func (v ForkVersion) IsSyncCommitteeCompatible() bool {
return v == Altair || v == Bellatrix || v == BellatrixBlind
}
func (v ForkVersion) IsParticipationBitsCompatible() bool {
return v == Altair || v == Bellatrix || v == BellatrixBlind
}
func (v ForkVersion) IsExecutionPayloadCompatible() bool {
return v.IsBellatrixCompatible()
}
func (v ForkVersion) IsBlindedBlockCompatible() bool {
return v == BellatrixBlind
}

View File

@@ -219,9 +219,13 @@ func (r *testRunner) testTxGeneration(ctx context.Context, g *errgroup.Group, ke
})
}
func (r *testRunner) waitForMatchingHead(ctx context.Context, timeout time.Duration, check, ref *grpc.ClientConn) error {
start := time.Now()
dctx, cancel := context.WithDeadline(ctx, start.Add(timeout))
func (r *testRunner) waitForMatchingHead(ctx context.Context, check, ref *grpc.ClientConn) error {
// sleep hack copied from testBeaconChainSync
// Sleep a second for every 4 blocks that need to be synced for the newly started node.
secondsPerEpoch := uint64(params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().SecondsPerSlot))
extraSecondsToSync := (r.config.EpochsToRun) * secondsPerEpoch
deadline := time.Now().Add(time.Second * time.Duration(extraSecondsToSync))
dctx, cancel := context.WithDeadline(ctx, deadline)
defer cancel()
checkClient := service.NewBeaconChainClient(check)
refClient := service.NewBeaconChainClient(ref)
@@ -229,8 +233,7 @@ func (r *testRunner) waitForMatchingHead(ctx context.Context, timeout time.Durat
select {
case <-dctx.Done():
// deadline ensures that the test eventually exits when beacon node fails to sync in a resonable timeframe
elapsed := time.Since(start)
return fmt.Errorf("deadline exceeded after %s waiting for known good block to appear in checkpoint-synced node", elapsed)
return fmt.Errorf("deadline exceeded waiting for known good block to appear in checkpoint-synced node")
default:
cResp, err := checkClient.GetBlockRoot(ctx, &v1.BlockRequest{BlockId: []byte("head")})
if err != nil {
@@ -253,7 +256,6 @@ func (r *testRunner) waitForMatchingHead(ctx context.Context, timeout time.Durat
}
func (r *testRunner) testCheckpointSync(ctx context.Context, g *errgroup.Group, i int, conns []*grpc.ClientConn, bnAPI, enr, minerEnr string) error {
matchTimeout := 3 * time.Minute
ethNode := eth1.NewNode(i, minerEnr)
g.Go(func() error {
return ethNode.Start(ctx)
@@ -302,7 +304,7 @@ func (r *testRunner) testCheckpointSync(ctx context.Context, g *errgroup.Group,
// this is so that the syncEvaluators checks can run on the checkpoint sync'd node
conns = append(conns, c)
err = r.waitForMatchingHead(ctx, matchTimeout, c, conns[0])
err = r.waitForMatchingHead(ctx, c, conns[0])
if err != nil {
return err
}

View File

@@ -52,7 +52,7 @@ func startChainService(t testing.TB, st state.BeaconState, block interfaces.Sign
blockchain.WithFinalizedStateAtStartUp(st),
blockchain.WithDatabase(db),
blockchain.WithAttestationService(attPool),
blockchain.WithForkChoiceStore(protoarray.New(0, 0)),
blockchain.WithForkChoiceStore(protoarray.New()),
blockchain.WithStateGen(stategen.New(db)),
blockchain.WithStateNotifier(&mock.MockStateNotifier{}),
blockchain.WithAttestationPool(attestations.NewPool()),

View File

@@ -163,7 +163,7 @@ func (v *validator) ProposeBlock(ctx context.Context, slot types.Slot, pubKey [f
"numAttestations": len(blk.Block().Body().Attestations()),
"numDeposits": len(blk.Block().Body().Deposits()),
"graffiti": string(blk.Block().Body().Graffiti()),
"fork": blk.Block().Version().String(),
"fork": version.String(blk.Block().Version()),
}).Info("Submitted new block")
if v.emitAccountMetrics {