mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 13:58:09 -05:00
Compare commits
5 Commits
methodical
...
further-ve
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a89a51af06 | ||
|
|
7f443e8387 | ||
|
|
18fc17c903 | ||
|
|
d7b01b9d81 | ||
|
|
7ebd9035dd |
@@ -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
|
||||
|
||||
@@ -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 := ðpb.Checkpoint{Epoch: 1, Root: tt.finalizedRoot[:]}
|
||||
fc := ðpb.Checkpoint{Epoch: 0, Root: tt.finalizedRoot[:]}
|
||||
service.store.SetFinalizedCheckptAndPayloadHash(fc, [32]byte{'a'})
|
||||
service.store.SetJustifiedCheckptAndPayloadHash(fc, [32]byte{'b'})
|
||||
arg := ¬ifyForkchoiceUpdateArg{
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -174,10 +174,8 @@ func TestUpdateHead_MissingJustifiedRoot(t *testing.T) {
|
||||
service.store.SetJustifiedCheckptAndPayloadHash(ðpb.Checkpoint{Root: r[:]}, [32]byte{'a'})
|
||||
service.store.SetFinalizedCheckptAndPayloadHash(ðpb.Checkpoint{}, [32]byte{'b'})
|
||||
service.store.SetBestJustifiedCheckpt(ðpb.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 := ðpb.Checkpoint{
|
||||
Root: bellatrixBlkRoot[:],
|
||||
Epoch: 1,
|
||||
Epoch: 0,
|
||||
}
|
||||
service.store.SetFinalizedCheckptAndPayloadHash(fcp, [32]byte{'a'})
|
||||
service.store.SetJustifiedCheckptAndPayloadHash(fcp, [32]byte{'b'})
|
||||
|
||||
@@ -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)),
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)),
|
||||
|
||||
@@ -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)),
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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(ðpb.Checkpoint{Root: gRoot[:]}, [32]byte{'a'})
|
||||
service.store.SetJustifiedCheckptAndPayloadHash(ðpb.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(ðpb.Checkpoint{Root: gRoot[:]}, [32]byte{'a'})
|
||||
service.store.SetJustifiedCheckptAndPayloadHash(ðpb.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(ðpb.Checkpoint{Root: gRoot[:]}, [32]byte{'a'})
|
||||
service.store.SetJustifiedCheckptAndPayloadHash(ðpb.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(ðpb.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(ðpb.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(ðpb.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)),
|
||||
|
||||
@@ -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)),
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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(ðpb.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(ðpb.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(ðpb.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(ðpb.Checkpoint{Epoch: 0, Root: params.BeaconConfig().ZeroHash[:]}, [32]byte{})
|
||||
|
||||
@@ -12,7 +12,6 @@ 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"
|
||||
)
|
||||
@@ -75,16 +74,10 @@ func ProcessProposerSlashing(
|
||||
return nil, errors.Wrap(err, "could not verify proposer slashing")
|
||||
}
|
||||
cfg := params.BeaconConfig()
|
||||
var slashingQuotient uint64
|
||||
switch {
|
||||
case beaconState.Version() == version.Phase0:
|
||||
slashingQuotient = cfg.MinSlashingPenaltyQuotient
|
||||
case beaconState.Version() == version.Altair:
|
||||
slashingQuotient = cfg.MinSlashingPenaltyQuotientAltair
|
||||
case beaconState.Version() == version.Bellatrix:
|
||||
slashingQuotient = cfg.MinSlashingPenaltyQuotientBellatrix
|
||||
default:
|
||||
return nil, errors.New("unknown state version")
|
||||
|
||||
slashingQuotient, err := beaconState.MinSlashingPenaltyQuotient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
beaconState, err = slashFunc(ctx, beaconState, slashing.Header_1.Header.ProposerIndex, slashingQuotient, cfg.ProposerRewardQuotient)
|
||||
if err != nil {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -13,22 +13,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 +47,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 +72,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
|
||||
@@ -326,20 +327,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 +389,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 +478,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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 := ðpb.Checkpoint{Root: jr[:], Epoch: 3}
|
||||
fc := ðpb.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: ðpb.Checkpoint{Epoch: 1, Root: params.BeaconConfig().ZeroHash[:]},
|
||||
FinalizedCheckpoint: ðpb.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: ðpb.Checkpoint{Epoch: 1, Root: params.BeaconConfig().ZeroHash[:]},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{Epoch: 1, Root: params.BeaconConfig().ZeroHash[:]},
|
||||
})
|
||||
root, err = blk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
})
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(ðpb.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(ðpb.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)
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ 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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
})
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 := ðpb.Checkpoint{Root: jr[:], Epoch: 3}
|
||||
fc := ðpb.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: ðpb.Checkpoint{Epoch: 1, Root: params.BeaconConfig().ZeroHash[:]},
|
||||
FinalizedCheckpoint: ðpb.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: ðpb.Checkpoint{Epoch: 1, Root: params.BeaconConfig().ZeroHash[:]},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{Epoch: 1, Root: params.BeaconConfig().ZeroHash[:]},
|
||||
})
|
||||
root, err = blk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(ðpb.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(ðpb.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)
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -142,5 +142,7 @@ func (s *Service) logTtdStatus(ctx context.Context, ttd *uint256.Int) (bool, err
|
||||
"latestDifficulty": latestTtd.String(),
|
||||
"terminalDifficulty": ttd.ToBig().String(),
|
||||
}).Info("terminal difficulty has not been reached yet")
|
||||
|
||||
totalTerminalDifficulty.Set(float64(latestTtd.Uint64()))
|
||||
return false, nil
|
||||
}
|
||||
|
||||
@@ -6,6 +6,10 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
totalTerminalDifficulty = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "total_terminal_difficulty",
|
||||
Help: "The total terminal difficulty of the execution chain before merge",
|
||||
})
|
||||
newPayloadLatency = promauto.NewHistogram(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "new_payload_v1_latency_milliseconds",
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ type BeaconState interface {
|
||||
// SpecParametersProvider provides fork-specific configuration parameters as
|
||||
// defined in the consensus specification for the beacon chain.
|
||||
type SpecParametersProvider interface {
|
||||
MinSlashingPenaltyQuotient() (uint64, error)
|
||||
InactivityPenaltyQuotient() (uint64, error)
|
||||
ProportionalSlashingMultiplier() (uint64, error)
|
||||
}
|
||||
|
||||
@@ -28,3 +28,15 @@ func (b *BeaconState) InactivityPenaltyQuotient() (uint64, error) {
|
||||
}
|
||||
return 0, errNotSupported("InactivityPenaltyQuotient()", b.version)
|
||||
}
|
||||
|
||||
func (b *BeaconState) MinSlashingPenaltyQuotient() (uint64, error) {
|
||||
switch b.version {
|
||||
case version.Bellatrix:
|
||||
return params.BeaconConfig().MinSlashingPenaltyQuotientBellatrix, nil
|
||||
case version.Altair:
|
||||
return params.BeaconConfig().MinSlashingPenaltyQuotientAltair, nil
|
||||
case version.Phase0:
|
||||
return params.BeaconConfig().MinSlashingPenaltyQuotient, nil
|
||||
}
|
||||
return 0, errNotSupported("MinSlashingPenaltyQuotient()", b.version)
|
||||
}
|
||||
|
||||
@@ -9,3 +9,7 @@ func (b *BeaconState) ProportionalSlashingMultiplier() (uint64, error) {
|
||||
func (b *BeaconState) InactivityPenaltyQuotient() (uint64, error) {
|
||||
return params.BeaconConfig().InactivityPenaltyQuotient, nil
|
||||
}
|
||||
|
||||
func (b *BeaconState) MinSlashingPenaltyQuotient() (uint64, error) {
|
||||
return params.BeaconConfig().MinSlashingPenaltyQuotient, nil
|
||||
}
|
||||
|
||||
@@ -9,3 +9,7 @@ func (b *BeaconState) ProportionalSlashingMultiplier() (uint64, error) {
|
||||
func (b *BeaconState) InactivityPenaltyQuotient() (uint64, error) {
|
||||
return params.BeaconConfig().InactivityPenaltyQuotientAltair, nil
|
||||
}
|
||||
|
||||
func (b *BeaconState) MinSlashingPenaltyQuotient() (uint64, error) {
|
||||
return params.BeaconConfig().MinSlashingPenaltyQuotientAltair, nil
|
||||
}
|
||||
|
||||
@@ -9,3 +9,7 @@ func (b *BeaconState) ProportionalSlashingMultiplier() (uint64, error) {
|
||||
func (b *BeaconState) InactivityPenaltyQuotient() (uint64, error) {
|
||||
return params.BeaconConfig().InactivityPenaltyQuotientBellatrix, nil
|
||||
}
|
||||
|
||||
func (b *BeaconState) MinSlashingPenaltyQuotient() (uint64, error) {
|
||||
return params.BeaconConfig().MinSlashingPenaltyQuotientBellatrix, nil
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ go_library(
|
||||
importpath = "github.com/prysmaticlabs/prysm/config/features",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//cmd:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@com_github_urfave_cli_v2//:go_default_library",
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/cmd"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
@@ -130,7 +131,11 @@ func configureTestnet(ctx *cli.Context) error {
|
||||
}
|
||||
params.UseRopstenNetworkConfig()
|
||||
} else {
|
||||
log.Warn("Running on Ethereum Consensus Mainnet")
|
||||
if ctx.IsSet(cmd.ChainConfigFileFlag.Name) {
|
||||
log.Warn("Running on custom Ethereum network specified in a chain configuration yaml file")
|
||||
} else {
|
||||
log.Warn("Running on Ethereum Mainnet")
|
||||
}
|
||||
if err := params.SetActive(params.MainnetConfig().Copy()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ common_deps = [
|
||||
"//io/file:go_default_library",
|
||||
"//proto/eth/service:go_default_library",
|
||||
"//proto/eth/v1:go_default_library",
|
||||
"//math:go_default_library",
|
||||
"//proto/engine/v1:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//testing/assert:go_default_library",
|
||||
"//testing/endtoend/components:go_default_library",
|
||||
@@ -64,6 +66,7 @@ go_test(
|
||||
"@web3signer",
|
||||
],
|
||||
eth_network = "minimal",
|
||||
flaky = True,
|
||||
shard_count = 2,
|
||||
tags = [
|
||||
"e2e",
|
||||
@@ -72,7 +75,6 @@ go_test(
|
||||
"requires-network",
|
||||
],
|
||||
deps = common_deps,
|
||||
flaky = True,
|
||||
)
|
||||
|
||||
go_test(
|
||||
@@ -96,6 +98,7 @@ go_test(
|
||||
"@web3signer",
|
||||
],
|
||||
eth_network = "mainnet",
|
||||
flaky = True,
|
||||
shard_count = 2,
|
||||
tags = [
|
||||
"e2e",
|
||||
@@ -105,7 +108,6 @@ go_test(
|
||||
"requires-network",
|
||||
],
|
||||
deps = common_deps,
|
||||
flaky = True,
|
||||
)
|
||||
|
||||
go_test(
|
||||
@@ -129,6 +131,7 @@ go_test(
|
||||
"@web3signer",
|
||||
],
|
||||
eth_network = "mainnet",
|
||||
flaky = True,
|
||||
shard_count = 2,
|
||||
tags = [
|
||||
"exclusive",
|
||||
@@ -138,7 +141,6 @@ go_test(
|
||||
"scenario",
|
||||
],
|
||||
deps = common_deps,
|
||||
flaky = True,
|
||||
)
|
||||
|
||||
go_test(
|
||||
@@ -162,6 +164,7 @@ go_test(
|
||||
"@web3signer",
|
||||
],
|
||||
eth_network = "minimal",
|
||||
flaky = True,
|
||||
shard_count = 2,
|
||||
tags = [
|
||||
"exclusive",
|
||||
@@ -171,5 +174,4 @@ go_test(
|
||||
"scenario",
|
||||
],
|
||||
deps = common_deps,
|
||||
flaky = True,
|
||||
)
|
||||
|
||||
@@ -26,7 +26,7 @@ type componentHandler struct {
|
||||
web3Signer e2etypes.ComponentRunner
|
||||
bootnode e2etypes.ComponentRunner
|
||||
eth1Miner e2etypes.ComponentRunner
|
||||
eth1Proxy e2etypes.ComponentRunner
|
||||
eth1Proxy e2etypes.MultipleComponentRunners
|
||||
eth1Nodes e2etypes.MultipleComponentRunners
|
||||
beaconNodes e2etypes.MultipleComponentRunners
|
||||
validatorNodes e2etypes.MultipleComponentRunners
|
||||
|
||||
@@ -137,6 +137,14 @@ func (s *BeaconNodeSet) StopAtIndex(i int) error {
|
||||
return s.nodes[i].Stop()
|
||||
}
|
||||
|
||||
// ComponentAtIndex returns the component at the provided index.
|
||||
func (s *BeaconNodeSet) ComponentAtIndex(i int) (e2etypes.ComponentRunner, error) {
|
||||
if i >= len(s.nodes) {
|
||||
return nil, errors.Errorf("provided index exceeds slice size: %d >= %d", i, len(s.nodes))
|
||||
}
|
||||
return s.nodes[i], nil
|
||||
}
|
||||
|
||||
// BeaconNode represents beacon node.
|
||||
type BeaconNode struct {
|
||||
e2etypes.ComponentRunner
|
||||
|
||||
@@ -28,7 +28,7 @@ var _ e2etypes.MultipleComponentRunners = (*NodeSet)(nil)
|
||||
var _ e2etypes.MultipleComponentRunners = (*ProxySet)(nil)
|
||||
var _ e2etypes.ComponentRunner = (*Miner)(nil)
|
||||
var _ e2etypes.ComponentRunner = (*Node)(nil)
|
||||
var _ e2etypes.ComponentRunner = (*Proxy)(nil)
|
||||
var _ e2etypes.EngineProxy = (*Proxy)(nil)
|
||||
|
||||
// WaitForBlocks waits for a certain amount of blocks to be mined by the ETH1 chain before returning.
|
||||
func WaitForBlocks(web3 *ethclient.Client, keystore *keystore.Key, blocksToWait uint64) error {
|
||||
|
||||
@@ -110,3 +110,11 @@ func (s *NodeSet) StopAtIndex(i int) error {
|
||||
}
|
||||
return s.nodes[i].Stop()
|
||||
}
|
||||
|
||||
// ComponentAtIndex returns the component at the provided index.
|
||||
func (s *NodeSet) ComponentAtIndex(i int) (e2etypes.ComponentRunner, error) {
|
||||
if i >= len(s.nodes) {
|
||||
return nil, errors.Errorf("provided index exceeds slice size: %d >= %d", i, len(s.nodes))
|
||||
}
|
||||
return s.nodes[i], nil
|
||||
}
|
||||
|
||||
@@ -110,12 +110,21 @@ func (s *ProxySet) StopAtIndex(i int) error {
|
||||
return s.proxies[i].Stop()
|
||||
}
|
||||
|
||||
// ComponentAtIndex returns the component at the provided index.
|
||||
func (s *ProxySet) ComponentAtIndex(i int) (e2etypes.ComponentRunner, error) {
|
||||
if i >= len(s.proxies) {
|
||||
return nil, errors.Errorf("provided index exceeds slice size: %d >= %d", i, len(s.proxies))
|
||||
}
|
||||
return s.proxies[i], nil
|
||||
}
|
||||
|
||||
// Proxy represents an engine-api proxy.
|
||||
type Proxy struct {
|
||||
e2etypes.ComponentRunner
|
||||
started chan struct{}
|
||||
index int
|
||||
cancel func()
|
||||
started chan struct{}
|
||||
index int
|
||||
engineProxy *proxy.Proxy
|
||||
cancel func()
|
||||
}
|
||||
|
||||
// NewProxy creates and returns an engine-api proxy.
|
||||
@@ -157,6 +166,7 @@ func (node *Proxy) Start(ctx context.Context) error {
|
||||
// Set cancel into context.
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
node.cancel = cancel
|
||||
node.engineProxy = nProxy
|
||||
// Mark node as ready.
|
||||
close(node.started)
|
||||
return nProxy.Start(ctx)
|
||||
@@ -185,6 +195,22 @@ func (node *Proxy) Stop() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddRequestInterceptor adds in a json-rpc request interceptor.
|
||||
func (node *Proxy) AddRequestInterceptor(rpcMethodName string, responseGen func() interface{}, trigger func() bool) {
|
||||
node.engineProxy.AddRequestInterceptor(rpcMethodName, responseGen, trigger)
|
||||
}
|
||||
|
||||
// RemoveRequestInterceptor removes the request interceptor for the provided method.
|
||||
func (node *Proxy) RemoveRequestInterceptor(rpcMethodName string) {
|
||||
node.engineProxy.RemoveRequestInterceptor(rpcMethodName)
|
||||
}
|
||||
|
||||
// ReleaseBackedUpRequests releases backed up http requests which
|
||||
// were previously ignored due to our interceptors.
|
||||
func (node *Proxy) ReleaseBackedUpRequests(rpcMethodName string) {
|
||||
node.engineProxy.ReleaseBackedUpRequests(rpcMethodName)
|
||||
}
|
||||
|
||||
func parseJWTSecretFromFile(jwtSecretFile string) ([]byte, error) {
|
||||
enc, err := file.ReadFileAsBytes(jwtSecretFile)
|
||||
if err != nil {
|
||||
|
||||
@@ -127,6 +127,14 @@ func (s *LighthouseBeaconNodeSet) StopAtIndex(i int) error {
|
||||
return s.nodes[i].Stop()
|
||||
}
|
||||
|
||||
// ComponentAtIndex returns the component at the provided index.
|
||||
func (s *LighthouseBeaconNodeSet) ComponentAtIndex(i int) (e2etypes.ComponentRunner, error) {
|
||||
if i >= len(s.nodes) {
|
||||
return nil, errors.Errorf("provided index exceeds slice size: %d >= %d", i, len(s.nodes))
|
||||
}
|
||||
return s.nodes[i], nil
|
||||
}
|
||||
|
||||
// LighthouseBeaconNode represents a lighthouse beacon node.
|
||||
type LighthouseBeaconNode struct {
|
||||
e2etypes.ComponentRunner
|
||||
|
||||
@@ -131,6 +131,14 @@ func (s *LighthouseValidatorNodeSet) StopAtIndex(i int) error {
|
||||
return s.nodes[i].Stop()
|
||||
}
|
||||
|
||||
// ComponentAtIndex returns the component at the provided index.
|
||||
func (s *LighthouseValidatorNodeSet) ComponentAtIndex(i int) (e2etypes.ComponentRunner, error) {
|
||||
if i >= len(s.nodes) {
|
||||
return nil, errors.Errorf("provided index exceeds slice size: %d >= %d", i, len(s.nodes))
|
||||
}
|
||||
return s.nodes[i], nil
|
||||
}
|
||||
|
||||
// LighthouseValidatorNode represents a lighthouse validator node.
|
||||
type LighthouseValidatorNode struct {
|
||||
e2etypes.ComponentRunner
|
||||
|
||||
@@ -138,6 +138,14 @@ func (s *ValidatorNodeSet) StopAtIndex(i int) error {
|
||||
return s.nodes[i].Stop()
|
||||
}
|
||||
|
||||
// ComponentAtIndex returns the component at the provided index.
|
||||
func (s *ValidatorNodeSet) ComponentAtIndex(i int) (e2etypes.ComponentRunner, error) {
|
||||
if i >= len(s.nodes) {
|
||||
return nil, errors.Errorf("provided index exceeds slice size: %d >= %d", i, len(s.nodes))
|
||||
}
|
||||
return s.nodes[i], nil
|
||||
}
|
||||
|
||||
// ValidatorNode represents a validator node.
|
||||
type ValidatorNode struct {
|
||||
e2etypes.ComponentRunner
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") # gazelle:keep
|
||||
|
||||
lighthouse_version = "v2.1.4"
|
||||
lighthouse_version = "v2.3.0"
|
||||
lighthouse_archive_name = "lighthouse-%s-x86_64-unknown-linux-gnu-portable.tar.gz" % lighthouse_version
|
||||
|
||||
def e2e_deps():
|
||||
@@ -14,12 +14,7 @@ def e2e_deps():
|
||||
|
||||
http_archive(
|
||||
name = "lighthouse",
|
||||
sha256 = "236883a4827037d96636aa259eef8cf3abc54c795adc18c4c2880842e09c743c",
|
||||
sha256 = "6029acd211f269bcf41f86fd72fe540703a167ff96dfd952ff95b1693e3b5495",
|
||||
build_file = "@prysm//testing/endtoend:lighthouse.BUILD",
|
||||
# url = ("https://github.com/sigp/lighthouse/releases/download/%s/" + lighthouse_archive_name) % lighthouse_version,
|
||||
# This is a compiled version of lighthouse from their `unstable` branch at this commit
|
||||
# https://github.com/sigp/lighthouse/commit/99bb55472c278a1050f7679b2e018546ad3a28bf. Lighthouse does not have support
|
||||
# for all the merge features as of their latest release, so this is a temporary compromise to allow multiclient test
|
||||
# runs till their official release includes the required merge features in.
|
||||
url = "https://prysmaticlabs.com/uploads/misc/lighthouse-99bb5547.tar.xz",
|
||||
url = ("https://github.com/sigp/lighthouse/releases/download/%s/" + lighthouse_archive_name) % lighthouse_version,
|
||||
)
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/api/client/beacon"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/io/file"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
"github.com/prysmaticlabs/prysm/proto/eth/service"
|
||||
v1 "github.com/prysmaticlabs/prysm/proto/eth/v1"
|
||||
"google.golang.org/grpc/codes"
|
||||
@@ -149,26 +150,10 @@ func (r *testRunner) runEvaluators(conns []*grpc.ClientConn, tickingStartTime ti
|
||||
secondsPerEpoch := uint64(params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().SecondsPerSlot))
|
||||
ticker := helpers.NewEpochTicker(tickingStartTime, secondsPerEpoch)
|
||||
for currentEpoch := range ticker.C() {
|
||||
if config.EvalInterceptor(currentEpoch) {
|
||||
if config.EvalInterceptor(currentEpoch, conns) {
|
||||
continue
|
||||
}
|
||||
wg := new(sync.WaitGroup)
|
||||
for _, eval := range config.Evaluators {
|
||||
// Fix reference to evaluator as it will be running
|
||||
// in a separate goroutine.
|
||||
evaluator := eval
|
||||
// Only run if the policy says so.
|
||||
if !evaluator.Policy(types.Epoch(currentEpoch)) {
|
||||
continue
|
||||
}
|
||||
wg.Add(1)
|
||||
go t.Run(fmt.Sprintf(evaluator.Name, currentEpoch), func(t *testing.T) {
|
||||
err := evaluator.Evaluation(conns...)
|
||||
assert.NoError(t, err, "Evaluation failed for epoch %d: %v", currentEpoch, err)
|
||||
wg.Done()
|
||||
})
|
||||
}
|
||||
wg.Wait()
|
||||
r.executeProvidedEvaluators(currentEpoch, conns, config.Evaluators)
|
||||
|
||||
if t.Failed() || currentEpoch >= config.EpochsToRun-1 {
|
||||
ticker.Done()
|
||||
@@ -558,7 +543,27 @@ func (r *testRunner) addEvent(ev func() error) {
|
||||
r.comHandler.group.Go(ev)
|
||||
}
|
||||
|
||||
func (r *testRunner) singleNodeOffline(epoch uint64) bool {
|
||||
func (r *testRunner) executeProvidedEvaluators(currentEpoch uint64, conns []*grpc.ClientConn, evals []e2etypes.Evaluator) {
|
||||
wg := new(sync.WaitGroup)
|
||||
for _, eval := range evals {
|
||||
// Fix reference to evaluator as it will be running
|
||||
// in a separate goroutine.
|
||||
evaluator := eval
|
||||
// Only run if the policy says so.
|
||||
if !evaluator.Policy(types.Epoch(currentEpoch)) {
|
||||
continue
|
||||
}
|
||||
wg.Add(1)
|
||||
go r.t.Run(fmt.Sprintf(evaluator.Name, currentEpoch), func(t *testing.T) {
|
||||
err := evaluator.Evaluation(conns...)
|
||||
assert.NoError(t, err, "Evaluation failed for epoch %d: %v", currentEpoch, err)
|
||||
wg.Done()
|
||||
})
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func (r *testRunner) singleNodeOffline(epoch uint64, _ []*grpc.ClientConn) bool {
|
||||
switch epoch {
|
||||
case 9:
|
||||
require.NoError(r.t, r.comHandler.beaconNodes.PauseAtIndex(0))
|
||||
@@ -575,7 +580,7 @@ func (r *testRunner) singleNodeOffline(epoch uint64) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (r *testRunner) singleNodeOfflineMulticlient(epoch uint64) bool {
|
||||
func (r *testRunner) singleNodeOfflineMulticlient(epoch uint64, _ []*grpc.ClientConn) bool {
|
||||
switch epoch {
|
||||
case 9:
|
||||
require.NoError(r.t, r.comHandler.beaconNodes.PauseAtIndex(0))
|
||||
@@ -596,7 +601,7 @@ func (r *testRunner) singleNodeOfflineMulticlient(epoch uint64) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (r *testRunner) eeOffline(epoch uint64) bool {
|
||||
func (r *testRunner) eeOffline(epoch uint64, _ []*grpc.ClientConn) bool {
|
||||
switch epoch {
|
||||
case 9:
|
||||
require.NoError(r.t, r.comHandler.eth1Miner.Pause())
|
||||
@@ -611,7 +616,7 @@ func (r *testRunner) eeOffline(epoch uint64) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (r *testRunner) allValidatorsOffline(epoch uint64) bool {
|
||||
func (r *testRunner) allValidatorsOffline(epoch uint64, _ []*grpc.ClientConn) bool {
|
||||
switch epoch {
|
||||
case 9:
|
||||
require.NoError(r.t, r.comHandler.validatorNodes.PauseAtIndex(0))
|
||||
@@ -628,7 +633,95 @@ func (r *testRunner) allValidatorsOffline(epoch uint64) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// All Epochs are valid.
|
||||
func defaultInterceptor(_ uint64) bool {
|
||||
func (r *testRunner) optimisticSync(epoch uint64, conns []*grpc.ClientConn) bool {
|
||||
switch epoch {
|
||||
case 9:
|
||||
component, err := r.comHandler.eth1Proxy.ComponentAtIndex(0)
|
||||
require.NoError(r.t, err)
|
||||
component.(e2etypes.EngineProxy).AddRequestInterceptor("engine_newPayloadV1", func() interface{} {
|
||||
return &enginev1.PayloadStatus{
|
||||
Status: enginev1.PayloadStatus_SYNCING,
|
||||
LatestValidHash: make([]byte, 32),
|
||||
}
|
||||
}, func() bool {
|
||||
return true
|
||||
})
|
||||
return true
|
||||
case 10:
|
||||
r.executeProvidedEvaluators(epoch, []*grpc.ClientConn{conns[0]}, []e2etypes.Evaluator{
|
||||
ev.OptimisticSyncEnabled,
|
||||
})
|
||||
// Disable Interceptor
|
||||
component, err := r.comHandler.eth1Proxy.ComponentAtIndex(0)
|
||||
require.NoError(r.t, err)
|
||||
engineProxy, ok := component.(e2etypes.EngineProxy)
|
||||
require.Equal(r.t, true, ok)
|
||||
engineProxy.RemoveRequestInterceptor("engine_newPayloadV1")
|
||||
engineProxy.ReleaseBackedUpRequests("engine_newPayloadV1")
|
||||
|
||||
return true
|
||||
case 11, 12:
|
||||
// Allow 2 epochs for the network to finalize again.
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (r *testRunner) optimisticSyncMulticlient(epoch uint64, conns []*grpc.ClientConn) bool {
|
||||
switch epoch {
|
||||
case 9:
|
||||
// Set it for prysm beacon node.
|
||||
component, err := r.comHandler.eth1Proxy.ComponentAtIndex(0)
|
||||
require.NoError(r.t, err)
|
||||
component.(e2etypes.EngineProxy).AddRequestInterceptor("engine_newPayloadV1", func() interface{} {
|
||||
return &enginev1.PayloadStatus{
|
||||
Status: enginev1.PayloadStatus_SYNCING,
|
||||
LatestValidHash: make([]byte, 32),
|
||||
}
|
||||
}, func() bool {
|
||||
return true
|
||||
})
|
||||
// Set it for lighthouse beacon node.
|
||||
component, err = r.comHandler.eth1Proxy.ComponentAtIndex(2)
|
||||
require.NoError(r.t, err)
|
||||
component.(e2etypes.EngineProxy).AddRequestInterceptor("engine_newPayloadV1", func() interface{} {
|
||||
return &enginev1.PayloadStatus{
|
||||
Status: enginev1.PayloadStatus_SYNCING,
|
||||
LatestValidHash: make([]byte, 32),
|
||||
}
|
||||
}, func() bool {
|
||||
return true
|
||||
})
|
||||
return true
|
||||
case 10:
|
||||
r.executeProvidedEvaluators(epoch, []*grpc.ClientConn{conns[0]}, []e2etypes.Evaluator{
|
||||
ev.OptimisticSyncEnabled,
|
||||
})
|
||||
// Disable Interceptor
|
||||
component, err := r.comHandler.eth1Proxy.ComponentAtIndex(0)
|
||||
require.NoError(r.t, err)
|
||||
engineProxy, ok := component.(e2etypes.EngineProxy)
|
||||
require.Equal(r.t, true, ok)
|
||||
engineProxy.RemoveRequestInterceptor("engine_newPayloadV1")
|
||||
engineProxy.ReleaseBackedUpRequests("engine_newPayloadV1")
|
||||
|
||||
// Remove for lighthouse too
|
||||
component, err = r.comHandler.eth1Proxy.ComponentAtIndex(2)
|
||||
require.NoError(r.t, err)
|
||||
engineProxy, ok = component.(e2etypes.EngineProxy)
|
||||
require.Equal(r.t, true, ok)
|
||||
engineProxy.RemoveRequestInterceptor("engine_newPayloadV1")
|
||||
engineProxy.ReleaseBackedUpRequests("engine_newPayloadV1")
|
||||
|
||||
return true
|
||||
case 11, 12:
|
||||
// Allow 2 epochs for the network to finalize again.
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// All Epochs are valid.
|
||||
func defaultInterceptor(_ uint64, _ []*grpc.ClientConn) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ go_library(
|
||||
"//consensus-types/wrapper:go_default_library",
|
||||
"//container/slice:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//math:go_default_library",
|
||||
"//network/forks:go_default_library",
|
||||
"//proto/eth/service:go_default_library",
|
||||
"//proto/eth/v1:go_default_library",
|
||||
|
||||
@@ -3,14 +3,20 @@ package evaluators
|
||||
import (
|
||||
"context"
|
||||
"math"
|
||||
"strconv"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
ctypes "github.com/prysmaticlabs/prysm/consensus-types/primitives"
|
||||
mathutil "github.com/prysmaticlabs/prysm/math"
|
||||
"github.com/prysmaticlabs/prysm/proto/eth/service"
|
||||
v2 "github.com/prysmaticlabs/prysm/proto/eth/v2"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/testing/endtoend/helpers"
|
||||
e2e "github.com/prysmaticlabs/prysm/testing/endtoend/params"
|
||||
"github.com/prysmaticlabs/prysm/testing/endtoend/policies"
|
||||
"github.com/prysmaticlabs/prysm/testing/endtoend/types"
|
||||
"github.com/prysmaticlabs/prysm/time/slots"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
)
|
||||
@@ -23,6 +29,13 @@ var TransactionsPresent = types.Evaluator{
|
||||
Evaluation: transactionsPresent,
|
||||
}
|
||||
|
||||
// OptimisticSyncEnabled checks that the node is in an optimistic state.
|
||||
var OptimisticSyncEnabled = types.Evaluator{
|
||||
Name: "optimistic_sync_at_epoch_%d",
|
||||
Policy: policies.AllEpochs,
|
||||
Evaluation: optimisticSyncEnabled,
|
||||
}
|
||||
|
||||
func transactionsPresent(conns ...*grpc.ClientConn) error {
|
||||
conn := conns[0]
|
||||
client := ethpb.NewBeaconChainClient(conn)
|
||||
@@ -52,3 +65,49 @@ func transactionsPresent(conns ...*grpc.ClientConn) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func optimisticSyncEnabled(conns ...*grpc.ClientConn) error {
|
||||
for _, conn := range conns {
|
||||
client := service.NewBeaconChainClient(conn)
|
||||
head, err := client.GetBlockV2(context.Background(), &v2.BlockRequestV2{BlockId: []byte("head")})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
headSlot := uint64(0)
|
||||
switch hb := head.Data.Message.(type) {
|
||||
case *v2.SignedBeaconBlockContainerV2_Phase0Block:
|
||||
headSlot = uint64(hb.Phase0Block.Slot)
|
||||
case *v2.SignedBeaconBlockContainerV2_AltairBlock:
|
||||
headSlot = uint64(hb.AltairBlock.Slot)
|
||||
case *v2.SignedBeaconBlockContainerV2_BellatrixBlock:
|
||||
headSlot = uint64(hb.BellatrixBlock.Slot)
|
||||
default:
|
||||
return errors.New("no valid block type retrieved")
|
||||
}
|
||||
currEpoch := slots.ToEpoch(ctypes.Slot(headSlot))
|
||||
startSlot, err := slots.EpochStart(currEpoch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
isOptimistic := false
|
||||
for i := startSlot; i <= ctypes.Slot(headSlot); i++ {
|
||||
castI, err := mathutil.Int(uint64(i))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
block, err := client.GetBlockV2(context.Background(), &v2.BlockRequestV2{BlockId: []byte(strconv.Itoa(castI))})
|
||||
if err != nil {
|
||||
// Continue in the event of non-existent blocks.
|
||||
continue
|
||||
}
|
||||
if !block.ExecutionOptimistic {
|
||||
return errors.New("expected block to be optimistic, but it is not")
|
||||
}
|
||||
isOptimistic = true
|
||||
}
|
||||
if !isOptimistic {
|
||||
return errors.New("expected block to be optimistic, but it is not")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -14,3 +14,10 @@ func TestEndToEnd_ScenarioRun_BeaconOffline_Multiclient(t *testing.T) {
|
||||
runner.config.EvalInterceptor = runner.singleNodeOffline
|
||||
runner.scenarioRunner()
|
||||
}
|
||||
|
||||
func TestEndToEnd_ScenarioRun_OptimisticSync_Multiclient(t *testing.T) {
|
||||
runner := e2eMainnet(t, false /*usePrysmSh*/, true /*useMultiClient*/)
|
||||
runner.config.Evaluators = scenarioEvalsMulti()
|
||||
runner.config.EvalInterceptor = runner.optimisticSyncMulticlient
|
||||
runner.scenarioRunner()
|
||||
}
|
||||
|
||||
@@ -26,3 +26,11 @@ func TestEndToEnd_ScenarioRun_EEOffline(t *testing.T) {
|
||||
runner.config.EvalInterceptor = runner.eeOffline
|
||||
runner.scenarioRunner()
|
||||
}
|
||||
|
||||
func TestEndToEnd_ScenarioRun_OptimisticSync(t *testing.T) {
|
||||
runner := e2eMinimal(t)
|
||||
|
||||
runner.config.Evaluators = scenarioEvals()
|
||||
runner.config.EvalInterceptor = runner.optimisticSync
|
||||
runner.scenarioRunner()
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ type E2EConfig struct {
|
||||
Seed int64
|
||||
TracingSinkEndpoint string
|
||||
Evaluators []Evaluator
|
||||
EvalInterceptor func(uint64) bool
|
||||
EvalInterceptor func(uint64, []*grpc.ClientConn) bool
|
||||
BeaconFlags []string
|
||||
ValidatorFlags []string
|
||||
PeerIDs []string
|
||||
@@ -75,6 +75,8 @@ type ComponentRunner interface {
|
||||
|
||||
type MultipleComponentRunners interface {
|
||||
ComponentRunner
|
||||
// ComponentAtIndex returns the component at index
|
||||
ComponentAtIndex(i int) (ComponentRunner, error)
|
||||
// PauseAtIndex pauses the grouped component element at the desired index.
|
||||
PauseAtIndex(i int) error
|
||||
// ResumeAtIndex resumes the grouped component element at the desired index.
|
||||
@@ -83,6 +85,16 @@ type MultipleComponentRunners interface {
|
||||
StopAtIndex(i int) error
|
||||
}
|
||||
|
||||
type EngineProxy interface {
|
||||
ComponentRunner
|
||||
// AddRequestInterceptor adds in a json-rpc request interceptor.
|
||||
AddRequestInterceptor(rpcMethodName string, responseGen func() interface{}, trigger func() bool)
|
||||
// RemoveRequestInterceptor removes the request interceptor for the provided method.
|
||||
RemoveRequestInterceptor(rpcMethodName string)
|
||||
// ReleaseBackedUpRequests releases backed up http requests.
|
||||
ReleaseBackedUpRequests(rpcMethodName string)
|
||||
}
|
||||
|
||||
// BeaconNodeSet defines an interface for an object that fulfills the duties
|
||||
// of a group of beacon nodes.
|
||||
type BeaconNodeSet interface {
|
||||
|
||||
@@ -34,8 +34,8 @@ type jsonRPCObject struct {
|
||||
}
|
||||
|
||||
type interceptorConfig struct {
|
||||
response interface{}
|
||||
trigger func() bool
|
||||
responseGen func() interface{}
|
||||
trigger func() bool
|
||||
}
|
||||
|
||||
// Proxy server that sits as a middleware between an Ethereum consensus client and an execution client,
|
||||
@@ -46,7 +46,7 @@ type Proxy struct {
|
||||
srv *http.Server
|
||||
lock sync.RWMutex
|
||||
interceptors map[string]*interceptorConfig
|
||||
backedUpRequests []*http.Request
|
||||
backedUpRequests map[string][]*http.Request
|
||||
}
|
||||
|
||||
// New creates a proxy server forwarding requests from a consensus client to an execution client.
|
||||
@@ -57,7 +57,8 @@ func New(opts ...Option) (*Proxy, error) {
|
||||
proxyPort: defaultProxyPort,
|
||||
logger: logrus.New(),
|
||||
},
|
||||
interceptors: make(map[string]*interceptorConfig),
|
||||
interceptors: make(map[string]*interceptorConfig),
|
||||
backedUpRequests: map[string][]*http.Request{},
|
||||
}
|
||||
for _, o := range opts {
|
||||
if err := o(p); err != nil {
|
||||
@@ -112,7 +113,7 @@ func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
// Check if we need to intercept the request with a custom response.
|
||||
hasIntercepted, err := p.interceptIfNeeded(requestBytes, w)
|
||||
hasIntercepted, err := p.interceptIfNeeded(requestBytes, w, r)
|
||||
if err != nil {
|
||||
p.cfg.logger.WithError(err).Error("Could not intercept request")
|
||||
return
|
||||
@@ -126,7 +127,7 @@ func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// AddRequestInterceptor for a desired json-rpc method by specifying a custom response
|
||||
// and a function that checks if the interceptor should be triggered.
|
||||
func (p *Proxy) AddRequestInterceptor(rpcMethodName string, response interface{}, trigger func() bool) {
|
||||
func (p *Proxy) AddRequestInterceptor(rpcMethodName string, response func() interface{}, trigger func() bool) {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
p.cfg.logger.Infof("Adding in interceptor for method %s", rpcMethodName)
|
||||
@@ -136,9 +137,40 @@ func (p *Proxy) AddRequestInterceptor(rpcMethodName string, response interface{}
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveRequestInterceptor removes the request interceptor for the provided method.
|
||||
func (p *Proxy) RemoveRequestInterceptor(rpcMethodName string) {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
p.cfg.logger.Infof("Removing interceptor for method %s", rpcMethodName)
|
||||
delete(p.interceptors, rpcMethodName)
|
||||
}
|
||||
|
||||
// ReleaseBackedUpRequests releases backed up http requests which
|
||||
// were previously ignored due to our interceptors.
|
||||
func (p *Proxy) ReleaseBackedUpRequests(rpcMethodName string) {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
reqs := p.backedUpRequests[rpcMethodName]
|
||||
for _, r := range reqs {
|
||||
p.cfg.logger.Infof("Sending backed up request for method %s", rpcMethodName)
|
||||
rBytes, err := parseRequestBytes(r)
|
||||
if err != nil {
|
||||
p.cfg.logger.Error(err)
|
||||
continue
|
||||
}
|
||||
res, err := p.sendHttpRequest(r, rBytes)
|
||||
if err != nil {
|
||||
p.cfg.logger.Error(err)
|
||||
continue
|
||||
}
|
||||
p.cfg.logger.Infof("Received response %s for backed up request for method %s", http.StatusText(res.StatusCode), rpcMethodName)
|
||||
}
|
||||
delete(p.backedUpRequests, rpcMethodName)
|
||||
}
|
||||
|
||||
// Checks if there is a custom interceptor hook on the request, check if it can be
|
||||
// triggered, and then write the custom response to the writer.
|
||||
func (p *Proxy) interceptIfNeeded(requestBytes []byte, w http.ResponseWriter) (hasIntercepted bool, err error) {
|
||||
func (p *Proxy) interceptIfNeeded(requestBytes []byte, w http.ResponseWriter, r *http.Request) (hasIntercepted bool, err error) {
|
||||
if !isEngineAPICall(requestBytes) {
|
||||
return
|
||||
}
|
||||
@@ -159,12 +191,13 @@ func (p *Proxy) interceptIfNeeded(requestBytes []byte, w http.ResponseWriter) (h
|
||||
jResp := &jsonRPCObject{
|
||||
Method: jreq.Method,
|
||||
ID: jreq.ID,
|
||||
Result: interceptor.response,
|
||||
Result: interceptor.responseGen(),
|
||||
}
|
||||
if err = json.NewEncoder(w).Encode(jResp); err != nil {
|
||||
return
|
||||
}
|
||||
hasIntercepted = true
|
||||
p.backedUpRequests[jreq.Method] = append(p.backedUpRequests[jreq.Method], r)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -177,18 +210,39 @@ func (p *Proxy) proxyRequest(requestBytes []byte, w http.ResponseWriter, r *http
|
||||
jreq = &jsonRPCObject{Method: "unknown"}
|
||||
}
|
||||
p.cfg.logger.Infof("Forwarding %s request for method %s to %s", r.Method, jreq.Method, p.cfg.destinationUrl.String())
|
||||
proxyReq, err := http.NewRequest(r.Method, p.cfg.destinationUrl.String(), r.Body)
|
||||
proxyRes, err := p.sendHttpRequest(r, requestBytes)
|
||||
if err != nil {
|
||||
p.cfg.logger.WithError(err).Error("Could create new request")
|
||||
return
|
||||
}
|
||||
p.cfg.logger.Infof("Received response for %s request with method %s from %s", r.Method, jreq.Method, p.cfg.destinationUrl.String())
|
||||
|
||||
defer func() {
|
||||
if err = proxyRes.Body.Close(); err != nil {
|
||||
p.cfg.logger.WithError(err).Error("Could not do close proxy responseGen body")
|
||||
}
|
||||
}()
|
||||
|
||||
// Pipe the proxy responseGen to the original caller.
|
||||
if _, err = io.Copy(w, proxyRes.Body); err != nil {
|
||||
p.cfg.logger.WithError(err).Error("Could not copy proxy request body")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Proxy) sendHttpRequest(req *http.Request, requestBytes []byte) (*http.Response, error) {
|
||||
proxyReq, err := http.NewRequest(req.Method, p.cfg.destinationUrl.String(), req.Body)
|
||||
if err != nil {
|
||||
p.cfg.logger.WithError(err).Error("Could not create new request")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Set the modified request as the proxy request body.
|
||||
proxyReq.Body = ioutil.NopCloser(bytes.NewBuffer(requestBytes))
|
||||
|
||||
// Required proxy headers for forwarding JSON-RPC requests to the execution client.
|
||||
proxyReq.Header.Set("Host", r.Host)
|
||||
proxyReq.Header.Set("X-Forwarded-For", r.RemoteAddr)
|
||||
proxyReq.Header.Set("Host", req.Host)
|
||||
proxyReq.Header.Set("X-Forwarded-For", req.RemoteAddr)
|
||||
proxyReq.Header.Set("Content-Type", "application/json")
|
||||
|
||||
client := &http.Client{}
|
||||
@@ -198,21 +252,9 @@ func (p *Proxy) proxyRequest(requestBytes []byte, w http.ResponseWriter, r *http
|
||||
proxyRes, err := client.Do(proxyReq)
|
||||
if err != nil {
|
||||
p.cfg.logger.WithError(err).Error("Could not forward request to destination server")
|
||||
return
|
||||
}
|
||||
p.cfg.logger.Infof("Received response for %s request with method %s from %s", r.Method, jreq.Method, p.cfg.destinationUrl.String())
|
||||
|
||||
defer func() {
|
||||
if err = proxyRes.Body.Close(); err != nil {
|
||||
p.cfg.logger.WithError(err).Error("Could not do close proxy response body")
|
||||
}
|
||||
}()
|
||||
|
||||
// Pipe the proxy response to the original caller.
|
||||
if _, err = io.Copy(w, proxyRes.Body); err != nil {
|
||||
p.cfg.logger.WithError(err).Error("Could not copy proxy request body")
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
return proxyRes, nil
|
||||
}
|
||||
|
||||
// Peek into the bytes of an HTTP request's body.
|
||||
|
||||
@@ -116,7 +116,9 @@ func TestProxy_CustomInterceptors(t *testing.T) {
|
||||
// RPC method to intercept.
|
||||
proxy.AddRequestInterceptor(
|
||||
method,
|
||||
&syncingResponse{Syncing: false}, // Custom response.
|
||||
func() interface{} {
|
||||
return &syncingResponse{Syncing: false}
|
||||
}, // Custom response.
|
||||
func() bool {
|
||||
return true // Always intercept with a custom response.
|
||||
},
|
||||
@@ -164,7 +166,9 @@ func TestProxy_CustomInterceptors(t *testing.T) {
|
||||
method := "engine_newPayloadV1"
|
||||
|
||||
// RPC method to intercept.
|
||||
wantInterceptedResponse := &engineResponse{BlockHash: common.BytesToHash([]byte("bar"))}
|
||||
wantInterceptedResponse := func() interface{} {
|
||||
return &engineResponse{BlockHash: common.BytesToHash([]byte("bar"))}
|
||||
}
|
||||
conditional := false
|
||||
proxy.AddRequestInterceptor(
|
||||
method,
|
||||
@@ -199,7 +203,7 @@ func TestProxy_CustomInterceptors(t *testing.T) {
|
||||
proxyResult = &engineResponse{}
|
||||
err = rpcClient.CallContext(ctx, proxyResult, method)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, wantInterceptedResponse, proxyResult)
|
||||
require.DeepEqual(t, wantInterceptedResponse(), proxyResult)
|
||||
})
|
||||
t.Run("triggers interceptor response correctly", func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
@@ -230,7 +234,9 @@ func TestProxy_CustomInterceptors(t *testing.T) {
|
||||
method := "engine_newPayloadV1"
|
||||
|
||||
// RPC method to intercept.
|
||||
wantInterceptedResponse := &engineResponse{BlockHash: common.BytesToHash([]byte("bar"))}
|
||||
wantInterceptedResponse := func() interface{} {
|
||||
return &engineResponse{BlockHash: common.BytesToHash([]byte("bar"))}
|
||||
}
|
||||
proxy.AddRequestInterceptor(
|
||||
method,
|
||||
wantInterceptedResponse,
|
||||
@@ -249,7 +255,7 @@ func TestProxy_CustomInterceptors(t *testing.T) {
|
||||
|
||||
// The interception should work and we should not be getting the destination
|
||||
// response but rather a custom response from the interceptor config.
|
||||
require.DeepEqual(t, wantInterceptedResponse, proxyResult)
|
||||
require.DeepEqual(t, wantInterceptedResponse(), proxyResult)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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()),
|
||||
|
||||
Reference in New Issue
Block a user