Compare commits

...

15 Commits

Author SHA1 Message Date
terence tsao
b1fa0460bf Fix withdrawal epoch overflows 2022-05-23 10:50:30 -07:00
terence tsao
c2f3717f63 Merge branch 'develop' of github.com:prysmaticlabs/prysm into develop 2022-05-23 06:48:47 -07:00
Potuz
237807b248 Do not update forkchoice checkpoints on calls to Head (#10702)
* Only update forkchoice checkpoints at epoch transition

* gazelle

* blockchain package changes

* fix node

* spectest package

* rpc package

* fix spec test

* Fix spectests

* fix new_slot.test

* gaz

* fix spectests

* fix conflicts

* Update beacon-chain/blockchain/process_block.go

* regression do not update on newSlot

* revert bd64cab

* terence's review

* fix conflicts

* fix latest conflicts

* gaz

* go mod tidy

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2022-05-22 18:37:01 +00:00
terencechain
bcd75adedd Consolidate blockchain errors (#10736)
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2022-05-22 17:48:54 +00:00
Potuz
0c981e8853 Change synced new block log (#10724)
* Change synced new block log

* Update beacon-chain/blockchain/log.go

Co-authored-by: terencechain <terence@prysmaticlabs.com>

* Fix finalized -> justified

* Update beacon-chain/blockchain/receive_block.go

* fix conflicts

Co-authored-by: terencechain <terence@prysmaticlabs.com>
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2022-05-22 16:57:48 +00:00
terence tsao
6be2b2071a Consolidate blockchain errors 2022-05-22 09:56:05 -07:00
Potuz
e7991b9d7b Track unrealized justification/finalization in forkchoice (#10658)
* Track unrealized justification/finalization in forkchoice

* add missing files

* mod tidy

Co-authored-by: terencechain <terence@prysmaticlabs.com>
2022-05-21 10:27:07 -03:00
Raul Jordan
244e670b71 Move BeaconBlockNil Checker Function to Consensus-Types/Wrapper Package (#10731)
* beacon block is nil wrapper

* gaz

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2022-05-20 23:29:16 +00:00
Raul Jordan
dc5fb92b28 Remove Unnecessary State Interfaces (#10707)
* rem other state interfaces

* redundant check

* gaz

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2022-05-20 22:40:03 +00:00
terencechain
a2db03b9e9 Update engine API err codes (#10730)
Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>
2022-05-20 20:08:00 +00:00
terencechain
370cf1a6c8 Chain info: Return err if checkpoint is nil (#10729)
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2022-05-20 18:41:33 +00:00
Potuz
76f6d74b83 Add new slot tests (#10728)
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2022-05-20 18:17:53 +00:00
terencechain
addb3cd665 More selective on marking block as bad (#10681)
* Starting, looking for feedbacks

* Update error.go

* Wrap invalid blocks to rest of the processings

* More tests

* More tests

* Fix tests

* Update process_block_test.go

* Update execution_engine_test.go

* Update BUILD.bazel

* Nishant's feedback and Kasey's recommendation

* Add comments on what an invalid block is

* Update beacon-chain/blockchain/error.go

Co-authored-by: Potuz <potuz@prysmaticlabs.com>

* Update beacon-chain/blockchain/error.go

Co-authored-by: Potuz <potuz@prysmaticlabs.com>

* Rm faulty invalid conditions

Co-authored-by: Potuz <potuz@prysmaticlabs.com>
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2022-05-20 17:05:39 +00:00
Preston Van Loon
c603d120d7 Refactor high complexity StreamBlocksAltair (#10726)
* Refactor high complexity StreamBlocksAltair

* catch nil data

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2022-05-20 16:17:55 +00:00
Raul Jordan
39893bbe30 Encapsulate Fork-Specific Parameters Under BeaconState Interface (#10706)
* encapsulate beacon state specific spec parameters

* edit build file

* code review suggestion

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2022-05-20 15:30:30 +00:00
144 changed files with 1836 additions and 838 deletions

View File

@@ -66,6 +66,7 @@ go_library(
"//config/params:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//consensus-types/primitives:go_default_library",
"//consensus-types/wrapper:go_default_library",
"//crypto/bls:go_default_library",
"//encoding/bytesutil:go_default_library",
"//math:go_default_library",
@@ -110,6 +111,7 @@ go_test(
"log_test.go",
"metrics_test.go",
"mock_test.go",
"new_slot_test.go",
"pow_block_test.go",
"process_attestation_test.go",
"process_block_test.go",

View File

@@ -4,6 +4,8 @@ import (
"context"
"time"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/beacon-chain/blockchain/store"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice"
doublylinkedtree "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/doubly-linked-tree"
@@ -79,9 +81,9 @@ type CanonicalFetcher interface {
// FinalizationFetcher defines a common interface for methods in blockchain service which
// directly retrieve finalization and justification related data.
type FinalizationFetcher interface {
FinalizedCheckpt() *ethpb.Checkpoint
CurrentJustifiedCheckpt() *ethpb.Checkpoint
PreviousJustifiedCheckpt() *ethpb.Checkpoint
FinalizedCheckpt() (*ethpb.Checkpoint, error)
CurrentJustifiedCheckpt() (*ethpb.Checkpoint, error)
PreviousJustifiedCheckpt() (*ethpb.Checkpoint, error)
VerifyFinalizedBlkDescendant(ctx context.Context, blockRoot [32]byte) error
}
@@ -92,44 +94,47 @@ type OptimisticModeFetcher interface {
}
// FinalizedCheckpt returns the latest finalized checkpoint from chain store.
func (s *Service) FinalizedCheckpt() *ethpb.Checkpoint {
cp := s.store.FinalizedCheckpt()
if cp == nil {
return &ethpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
func (s *Service) FinalizedCheckpt() (*ethpb.Checkpoint, error) {
cp, err := s.store.FinalizedCheckpt()
if err != nil {
return nil, err
}
return ethpb.CopyCheckpoint(cp)
return ethpb.CopyCheckpoint(cp), nil
}
// CurrentJustifiedCheckpt returns the current justified checkpoint from chain store.
func (s *Service) CurrentJustifiedCheckpt() *ethpb.Checkpoint {
cp := s.store.JustifiedCheckpt()
if cp == nil {
return &ethpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
func (s *Service) CurrentJustifiedCheckpt() (*ethpb.Checkpoint, error) {
cp, err := s.store.JustifiedCheckpt()
if err != nil {
return nil, err
}
return ethpb.CopyCheckpoint(cp)
return ethpb.CopyCheckpoint(cp), nil
}
// PreviousJustifiedCheckpt returns the previous justified checkpoint from chain store.
func (s *Service) PreviousJustifiedCheckpt() *ethpb.Checkpoint {
cp := s.store.PrevJustifiedCheckpt()
if cp == nil {
return &ethpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
func (s *Service) PreviousJustifiedCheckpt() (*ethpb.Checkpoint, error) {
cp, err := s.store.PrevJustifiedCheckpt()
if err != nil {
return nil, err
}
return ethpb.CopyCheckpoint(cp)
return ethpb.CopyCheckpoint(cp), nil
}
// BestJustifiedCheckpt returns the best justified checkpoint from store.
func (s *Service) BestJustifiedCheckpt() *ethpb.Checkpoint {
cp := s.store.BestJustifiedCheckpt()
// If there is no best justified checkpoint, return the checkpoint with root as zeros to be used for genesis cases.
if cp == nil {
return &ethpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
func (s *Service) BestJustifiedCheckpt() (*ethpb.Checkpoint, error) {
cp, err := s.store.BestJustifiedCheckpt()
if err != nil {
// If there is no best justified checkpoint, return the checkpoint with root as zeros to be used for genesis cases.
if errors.Is(err, store.ErrNilCheckpoint) {
return &ethpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}, nil
}
return nil, err
}
return ethpb.CopyCheckpoint(cp)
return ethpb.CopyCheckpoint(cp), nil
}
// HeadSlot returns the slot of the head of the chain.

View File

@@ -5,6 +5,7 @@ import (
"testing"
"time"
"github.com/prysmaticlabs/prysm/beacon-chain/blockchain/store"
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"
@@ -26,12 +27,6 @@ var _ ChainInfoFetcher = (*Service)(nil)
var _ TimeFetcher = (*Service)(nil)
var _ ForkFetcher = (*Service)(nil)
func TestFinalizedCheckpt_Nil(t *testing.T) {
beaconDB := testDB.SetupDB(t)
c := setupBeaconChain(t, beaconDB)
assert.DeepEqual(t, params.BeaconConfig().ZeroHash[:], c.FinalizedCheckpt().Root, "Incorrect pre chain start value")
}
func TestHeadRoot_Nil(t *testing.T) {
beaconDB := testDB.SetupDB(t)
c := setupBeaconChain(t, beaconDB)
@@ -53,7 +48,9 @@ func TestFinalizedCheckpt_CanRetrieve(t *testing.T) {
c := setupBeaconChain(t, beaconDB)
c.store.SetFinalizedCheckptAndPayloadHash(cp, [32]byte{'a'})
assert.Equal(t, cp.Epoch, c.FinalizedCheckpt().Epoch, "Unexpected finalized epoch")
cp, err := c.FinalizedCheckpt()
require.NoError(t, err)
assert.Equal(t, cp.Epoch, cp.Epoch, "Unexpected finalized epoch")
}
func TestFinalizedCheckpt_GenesisRootOk(t *testing.T) {
@@ -64,17 +61,22 @@ func TestFinalizedCheckpt_GenesisRootOk(t *testing.T) {
c := setupBeaconChain(t, beaconDB)
c.store.SetFinalizedCheckptAndPayloadHash(cp, [32]byte{'a'})
c.originBlockRoot = genesisRoot
assert.DeepEqual(t, c.originBlockRoot[:], c.FinalizedCheckpt().Root)
cp, err := c.FinalizedCheckpt()
require.NoError(t, err)
assert.DeepEqual(t, c.originBlockRoot[:], cp.Root)
}
func TestCurrentJustifiedCheckpt_CanRetrieve(t *testing.T) {
beaconDB := testDB.SetupDB(t)
c := setupBeaconChain(t, beaconDB)
assert.Equal(t, params.BeaconConfig().ZeroHash, bytesutil.ToBytes32(c.CurrentJustifiedCheckpt().Root), "Unexpected justified epoch")
_, err := c.CurrentJustifiedCheckpt()
require.ErrorIs(t, err, store.ErrNilCheckpoint)
cp := &ethpb.Checkpoint{Epoch: 6, Root: bytesutil.PadTo([]byte("foo"), 32)}
c.store.SetJustifiedCheckptAndPayloadHash(cp, [32]byte{})
assert.Equal(t, cp.Epoch, c.CurrentJustifiedCheckpt().Epoch, "Unexpected justified epoch")
jp, err := c.CurrentJustifiedCheckpt()
require.NoError(t, err)
assert.Equal(t, cp.Epoch, jp.Epoch, "Unexpected justified epoch")
}
func TestJustifiedCheckpt_GenesisRootOk(t *testing.T) {
@@ -85,7 +87,9 @@ func TestJustifiedCheckpt_GenesisRootOk(t *testing.T) {
cp := &ethpb.Checkpoint{Root: genesisRoot[:]}
c.store.SetJustifiedCheckptAndPayloadHash(cp, [32]byte{})
c.originBlockRoot = genesisRoot
assert.DeepEqual(t, c.originBlockRoot[:], c.CurrentJustifiedCheckpt().Root)
cp, err := c.CurrentJustifiedCheckpt()
require.NoError(t, err)
assert.DeepEqual(t, c.originBlockRoot[:], cp.Root)
}
func TestPreviousJustifiedCheckpt_CanRetrieve(t *testing.T) {
@@ -93,9 +97,12 @@ func TestPreviousJustifiedCheckpt_CanRetrieve(t *testing.T) {
cp := &ethpb.Checkpoint{Epoch: 7, Root: bytesutil.PadTo([]byte("foo"), 32)}
c := setupBeaconChain(t, beaconDB)
assert.Equal(t, params.BeaconConfig().ZeroHash, bytesutil.ToBytes32(c.CurrentJustifiedCheckpt().Root), "Unexpected justified epoch")
_, err := c.PreviousJustifiedCheckpt()
require.ErrorIs(t, err, store.ErrNilCheckpoint)
c.store.SetPrevJustifiedCheckpt(cp)
assert.Equal(t, cp.Epoch, c.PreviousJustifiedCheckpt().Epoch, "Unexpected previous justified epoch")
pcp, err := c.PreviousJustifiedCheckpt()
require.NoError(t, err)
assert.Equal(t, cp.Epoch, pcp.Epoch, "Unexpected previous justified epoch")
}
func TestPrevJustifiedCheckpt_GenesisRootOk(t *testing.T) {
@@ -106,7 +113,9 @@ func TestPrevJustifiedCheckpt_GenesisRootOk(t *testing.T) {
c := setupBeaconChain(t, beaconDB)
c.store.SetPrevJustifiedCheckpt(cp)
c.originBlockRoot = genesisRoot
assert.DeepEqual(t, c.originBlockRoot[:], c.PreviousJustifiedCheckpt().Root)
pcp, err := c.PreviousJustifiedCheckpt()
require.NoError(t, err)
assert.DeepEqual(t, c.originBlockRoot[:], pcp.Root)
}
func TestHeadSlot_CanRetrieve(t *testing.T) {
@@ -274,8 +283,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,
params.BeaconConfig().ZeroHash)}}
c := &Service{cfg: &config{ForkChoiceStore: protoarray.New(0, 0)}}
require.NoError(t, c.cfg.ForkChoiceStore.InsertOptimisticBlock(ctx, 100, [32]byte{'a'}, [32]byte{}, params.BeaconConfig().ZeroHash, 0, 0))
require.NoError(t, c.cfg.ForkChoiceStore.InsertOptimisticBlock(ctx, 101, [32]byte{'b'}, [32]byte{'a'}, params.BeaconConfig().ZeroHash, 0, 0))
require.NoError(t, c.cfg.ForkChoiceStore.InsertOptimisticBlock(ctx, 102, [32]byte{'c'}, [32]byte{'b'}, params.BeaconConfig().ZeroHash, 0, 0))
@@ -371,7 +379,7 @@ func TestService_IsOptimistic_ProtoArray(t *testing.T) {
params.OverrideBeaconConfig(cfg)
ctx := context.Background()
c := &Service{cfg: &config{ForkChoiceStore: protoarray.New(0, 0, [32]byte{})}, head: &head{slot: 101, root: [32]byte{'b'}}}
c := &Service{cfg: &config{ForkChoiceStore: protoarray.New(0, 0)}, head: &head{slot: 101, root: [32]byte{'b'}}}
require.NoError(t, c.cfg.ForkChoiceStore.InsertOptimisticBlock(ctx, 100, [32]byte{'a'}, [32]byte{}, params.BeaconConfig().ZeroHash, 0, 0))
require.NoError(t, c.cfg.ForkChoiceStore.InsertOptimisticBlock(ctx, 101, [32]byte{'b'}, [32]byte{'a'}, params.BeaconConfig().ZeroHash, 0, 0))
@@ -406,7 +414,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, [32]byte{})}, head: &head{slot: 101, root: [32]byte{'b'}}}
c := &Service{cfg: &config{ForkChoiceStore: protoarray.New(0, 0)}, head: &head{slot: 101, root: [32]byte{'b'}}}
require.NoError(t, c.cfg.ForkChoiceStore.InsertOptimisticBlock(ctx, 100, [32]byte{'a'}, [32]byte{}, params.BeaconConfig().ZeroHash, 0, 0))
require.NoError(t, c.cfg.ForkChoiceStore.InsertOptimisticBlock(ctx, 101, [32]byte{'b'}, [32]byte{'a'}, params.BeaconConfig().ZeroHash, 0, 0))
@@ -429,7 +437,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, [32]byte{})}, head: &head{slot: 101, root: [32]byte{'b'}}}
c := &Service{cfg: &config{BeaconDB: beaconDB, ForkChoiceStore: protoarray.New(0, 0)}, head: &head{slot: 101, root: [32]byte{'b'}}}
c.head = &head{root: params.BeaconConfig().ZeroHash}
b := util.NewBeaconBlock()
b.Block.Slot = 10

View File

@@ -3,17 +3,60 @@ package blockchain
import "github.com/pkg/errors"
var (
// errNilJustifiedInStore is returned when a nil justified checkpt is returned from store.
errNilJustifiedInStore = errors.New("nil justified checkpoint returned from store")
// errNilBestJustifiedInStore is returned when a nil justified checkpt is returned from store.
errNilBestJustifiedInStore = errors.New("nil best justified checkpoint returned from store")
// ErrInvalidPayload is returned when the payload is invalid
ErrInvalidPayload = errors.New("recevied an INVALID payload from execution engine")
// ErrUndefinedExecutionEngineError is returned when the execution engine returns an error that is not defined
ErrUndefinedExecutionEngineError = errors.New("received an undefined ee error")
// errNilFinalizedInStore is returned when a nil finalized checkpt is returned from store.
errNilFinalizedInStore = errors.New("nil finalized checkpoint returned from store")
// errNilFinalizedCheckpoint is returned when a nil finalized checkpt is returned from a state.
errNilFinalizedCheckpoint = errors.New("nil finalized checkpoint returned from state")
// errNilJustifiedCheckpoint is returned when a nil justified checkpt is returned from a state.
errNilJustifiedCheckpoint = errors.New("nil finalized checkpoint returned from state")
// errInvalidNilSummary is returned when a nil summary is returned from the DB.
errInvalidNilSummary = errors.New("nil summary returned from the DB")
// errWrongBlockCount is returned when the wrong number of blocks or
// block roots is used
// errWrongBlockCount is returned when the wrong number of blocks or block roots is used
errWrongBlockCount = errors.New("wrong number of blocks or block roots")
// block is not a valid optimistic candidate block
errNotOptimisticCandidate = errors.New("block is not suitable for optimistic sync")
// errBlockNotFoundInCacheOrDB is returned when a block is not found in the cache or DB.
errBlockNotFoundInCacheOrDB = errors.New("block not found in cache or db")
// errNilStateFromStategen is returned when a nil state is returned from the state generator.
errNilStateFromStategen = errors.New("justified state can't be nil")
// errWSBlockNotFound is returned when a block is not found in the WS cache or DB.
errWSBlockNotFound = errors.New("weak subjectivity root not found in db")
// errWSBlockNotFoundInEpoch is returned when a block is not found in the WS cache or DB within epoch.
errWSBlockNotFoundInEpoch = errors.New("weak subjectivity root not found in db within epoch")
)
// An invalid block is the block that fails state transition based on the core protocol rules.
// The beacon node shall not be accepting nor building blocks that branch off from an invalid block.
// Some examples of invalid blocks are:
// The block violates state transition rules.
// The block is deemed invalid according to execution layer client.
// The block violates certain fork choice rules (before finalized slot, not finalized ancestor)
type invalidBlock struct {
error
}
type invalidBlockError interface {
Error() string
InvalidBlock() bool
}
// InvalidBlock returns true for `invalidBlock`.
func (e invalidBlock) InvalidBlock() bool {
return true
}
// IsInvalidBlock returns true if the error has `invalidBlock`.
func IsInvalidBlock(e error) bool {
if e == nil {
return false
}
d, ok := e.(invalidBlockError)
if !ok {
return IsInvalidBlock(errors.Unwrap(e))
}
return d.InvalidBlock()
}

View File

@@ -0,0 +1,17 @@
package blockchain
import (
"testing"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/testing/require"
)
func TestIsInvalidBlock(t *testing.T) {
require.Equal(t, false, IsInvalidBlock(ErrInvalidPayload))
err := invalidBlock{ErrInvalidPayload}
require.Equal(t, true, IsInvalidBlock(err))
newErr := errors.Wrap(err, "wrap me")
require.Equal(t, true, IsInvalidBlock(newErr))
}

View File

@@ -16,6 +16,7 @@ import (
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
@@ -24,11 +25,6 @@ import (
"go.opencensus.io/trace"
)
var (
ErrInvalidPayload = errors.New("recevied an INVALID payload from execution engine")
ErrUndefinedExecutionEngineError = errors.New("received an undefined ee error")
)
// notifyForkchoiceUpdateArg is the argument for the forkchoice update notification `notifyForkchoiceUpdate`.
type notifyForkchoiceUpdateArg struct {
headState state.BeaconState
@@ -168,20 +164,20 @@ func (s *Service) notifyNewPayload(ctx context.Context, postStateVersion int,
if blocks.IsPreBellatrixVersion(postStateVersion) {
return true, nil
}
if err := helpers.BeaconBlockIsNil(blk); err != nil {
if err := wrapper.BeaconBlockIsNil(blk); err != nil {
return false, err
}
body := blk.Block().Body()
enabled, err := blocks.IsExecutionEnabledUsingHeader(postStateHeader, body)
if err != nil {
return false, errors.Wrap(err, "could not determine if execution is enabled")
return false, errors.Wrap(invalidBlock{err}, "could not determine if execution is enabled")
}
if !enabled {
return true, nil
}
payload, err := body.ExecutionPayload()
if err != nil {
return false, errors.Wrap(err, "could not get execution payload")
return false, errors.Wrap(invalidBlock{err}, "could not get execution payload")
}
lastValidHash, err := s.cfg.ExecutionEngineCaller.NewPayload(ctx, payload)
switch err {
@@ -213,7 +209,7 @@ func (s *Service) notifyNewPayload(ctx context.Context, postStateVersion int,
"blockRoot": fmt.Sprintf("%#x", root),
"invalidCount": len(invalidRoots),
}).Warn("Pruned invalid blocks")
return false, ErrInvalidPayload
return false, invalidBlock{ErrInvalidPayload}
default:
return false, errors.WithMessage(ErrUndefinedExecutionEngineError, err.Error())
}

View File

@@ -43,7 +43,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, [32]byte{'a'})
fcs := protoarray.New(0, 0)
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -305,7 +305,7 @@ 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, 0, bra, []uint64{50, 100, 200}, 0)
headRoot, err := fcs.Head(ctx, bra, []uint64{50, 100, 200})
require.NoError(t, err)
require.Equal(t, brg, headRoot)
@@ -326,7 +326,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, 0, bra, service.justifiedBalances.balances, 0)
headRoot, err = fcs.Head(ctx, bra, service.justifiedBalances.balances)
require.NoError(t, err)
require.Equal(t, brd, headRoot)
@@ -343,7 +343,7 @@ func Test_NotifyNewPayload(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0, [32]byte{'a'})
fcs := protoarray.New(0, 0)
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -387,12 +387,13 @@ func Test_NotifyNewPayload(t *testing.T) {
require.NoError(t, fcs.InsertOptimisticBlock(ctx, 1, r, [32]byte{}, params.BeaconConfig().ZeroHash, 0, 0))
tests := []struct {
name string
postState state.BeaconState
invalidBlock bool
isValidPayload bool
blk interfaces.SignedBeaconBlock
newPayloadErr error
errString string
name string
}{
{
name: "phase 0 post state",
@@ -424,6 +425,7 @@ func Test_NotifyNewPayload(t *testing.T) {
newPayloadErr: powchain.ErrInvalidPayloadStatus,
errString: ErrInvalidPayload.Error(),
isValidPayload: false,
invalidBlock: true,
},
{
name: "altair pre state, altair block",
@@ -535,9 +537,13 @@ func Test_NotifyNewPayload(t *testing.T) {
isValidPayload, err := service.notifyNewPayload(ctx, postVersion, postHeader, tt.blk)
if tt.errString != "" {
require.ErrorContains(t, tt.errString, err)
if tt.invalidBlock {
require.Equal(t, true, IsInvalidBlock(err))
}
} else {
require.NoError(t, err)
require.Equal(t, tt.isValidPayload, isValidPayload)
require.Equal(t, false, IsInvalidBlock(err))
}
})
}
@@ -549,7 +555,7 @@ func Test_NotifyNewPayload_SetOptimisticToValid(t *testing.T) {
params.OverrideBeaconConfig(cfg)
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0, [32]byte{'a'})
fcs := protoarray.New(0, 0)
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -592,7 +598,7 @@ func Test_IsOptimisticCandidateBlock(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0, [32]byte{'a'})
fcs := protoarray.New(0, 0)
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -690,7 +696,11 @@ func Test_IsOptimisticCandidateBlock(t *testing.T) {
require.NoError(t, service.cfg.BeaconDB.SaveBlock(ctx, wrappedParentBlock))
err = service.optimisticCandidateBlock(ctx, tt.blk)
require.Equal(t, tt.err, err)
if tt.err != nil {
require.Equal(t, tt.err.Error(), err.Error())
} else {
require.NoError(t, err)
}
}
}
@@ -790,7 +800,7 @@ func Test_UpdateLastValidatedCheckpoint(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
stateGen := stategen.New(beaconDB)
fcs := protoarray.New(0, 0, [32]byte{})
fcs := protoarray.New(0, 0)
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stateGen),
@@ -887,7 +897,7 @@ func TestService_removeInvalidBlockAndState(t *testing.T) {
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
WithForkChoiceStore(protoarray.New(0, 0, [32]byte{})),
WithForkChoiceStore(protoarray.New(0, 0)),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
@@ -943,7 +953,7 @@ func TestService_getPayloadHash(t *testing.T) {
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
WithForkChoiceStore(protoarray.New(0, 0, [32]byte{})),
WithForkChoiceStore(protoarray.New(0, 0)),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)

View File

@@ -17,6 +17,7 @@ import (
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
ethpbv1 "github.com/prysmaticlabs/prysm/proto/eth/v1"
"github.com/prysmaticlabs/prysm/time/slots"
@@ -27,13 +28,14 @@ import (
// UpdateAndSaveHeadWithBalances updates the beacon state head after getting justified balanced from cache.
// This function is only used in spec-tests, it does save the head after updating it.
func (s *Service) UpdateAndSaveHeadWithBalances(ctx context.Context) error {
cp := s.store.JustifiedCheckpt()
if cp == nil {
return errors.New("no justified checkpoint")
}
balances, err := s.justifiedBalances.get(ctx, bytesutil.ToBytes32(cp.Root))
jp, err := s.store.JustifiedCheckpt()
if err != nil {
msg := fmt.Sprintf("could not read balances for state w/ justified checkpoint %#x", cp.Root)
return err
}
balances, err := s.justifiedBalances.get(ctx, bytesutil.ToBytes32(jp.Root))
if err != nil {
msg := fmt.Sprintf("could not read balances for state w/ justified checkpoint %#x", jp.Root)
return errors.Wrap(err, msg)
}
headRoot, err := s.updateHead(ctx, balances)
@@ -66,13 +68,13 @@ func (s *Service) updateHead(ctx context.Context, balances []uint64) ([32]byte,
defer span.End()
// Get head from the fork choice service.
f := s.store.FinalizedCheckpt()
if f == nil {
return [32]byte{}, errNilFinalizedInStore
f, err := s.store.FinalizedCheckpt()
if err != nil {
return [32]byte{}, errors.Wrap(err, "could not get finalized checkpoint")
}
j := s.store.JustifiedCheckpt()
if j == nil {
return [32]byte{}, errNilJustifiedInStore
j, err := s.store.JustifiedCheckpt()
if err != nil {
return [32]byte{}, errors.Wrap(err, "could not get justified checkpoint")
}
// To get head before the first justified epoch, the fork choice will start with origin root
// instead of zero hashes.
@@ -93,14 +95,14 @@ func (s *Service) updateHead(ctx context.Context, balances []uint64) ([32]byte,
if features.Get().EnableForkChoiceDoublyLinkedTree {
s.cfg.ForkChoiceStore = doublylinkedtree.New(j.Epoch, f.Epoch)
} else {
s.cfg.ForkChoiceStore = protoarray.New(j.Epoch, f.Epoch, bytesutil.ToBytes32(f.Root))
s.cfg.ForkChoiceStore = protoarray.New(j.Epoch, f.Epoch)
}
if err := s.insertBlockToForkChoiceStore(ctx, jb.Block(), headStartRoot, f, j); err != nil {
return [32]byte{}, err
}
}
return s.cfg.ForkChoiceStore.Head(ctx, j.Epoch, headStartRoot, balances, f.Epoch)
return s.cfg.ForkChoiceStore.Head(ctx, headStartRoot, balances)
}
// This saves head info to the local service cache, it also saves the
@@ -117,7 +119,7 @@ func (s *Service) saveHead(ctx context.Context, headRoot [32]byte, headBlock int
if headRoot == bytesutil.ToBytes32(r) {
return nil
}
if err := helpers.BeaconBlockIsNil(headBlock); err != nil {
if err := wrapper.BeaconBlockIsNil(headBlock); err != nil {
return err
}
if headState == nil || headState.IsNil() {
@@ -190,7 +192,7 @@ func (s *Service) saveHead(ctx context.Context, headRoot [32]byte, headBlock int
// root in DB. With the inception of initial-sync-cache-state flag, it uses finalized
// check point as anchors to resume sync therefore head is no longer needed to be saved on per slot basis.
func (s *Service) saveHeadNoDB(ctx context.Context, b interfaces.SignedBeaconBlock, r [32]byte, hs state.BeaconState) error {
if err := helpers.BeaconBlockIsNil(b); err != nil {
if err := wrapper.BeaconBlockIsNil(b); err != nil {
return err
}
cachedHeadRoot, err := s.HeadRoot(ctx)

View File

@@ -4,12 +4,10 @@ import (
"context"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
)
var errBlockNotFoundInCacheOrDB = errors.New("block not found in cache or db")
// This saves a beacon block to the initial sync blocks cache.
func (s *Service) saveInitSyncBlock(r [32]byte, b interfaces.SignedBeaconBlock) {
s.initSyncBlocksLock.Lock()
@@ -49,7 +47,7 @@ func (s *Service) getBlock(ctx context.Context, r [32]byte) (interfaces.SignedBe
return nil, errors.Wrap(err, "could not retrieve block from db")
}
}
if err := helpers.BeaconBlockIsNil(b); err != nil {
if err := wrapper.BeaconBlockIsNil(b); err != nil {
return nil, errBlockNotFoundInCacheOrDB
}
return b, nil

View File

@@ -54,25 +54,33 @@ func logStateTransitionData(b interfaces.BeaconBlock) error {
return nil
}
func logBlockSyncStatus(block interfaces.BeaconBlock, blockRoot [32]byte, finalized *ethpb.Checkpoint, receivedTime time.Time, genesisTime uint64) error {
func logBlockSyncStatus(block interfaces.BeaconBlock, blockRoot [32]byte, justified, finalized *ethpb.Checkpoint, receivedTime time.Time, genesisTime uint64) error {
startTime, err := slots.ToTime(genesisTime, block.Slot())
if err != nil {
return err
}
log.WithFields(logrus.Fields{
"slot": block.Slot(),
"slotInEpoch": block.Slot() % params.BeaconConfig().SlotsPerEpoch,
"block": fmt.Sprintf("0x%s...", hex.EncodeToString(blockRoot[:])[:8]),
"epoch": slots.ToEpoch(block.Slot()),
"finalizedEpoch": finalized.Epoch,
"finalizedRoot": fmt.Sprintf("0x%s...", hex.EncodeToString(finalized.Root)[:8]),
"parentRoot": fmt.Sprintf("0x%s...", hex.EncodeToString(block.ParentRoot())[:8]),
"version": version.String(block.Version()),
}).Info("Synced new block")
log.WithFields(logrus.Fields{
"slot": block.Slot,
"sinceSlotStartTime": prysmTime.Now().Sub(startTime),
"chainServiceProcessedTime": prysmTime.Now().Sub(receivedTime),
}).Debug("Sync new block times")
level := log.Logger.GetLevel()
if level >= logrus.DebugLevel {
log.WithFields(logrus.Fields{
"slot": block.Slot(),
"slotInEpoch": block.Slot() % params.BeaconConfig().SlotsPerEpoch,
"block": fmt.Sprintf("0x%s...", hex.EncodeToString(blockRoot[:])[:8]),
"epoch": slots.ToEpoch(block.Slot()),
"justifiedEpoch": justified.Epoch,
"justifiedRoot": fmt.Sprintf("0x%s...", hex.EncodeToString(justified.Root)[:8]),
"finalizedEpoch": finalized.Epoch,
"finalizedRoot": fmt.Sprintf("0x%s...", hex.EncodeToString(finalized.Root)[:8]),
"parentRoot": fmt.Sprintf("0x%s...", hex.EncodeToString(block.ParentRoot())[:8]),
"version": version.String(block.Version()),
"sinceSlotStartTime": prysmTime.Now().Sub(startTime),
"chainServiceProcessedTime": prysmTime.Now().Sub(receivedTime),
}).Debug("Synced new block")
} else {
log.WithFields(logrus.Fields{
"slot": block.Slot(),
"block": fmt.Sprintf("0x%s...", hex.EncodeToString(blockRoot[:])[:8]),
"epoch": slots.ToEpoch(block.Slot()),
}).Info("Synced new block")
}
return nil
}

View File

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

View File

@@ -30,7 +30,6 @@ import (
// if ancestor_at_finalized_slot == store.finalized_checkpoint.root:
// store.justified_checkpoint = store.best_justified_checkpoint
func (s *Service) NewSlot(ctx context.Context, slot types.Slot) error {
// Reset proposer boost root in fork choice.
if err := s.cfg.ForkChoiceStore.ResetBoostedProposerRoot(ctx); err != nil {
return errors.Wrap(err, "could not reset boosted proposer root in fork choice")
@@ -42,17 +41,17 @@ func (s *Service) NewSlot(ctx context.Context, slot types.Slot) error {
}
// Update store.justified_checkpoint if a better checkpoint on the store.finalized_checkpoint chain
bj := s.store.BestJustifiedCheckpt()
if bj == nil {
return errNilBestJustifiedInStore
bj, err := s.store.BestJustifiedCheckpt()
if err != nil {
return errors.Wrap(err, "could not get best justified checkpoint")
}
j := s.store.JustifiedCheckpt()
if j == nil {
return errNilJustifiedInStore
j, err := s.store.JustifiedCheckpt()
if err != nil {
return errors.Wrap(err, "could not get justified checkpoint")
}
f := s.store.FinalizedCheckpt()
if f == nil {
return errNilFinalizedInStore
f, err := s.store.FinalizedCheckpt()
if err != nil {
return errors.Wrap(err, "could not get finalized checkpoint")
}
if bj.Epoch > j.Epoch {
finalizedSlot, err := slots.EpochStart(f.Epoch)
@@ -69,6 +68,9 @@ 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 {
return err
}
}
}
return nil

View File

@@ -5,19 +5,22 @@ import (
"testing"
"github.com/prysmaticlabs/prysm/beacon-chain/blockchain/store"
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
"github.com/prysmaticlabs/prysm/config/params"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/testing/assert"
"github.com/prysmaticlabs/prysm/testing/require"
)
func TestService_newSlot(t *testing.T) {
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0, [32]byte{})
fcs := protoarray.New(0, 0)
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -25,10 +28,18 @@ func TestService_newSlot(t *testing.T) {
}
ctx := context.Background()
genesisStateRoot := [32]byte{}
genesis := blocks.NewGenesisBlock(genesisStateRoot[:])
wsb, err := wrapper.WrappedSignedBeaconBlock(genesis)
require.NoError(t, err)
assert.NoError(t, beaconDB.SaveBlock(ctx, wsb))
bj, err := genesis.Block.HashTreeRoot()
require.NoError(t, err)
require.NoError(t, fcs.InsertOptimisticBlock(ctx, 0, [32]byte{}, [32]byte{}, [32]byte{}, 0, 0)) // genesis
require.NoError(t, fcs.InsertOptimisticBlock(ctx, 32, [32]byte{'a'}, [32]byte{}, [32]byte{}, 0, 0)) // finalized
require.NoError(t, fcs.InsertOptimisticBlock(ctx, 64, [32]byte{'b'}, [32]byte{'a'}, [32]byte{}, 0, 0)) // justified
require.NoError(t, fcs.InsertOptimisticBlock(ctx, 96, [32]byte{'c'}, [32]byte{'a'}, [32]byte{}, 0, 0)) // best justified
require.NoError(t, fcs.InsertOptimisticBlock(ctx, 96, bj, [32]byte{'a'}, [32]byte{}, 0, 0)) // best justified
require.NoError(t, fcs.InsertOptimisticBlock(ctx, 97, [32]byte{'d'}, [32]byte{}, [32]byte{}, 0, 0)) // bad
type args struct {
@@ -48,7 +59,7 @@ func TestService_newSlot(t *testing.T) {
slot: params.BeaconConfig().SlotsPerEpoch + 1,
finalized: &ethpb.Checkpoint{Epoch: 1, Root: bytesutil.PadTo([]byte{'a'}, 32)},
justified: &ethpb.Checkpoint{Epoch: 2, Root: bytesutil.PadTo([]byte{'b'}, 32)},
bestJustified: &ethpb.Checkpoint{Epoch: 3, Root: bytesutil.PadTo([]byte{'c'}, 32)},
bestJustified: &ethpb.Checkpoint{Epoch: 3, Root: bj[:]},
shouldEqual: false,
},
},
@@ -58,7 +69,7 @@ func TestService_newSlot(t *testing.T) {
slot: params.BeaconConfig().SlotsPerEpoch,
finalized: &ethpb.Checkpoint{Epoch: 1, Root: bytesutil.PadTo([]byte{'a'}, 32)},
justified: &ethpb.Checkpoint{Epoch: 3, Root: bytesutil.PadTo([]byte{'b'}, 32)},
bestJustified: &ethpb.Checkpoint{Epoch: 2, Root: bytesutil.PadTo([]byte{'c'}, 32)},
bestJustified: &ethpb.Checkpoint{Epoch: 2, Root: bj[:]},
shouldEqual: false,
},
},
@@ -78,7 +89,7 @@ func TestService_newSlot(t *testing.T) {
slot: params.BeaconConfig().SlotsPerEpoch,
finalized: &ethpb.Checkpoint{Epoch: 1, Root: bytesutil.PadTo([]byte{'a'}, 32)},
justified: &ethpb.Checkpoint{Epoch: 2, Root: bytesutil.PadTo([]byte{'b'}, 32)},
bestJustified: &ethpb.Checkpoint{Epoch: 3, Root: bytesutil.PadTo([]byte{'c'}, 32)},
bestJustified: &ethpb.Checkpoint{Epoch: 3, Root: bj[:]},
shouldEqual: true,
},
},
@@ -92,9 +103,17 @@ func TestService_newSlot(t *testing.T) {
require.NoError(t, service.NewSlot(ctx, test.args.slot))
if test.args.shouldEqual {
require.DeepSSZEqual(t, service.store.BestJustifiedCheckpt(), service.store.JustifiedCheckpt())
bcp, err := service.store.BestJustifiedCheckpt()
require.NoError(t, err)
cp, err := service.store.JustifiedCheckpt()
require.NoError(t, err)
require.DeepSSZEqual(t, bcp, cp)
} else {
require.DeepNotSSZEqual(t, service.store.BestJustifiedCheckpt(), service.store.JustifiedCheckpt())
bcp, err := service.store.BestJustifiedCheckpt()
require.NoError(t, err)
cp, err := service.store.JustifiedCheckpt()
require.NoError(t, err)
require.DeepNotSSZEqual(t, bcp, cp)
}
}
}

View File

@@ -10,10 +10,10 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/holiman/uint256"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
"github.com/prysmaticlabs/prysm/time/slots"
@@ -38,7 +38,7 @@ import (
// # Check if `pow_block` is a valid terminal PoW block
// assert is_valid_terminal_pow_block(pow_block, pow_parent)
func (s *Service) validateMergeBlock(ctx context.Context, b interfaces.SignedBeaconBlock) error {
if err := helpers.BeaconBlockIsNil(b); err != nil {
if err := wrapper.BeaconBlockIsNil(b); err != nil {
return err
}
payload, err := b.Block().Body().ExecutionPayload()
@@ -64,8 +64,9 @@ func (s *Service) validateMergeBlock(ctx context.Context, b interfaces.SignedBea
return err
}
if !valid {
return fmt.Errorf("invalid TTD, configTTD: %s, currentTTD: %s, parentTTD: %s",
err := fmt.Errorf("invalid TTD, configTTD: %s, currentTTD: %s, parentTTD: %s",
params.BeaconConfig().TerminalTotalDifficulty, mergeBlockTD, mergeBlockParentTD)
return invalidBlock{err}
}
log.WithFields(logrus.Fields{

View File

@@ -109,7 +109,7 @@ func Test_validateMergeBlock(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0, [32]byte{'a'})
fcs := protoarray.New(0, 0)
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -144,13 +144,15 @@ func Test_validateMergeBlock(t *testing.T) {
cfg.TerminalTotalDifficulty = "1"
params.OverrideBeaconConfig(cfg)
require.ErrorContains(t, "invalid TTD, configTTD: 1, currentTTD: 2, parentTTD: 1", service.validateMergeBlock(ctx, b))
err = service.validateMergeBlock(ctx, b)
require.ErrorContains(t, "invalid TTD, configTTD: 1, currentTTD: 2, parentTTD: 1", err)
require.Equal(t, true, IsInvalidBlock(err))
}
func Test_getBlkParentHashAndTD(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0, [32]byte{'a'})
fcs := protoarray.New(0, 0)
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),

View File

@@ -7,11 +7,11 @@ import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/async"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/core/transition"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/config/params"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/time/slots"
@@ -80,7 +80,7 @@ func (s *Service) verifyBeaconBlock(ctx context.Context, data *ethpb.Attestation
if err != nil {
return err
}
if err := helpers.BeaconBlockIsNil(b); err != nil {
if err := wrapper.BeaconBlockIsNil(b); err != nil {
return err
}
if b.Block().Slot() > data.Slot {

View File

@@ -28,7 +28,7 @@ func TestStore_OnAttestation_ErrorConditions_ProtoArray(t *testing.T) {
opts := []Option{
WithDatabase(beaconDB),
WithForkChoiceStore(protoarray.New(0, 0, [32]byte{})),
WithForkChoiceStore(protoarray.New(0, 0)),
WithStateGen(stategen.New(beaconDB)),
}
service, err := NewService(ctx, opts...)
@@ -250,7 +250,7 @@ func TestStore_OnAttestation_Ok_ProtoArray(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0, [32]byte{'a'})
fcs := protoarray.New(0, 0)
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -483,7 +483,7 @@ func TestVerifyFinalizedConsistency_InconsistentRoot_ProtoArray(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0, [32]byte{'a'})
fcs := protoarray.New(0, 0)
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -602,7 +602,7 @@ func TestVerifyFinalizedConsistency_IsCanonical(t *testing.T) {
require.NoError(t, service.cfg.ForkChoiceStore.InsertOptimisticBlock(ctx, b32.Block.Slot, r32, [32]byte{}, params.BeaconConfig().ZeroHash, 0, 0))
require.NoError(t, service.cfg.ForkChoiceStore.InsertOptimisticBlock(ctx, b33.Block.Slot, r33, r32, params.BeaconConfig().ZeroHash, 0, 0))
_, err = service.cfg.ForkChoiceStore.Head(ctx, 0, r32, []uint64{}, 0)
_, err = service.cfg.ForkChoiceStore.Head(ctx, r32, []uint64{})
require.NoError(t, err)
err = service.VerifyFinalizedConsistency(context.Background(), r33[:])
require.NoError(t, err)

View File

@@ -18,6 +18,7 @@ import (
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
"github.com/prysmaticlabs/prysm/crypto/bls"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/monitoring/tracing"
@@ -92,8 +93,8 @@ var initialSyncBlockCacheSize = uint64(2 * params.BeaconConfig().SlotsPerEpoch)
func (s *Service) onBlock(ctx context.Context, signed interfaces.SignedBeaconBlock, blockRoot [32]byte) error {
ctx, span := trace.StartSpan(ctx, "blockChain.onBlock")
defer span.End()
if err := helpers.BeaconBlockIsNil(signed); err != nil {
return err
if err := wrapper.BeaconBlockIsNil(signed); err != nil {
return invalidBlock{err}
}
b := signed.Block()
@@ -108,7 +109,7 @@ func (s *Service) onBlock(ctx context.Context, signed interfaces.SignedBeaconBlo
}
postState, err := transition.ExecuteStateTransition(ctx, preState, signed)
if err != nil {
return err
return invalidBlock{err}
}
postStateVersion, postStateHeader, err := getStateVersionAndPayload(postState)
if err != nil {
@@ -176,37 +177,55 @@ func (s *Service) onBlock(ctx context.Context, signed interfaces.SignedBeaconBlo
}
// Update justified check point.
justified := s.store.JustifiedCheckpt()
if justified == nil {
return errNilJustifiedInStore
justified, err := s.store.JustifiedCheckpt()
if err != nil {
return errors.Wrap(err, "could not get justified checkpoint")
}
currJustifiedEpoch := justified.Epoch
if postState.CurrentJustifiedCheckpoint().Epoch > currJustifiedEpoch {
psj := postState.CurrentJustifiedCheckpoint()
if psj == nil {
return errNilJustifiedCheckpoint
}
if psj.Epoch > currJustifiedEpoch {
if err := s.updateJustified(ctx, postState); err != nil {
return err
}
}
finalized := s.store.FinalizedCheckpt()
finalized, err := s.store.FinalizedCheckpt()
if err != nil {
return errors.Wrap(err, "could not get finalized checkpoint")
}
if finalized == nil {
return errNilFinalizedInStore
}
newFinalized := postState.FinalizedCheckpointEpoch() > finalized.Epoch
psf := postState.FinalizedCheckpoint()
if psf == nil {
return errNilFinalizedCheckpoint
}
newFinalized := psf.Epoch > finalized.Epoch
if newFinalized {
s.store.SetPrevFinalizedCheckpt(finalized)
cp := postState.FinalizedCheckpoint()
h, err := s.getPayloadHash(ctx, cp.Root)
h, err := s.getPayloadHash(ctx, psf.Root)
if err != nil {
return err
}
s.store.SetFinalizedCheckptAndPayloadHash(cp, h)
s.store.SetFinalizedCheckptAndPayloadHash(psf, h)
s.store.SetPrevJustifiedCheckpt(justified)
cp = postState.CurrentJustifiedCheckpoint()
h, err = s.getPayloadHash(ctx, cp.Root)
h, err = s.getPayloadHash(ctx, psj.Root)
if err != nil {
return err
}
s.store.SetJustifiedCheckptAndPayloadHash(postState.CurrentJustifiedCheckpoint(), h)
// Update Forkchoice checkpoints
if err := s.cfg.ForkChoiceStore.UpdateJustifiedCheckpoint(psj); err != nil {
return err
}
if err := s.cfg.ForkChoiceStore.UpdateFinalizedCheckpoint(psf); err != nil {
return err
}
}
balances, err := s.justifiedBalances.get(ctx, bytesutil.ToBytes32(justified.Root))
@@ -327,8 +346,8 @@ func (s *Service) onBlockBatch(ctx context.Context, blks []interfaces.SignedBeac
return nil, nil, errWrongBlockCount
}
if err := helpers.BeaconBlockIsNil(blks[0]); err != nil {
return nil, nil, err
if err := wrapper.BeaconBlockIsNil(blks[0]); err != nil {
return nil, nil, invalidBlock{err}
}
b := blks[0].Block()
@@ -371,7 +390,7 @@ func (s *Service) onBlockBatch(ctx context.Context, blks []interfaces.SignedBeac
set, preState, err = transition.ExecuteStateTransitionNoVerifyAnySig(ctx, preState, b)
if err != nil {
return nil, nil, err
return nil, nil, invalidBlock{err}
}
// Save potential boundary states.
if slots.IsEpochStart(preState.Slot()) {
@@ -392,7 +411,7 @@ func (s *Service) onBlockBatch(ctx context.Context, blks []interfaces.SignedBeac
}
verify, err := sigSet.Verify()
if err != nil {
return nil, nil, err
return nil, nil, invalidBlock{err}
}
if !verify {
return nil, nil, errors.New("batch block signature verification failed")
@@ -473,9 +492,9 @@ func (s *Service) handleBlockAfterBatchVerify(ctx context.Context, signed interf
s.clearInitSyncBlocks()
}
justified := s.store.JustifiedCheckpt()
if justified == nil {
return errNilJustifiedInStore
justified, err := s.store.JustifiedCheckpt()
if err != nil {
return errors.Wrap(err, "could not get justified checkpoint")
}
if jCheckpoint.Epoch > justified.Epoch {
if err := s.updateJustifiedInitSync(ctx, jCheckpoint); err != nil {
@@ -483,7 +502,10 @@ func (s *Service) handleBlockAfterBatchVerify(ctx context.Context, signed interf
}
}
finalized := s.store.FinalizedCheckpt()
finalized, err := s.store.FinalizedCheckpt()
if err != nil {
return errors.Wrap(err, "could not get finalized checkpoint")
}
if finalized == nil {
return errNilFinalizedInStore
}
@@ -664,7 +686,7 @@ func (s *Service) validateMergeTransitionBlock(ctx context.Context, stateVersion
// Skip validation if block has an empty payload.
payload, err := blk.Block().Body().ExecutionPayload()
if err != nil {
return err
return invalidBlock{err}
}
if blocks.IsEmptyPayload(payload) {
return nil

View File

@@ -92,9 +92,9 @@ func (s *Service) verifyBlkPreState(ctx context.Context, b interfaces.BeaconBloc
func (s *Service) VerifyFinalizedBlkDescendant(ctx context.Context, root [32]byte) error {
ctx, span := trace.StartSpan(ctx, "blockChain.VerifyFinalizedBlkDescendant")
defer span.End()
finalized := s.store.FinalizedCheckpt()
if finalized == nil {
return errNilFinalizedInStore
finalized, err := s.store.FinalizedCheckpt()
if err != nil {
return errors.Wrap(err, "could not get finalized checkpoint")
}
fRoot := s.ensureRootNotZeros(bytesutil.ToBytes32(finalized.Root))
finalizedBlkSigned, err := s.getBlock(ctx, fRoot)
@@ -115,7 +115,7 @@ func (s *Service) VerifyFinalizedBlkDescendant(ctx context.Context, root [32]byt
bytesutil.Trunc(root[:]), finalizedBlk.Slot(), bytesutil.Trunc(bFinalizedRoot),
bytesutil.Trunc(fRoot[:]))
tracing.AnnotateError(span, err)
return err
return invalidBlock{err}
}
return nil
}
@@ -123,16 +123,17 @@ func (s *Service) VerifyFinalizedBlkDescendant(ctx context.Context, root [32]byt
// verifyBlkFinalizedSlot validates input block is not less than or equal
// to current finalized slot.
func (s *Service) verifyBlkFinalizedSlot(b interfaces.BeaconBlock) error {
finalized := s.store.FinalizedCheckpt()
if finalized == nil {
return errNilFinalizedInStore
finalized, err := s.store.FinalizedCheckpt()
if err != nil {
return errors.Wrap(err, "could not get finalized checkpoint")
}
finalizedSlot, err := slots.EpochStart(finalized.Epoch)
if err != nil {
return err
}
if finalizedSlot >= b.Slot() {
return fmt.Errorf("block is equal or earlier than finalized block, slot %d < slot %d", b.Slot(), finalizedSlot)
err = fmt.Errorf("block is equal or earlier than finalized block, slot %d < slot %d", b.Slot(), finalizedSlot)
return invalidBlock{err}
}
return nil
}
@@ -165,7 +166,10 @@ func (s *Service) shouldUpdateCurrentJustified(ctx context.Context, newJustified
if slots.SinceEpochStarts(s.CurrentSlot()) < params.BeaconConfig().SafeSlotsToUpdateJustified {
return true, nil
}
justified := s.store.JustifiedCheckpt()
justified, err := s.store.JustifiedCheckpt()
if err != nil {
return false, errors.Wrap(err, "could not get justified checkpoint")
}
jSlot, err := slots.EpochStart(justified.Epoch)
if err != nil {
return false, err
@@ -187,9 +191,9 @@ func (s *Service) updateJustified(ctx context.Context, state state.ReadOnlyBeaco
defer span.End()
cpt := state.CurrentJustifiedCheckpoint()
bestJustified := s.store.BestJustifiedCheckpt()
if bestJustified == nil {
return errNilBestJustifiedInStore
bestJustified, err := s.store.BestJustifiedCheckpt()
if err != nil {
return errors.Wrap(err, "could not get best justified checkpoint")
}
if cpt.Epoch > bestJustified.Epoch {
s.store.SetBestJustifiedCheckpt(cpt)
@@ -200,9 +204,9 @@ func (s *Service) updateJustified(ctx context.Context, state state.ReadOnlyBeaco
}
if canUpdate {
justified := s.store.JustifiedCheckpt()
if justified == nil {
return errNilJustifiedInStore
justified, err := s.store.JustifiedCheckpt()
if err != nil {
return errors.Wrap(err, "could not get justified checkpoint")
}
s.store.SetPrevJustifiedCheckpt(justified)
h, err := s.getPayloadHash(ctx, cpt.Root)
@@ -210,6 +214,10 @@ func (s *Service) updateJustified(ctx context.Context, state state.ReadOnlyBeaco
return err
}
s.store.SetJustifiedCheckptAndPayloadHash(cpt, h)
// Update forkchoice's justified checkpoint
if err := s.cfg.ForkChoiceStore.UpdateJustifiedCheckpoint(cpt); err != nil {
return err
}
}
return nil
@@ -219,9 +227,9 @@ func (s *Service) updateJustified(ctx context.Context, state state.ReadOnlyBeaco
// caches justified checkpoint balances for fork choice and save justified checkpoint in DB.
// This method does not have defense against fork choice bouncing attack, which is why it's only recommend to be used during initial syncing.
func (s *Service) updateJustifiedInitSync(ctx context.Context, cp *ethpb.Checkpoint) error {
justified := s.store.JustifiedCheckpt()
if justified == nil {
return errNilJustifiedInStore
justified, err := s.store.JustifiedCheckpt()
if err != nil {
return errors.Wrap(err, "could not get justified checkpoint")
}
s.store.SetPrevJustifiedCheckpt(justified)
@@ -344,9 +352,9 @@ func (s *Service) fillInForkChoiceMissingBlocks(ctx context.Context, blk interfa
parentRoot := bytesutil.ToBytes32(blk.ParentRoot())
slot := blk.Slot()
// Fork choice only matters from last finalized slot.
finalized := s.store.FinalizedCheckpt()
if finalized == nil {
return errNilFinalizedInStore
finalized, err := s.store.FinalizedCheckpt()
if err != nil {
return err
}
fSlot, err := slots.EpochStart(finalized.Epoch)
if err != nil {

View File

@@ -47,7 +47,7 @@ func TestStore_OnBlock_ProtoArray(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0, [32]byte{'a'})
fcs := protoarray.New(0, 0)
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -268,8 +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, 0,
params.BeaconConfig().ZeroHash, []uint64{}, 0)
_, err = service.cfg.ForkChoiceStore.Head(ctx, params.BeaconConfig().ZeroHash, []uint64{})
require.ErrorContains(t, "could not apply proposer boost score: invalid proposer boost root", err)
}
@@ -294,7 +293,7 @@ func TestStore_OnBlockBatch_ProtoArray(t *testing.T) {
service.store.SetFinalizedCheckptAndPayloadHash(&ethpb.Checkpoint{Root: gRoot[:]}, [32]byte{'a'})
service.store.SetJustifiedCheckptAndPayloadHash(&ethpb.Checkpoint{Root: gRoot[:]}, [32]byte{'b'})
service.cfg.ForkChoiceStore = protoarray.New(0, 0, [32]byte{})
service.cfg.ForkChoiceStore = protoarray.New(0, 0)
wsb, err = wrapper.WrappedSignedBeaconBlock(genesis)
require.NoError(t, err)
service.saveInitSyncBlock(gRoot, wsb)
@@ -504,7 +503,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, [32]byte{})
service.cfg.ForkChoiceStore = protoarray.New(0, 0)
lastJustifiedBlk := util.NewBeaconBlock()
lastJustifiedBlk.Block.ParentRoot = bytesutil.PadTo([]byte{'G'}, 32)
lastJustifiedRoot, err := lastJustifiedBlk.Block.HashTreeRoot()
@@ -584,7 +583,7 @@ func TestCachedPreState_CanGetFromStateSummary_ProtoArray(t *testing.T) {
gRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err)
service.store.SetFinalizedCheckptAndPayloadHash(&ethpb.Checkpoint{Root: gRoot[:]}, [32]byte{})
service.cfg.ForkChoiceStore = protoarray.New(0, 0, [32]byte{})
service.cfg.ForkChoiceStore = protoarray.New(0, 0)
wsb, err = wrapper.WrappedSignedBeaconBlock(genesis)
require.NoError(t, err)
service.saveInitSyncBlock(gRoot, wsb)
@@ -655,7 +654,7 @@ func TestCachedPreState_CanGetFromDB(t *testing.T) {
gRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err)
service.store.SetFinalizedCheckptAndPayloadHash(&ethpb.Checkpoint{Root: gRoot[:]}, [32]byte{})
service.cfg.ForkChoiceStore = protoarray.New(0, 0, [32]byte{})
service.cfg.ForkChoiceStore = protoarray.New(0, 0)
wsb, err = wrapper.WrappedSignedBeaconBlock(genesis)
require.NoError(t, err)
service.saveInitSyncBlock(gRoot, wsb)
@@ -686,7 +685,7 @@ func TestUpdateJustified_CouldUpdateBest(t *testing.T) {
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
WithForkChoiceStore(protoarray.New(0, 0, [32]byte{})),
WithForkChoiceStore(protoarray.New(0, 0)),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
@@ -709,13 +708,17 @@ func TestUpdateJustified_CouldUpdateBest(t *testing.T) {
require.NoError(t, s.SetCurrentJustifiedCheckpoint(&ethpb.Checkpoint{Epoch: 1, Root: r[:]}))
require.NoError(t, service.updateJustified(context.Background(), s))
assert.Equal(t, s.CurrentJustifiedCheckpoint().Epoch, service.store.BestJustifiedCheckpt().Epoch, "Incorrect justified epoch in service")
cp, err := service.store.BestJustifiedCheckpt()
require.NoError(t, err)
assert.Equal(t, s.CurrentJustifiedCheckpoint().Epoch, cp.Epoch, "Incorrect justified epoch in service")
// Could not update
service.store.SetBestJustifiedCheckpt(&ethpb.Checkpoint{Root: []byte{'A'}, Epoch: 2})
require.NoError(t, service.updateJustified(context.Background(), s))
assert.Equal(t, types.Epoch(2), service.store.BestJustifiedCheckpt().Epoch, "Incorrect justified epoch in service")
cp, err = service.store.BestJustifiedCheckpt()
require.NoError(t, err)
assert.Equal(t, types.Epoch(2), cp.Epoch, "Incorrect justified epoch in service")
}
func TestFillForkChoiceMissingBlocks_CanSave_ProtoArray(t *testing.T) {
@@ -728,7 +731,7 @@ func TestFillForkChoiceMissingBlocks_CanSave_ProtoArray(t *testing.T) {
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
service.cfg.ForkChoiceStore = protoarray.New(0, 0, [32]byte{'A'})
service.cfg.ForkChoiceStore = protoarray.New(0, 0)
service.store.SetFinalizedCheckptAndPayloadHash(&ethpb.Checkpoint{Root: make([]byte, 32)}, [32]byte{})
genesisStateRoot := [32]byte{}
@@ -819,7 +822,7 @@ func TestFillForkChoiceMissingBlocks_RootsMatch_ProtoArray(t *testing.T) {
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
service.cfg.ForkChoiceStore = protoarray.New(0, 0, [32]byte{'A'})
service.cfg.ForkChoiceStore = protoarray.New(0, 0)
service.store.SetFinalizedCheckptAndPayloadHash(&ethpb.Checkpoint{Root: make([]byte, 32)}, [32]byte{})
genesisStateRoot := [32]byte{}
@@ -917,7 +920,7 @@ func TestFillForkChoiceMissingBlocks_FilterFinalized_ProtoArray(t *testing.T) {
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
service.cfg.ForkChoiceStore = protoarray.New(0, 0, [32]byte{'A'})
service.cfg.ForkChoiceStore = protoarray.New(0, 0)
// Set finalized epoch to 1.
service.store.SetFinalizedCheckptAndPayloadHash(&ethpb.Checkpoint{Epoch: 1}, [32]byte{})
@@ -1141,7 +1144,7 @@ func TestAncestor_HandleSkipSlot(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0, [32]byte{'a'})
fcs := protoarray.New(0, 0)
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -1230,7 +1233,7 @@ func TestAncestor_CanUseDB(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0, [32]byte{'a'})
fcs := protoarray.New(0, 0)
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -1290,7 +1293,7 @@ func TestVerifyBlkDescendant(t *testing.T) {
beaconDB := testDB.SetupDB(t)
ctx := context.Background()
fcs := protoarray.New(0, 0, [32]byte{'a'})
fcs := protoarray.New(0, 0)
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -1318,9 +1321,10 @@ func TestVerifyBlkDescendant(t *testing.T) {
finalizedRoot [32]byte
}
tests := []struct {
name string
args args
wantedErr string
name string
args args
wantedErr string
invalidBlockRoot bool
}{
{
name: "could not get finalized block in block service cache",
@@ -1343,7 +1347,8 @@ func TestVerifyBlkDescendant(t *testing.T) {
finalizedRoot: r1,
parentRoot: r,
},
wantedErr: "is not a descendant of the current finalized block slot",
wantedErr: "is not a descendant of the current finalized block slot",
invalidBlockRoot: true,
},
{
name: "is descendant",
@@ -1360,6 +1365,9 @@ func TestVerifyBlkDescendant(t *testing.T) {
err = service.VerifyFinalizedBlkDescendant(ctx, tt.args.parentRoot)
if tt.wantedErr != "" {
assert.ErrorContains(t, tt.wantedErr, err)
if tt.invalidBlockRoot {
require.Equal(t, true, IsInvalidBlock(err))
}
} else if err != nil {
assert.NoError(t, err)
}
@@ -1389,9 +1397,13 @@ func TestUpdateJustifiedInitSync(t *testing.T) {
require.NoError(t, service.updateJustifiedInitSync(ctx, newCp))
assert.DeepSSZEqual(t, currentCp, service.PreviousJustifiedCheckpt(), "Incorrect previous justified checkpoint")
assert.DeepSSZEqual(t, newCp, service.CurrentJustifiedCheckpt(), "Incorrect current justified checkpoint in cache")
cp, err := service.cfg.BeaconDB.JustifiedCheckpoint(ctx)
cp, err := service.PreviousJustifiedCheckpt()
require.NoError(t, err)
assert.DeepSSZEqual(t, currentCp, cp, "Incorrect previous justified checkpoint")
cp, err = service.CurrentJustifiedCheckpt()
require.NoError(t, err)
assert.DeepSSZEqual(t, newCp, cp, "Incorrect current justified checkpoint in cache")
cp, err = service.cfg.BeaconDB.JustifiedCheckpoint(ctx)
require.NoError(t, err)
assert.DeepSSZEqual(t, newCp, cp, "Incorrect current justified checkpoint in db")
}
@@ -1426,7 +1438,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, [32]byte{'a'})
fcs := protoarray.New(0, 0)
depositCache, err := depositcache.New()
require.NoError(t, err)
opts := []Option{
@@ -1459,16 +1471,78 @@ func TestOnBlock_CanFinalize(t *testing.T) {
testState, err = service.cfg.StateGen.StateByRoot(ctx, r)
require.NoError(t, err)
}
require.Equal(t, types.Epoch(3), service.CurrentJustifiedCheckpt().Epoch)
require.Equal(t, types.Epoch(2), service.FinalizedCheckpt().Epoch)
cp, err := service.CurrentJustifiedCheckpt()
require.NoError(t, err)
require.Equal(t, types.Epoch(3), cp.Epoch)
cp, err = service.FinalizedCheckpt()
require.NoError(t, err)
require.Equal(t, types.Epoch(2), cp.Epoch)
// The update should persist in DB.
j, err := service.cfg.BeaconDB.JustifiedCheckpoint(ctx)
require.NoError(t, err)
require.Equal(t, j.Epoch, service.CurrentJustifiedCheckpt().Epoch)
cp, err = service.CurrentJustifiedCheckpt()
require.NoError(t, err)
require.Equal(t, j.Epoch, cp.Epoch)
f, err := service.cfg.BeaconDB.FinalizedCheckpoint(ctx)
require.NoError(t, err)
require.Equal(t, f.Epoch, service.FinalizedCheckpt().Epoch)
cp, err = service.FinalizedCheckpt()
require.NoError(t, err)
require.Equal(t, f.Epoch, cp.Epoch)
}
func TestOnBlock_NilBlock(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0)
depositCache, err := depositcache.New()
require.NoError(t, err)
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
WithForkChoiceStore(fcs),
WithDepositCache(depositCache),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
err = service.onBlock(ctx, nil, [32]byte{})
require.Equal(t, true, IsInvalidBlock(err))
}
func TestOnBlock_InvalidSignature(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0)
depositCache, err := depositcache.New()
require.NoError(t, err)
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
WithForkChoiceStore(fcs),
WithDepositCache(depositCache),
WithStateNotifier(&mock.MockStateNotifier{}),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
gs, keys := util.DeterministicGenesisState(t, 32)
require.NoError(t, service.saveGenesisData(ctx, gs))
gBlk, err := service.cfg.BeaconDB.GenesisBlock(ctx)
require.NoError(t, err)
gRoot, err := gBlk.Block().HashTreeRoot()
require.NoError(t, err)
service.store.SetFinalizedCheckptAndPayloadHash(&ethpb.Checkpoint{Root: gRoot[:]}, [32]byte{})
blk, err := util.GenerateFullBlock(gs, keys, util.DefaultBlockGenConfig(), 1)
require.NoError(t, err)
blk.Signature = []byte{'a'} // Mutate the signature.
r, err := blk.Block.HashTreeRoot()
require.NoError(t, err)
wsb, err := wrapper.WrappedSignedBeaconBlock(blk)
require.NoError(t, err)
err = service.onBlock(ctx, wsb, r)
require.Equal(t, true, IsInvalidBlock(err))
}
func TestOnBlock_CallNewPayloadAndForkchoiceUpdated(t *testing.T) {
@@ -1480,7 +1554,7 @@ func TestOnBlock_CallNewPayloadAndForkchoiceUpdated(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0, [32]byte{'a'})
fcs := protoarray.New(0, 0)
depositCache, err := depositcache.New()
require.NoError(t, err)
opts := []Option{
@@ -1718,7 +1792,7 @@ func Test_validateMergeTransitionBlock(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0, [32]byte{'a'})
fcs := protoarray.New(0, 0)
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -1846,7 +1920,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, [32]byte{'a'})
fcs := protoarray.New(0, 0)
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
@@ -1897,7 +1971,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, [32]byte{'a'})
fcs := protoarray.New(0, 0)
depositCache, err := depositcache.New()
require.NoError(t, err)
opts := []Option{
@@ -1969,6 +2043,26 @@ 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, [32]byte{'a'})
service.cfg.ForkChoiceStore = protoarray.New(0, 0)
}
}
func Test_verifyBlkFinalizedSlot_invalidBlock(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0)
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
WithForkChoiceStore(fcs),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
service.store.SetFinalizedCheckptAndPayloadHash(&ethpb.Checkpoint{Epoch: 1}, [32]byte{'a'})
blk := util.HydrateBeaconBlock(&ethpb.BeaconBlock{Slot: 1})
wb, err := wrapper.WrappedBeaconBlock(blk)
require.NoError(t, err)
err = service.verifyBlkFinalizedSlot(wb)
require.Equal(t, true, IsInvalidBlock(err))
}

View File

@@ -71,9 +71,9 @@ func (s *Service) VerifyFinalizedConsistency(ctx context.Context, root []byte) e
return nil
}
f := s.FinalizedCheckpt()
if f == nil {
return errNilFinalizedInStore
f, err := s.FinalizedCheckpt()
if err != nil {
return err
}
ss, err := slots.EpochStart(f.Epoch)
if err != nil {
@@ -152,9 +152,9 @@ func (s *Service) UpdateHead(ctx context.Context) error {
s.processAttestations(ctx)
justified := s.store.JustifiedCheckpt()
if justified == nil {
return errNilJustifiedInStore
justified, err := s.store.JustifiedCheckpt()
if err != nil {
return err
}
balances, err := s.justifiedBalances.get(ctx, bytesutil.ToBytes32(justified.Root))
if err != nil {

View File

@@ -59,14 +59,18 @@ func (s *Service) ReceiveBlock(ctx context.Context, block interfaces.SignedBeaco
}
// Reports on block and fork choice metrics.
finalized := s.store.FinalizedCheckpt()
if finalized == nil {
justified, err := s.store.JustifiedCheckpt()
if err != nil {
return err
}
finalized, err := s.store.FinalizedCheckpt()
if err != nil {
return errNilFinalizedInStore
}
reportSlotMetrics(blockCopy.Block().Slot(), s.HeadSlot(), s.CurrentSlot(), finalized)
// Log block sync status.
if err := logBlockSyncStatus(blockCopy.Block(), blockRoot, finalized, receivedTime, uint64(s.genesisTime.Unix())); err != nil {
if err := logBlockSyncStatus(blockCopy.Block(), blockRoot, justified, finalized, receivedTime, uint64(s.genesisTime.Unix())); err != nil {
return err
}
// Log state transition data.
@@ -106,9 +110,9 @@ func (s *Service) ReceiveBlockBatch(ctx context.Context, blocks []interfaces.Sig
})
// Reports on blockCopy and fork choice metrics.
finalized := s.store.FinalizedCheckpt()
if finalized == nil {
return errNilFinalizedInStore
finalized, err := s.store.FinalizedCheckpt()
if err != nil {
return errors.Wrap(err, "could not get finalized checkpoint")
}
reportSlotMetrics(blockCopy.Block().Slot(), s.HeadSlot(), s.CurrentSlot(), finalized)
}
@@ -116,7 +120,10 @@ func (s *Service) ReceiveBlockBatch(ctx context.Context, blocks []interfaces.Sig
if err := s.cfg.BeaconDB.SaveBlocks(ctx, s.getInitSyncBlocks()); err != nil {
return err
}
finalized := s.store.FinalizedCheckpt()
finalized, err := s.store.FinalizedCheckpt()
if err != nil {
return errors.Wrap(err, "could not get finalized checkpoint")
}
if finalized == nil {
return errNilFinalizedInStore
}
@@ -169,7 +176,10 @@ func (s *Service) checkSaveHotStateDB(ctx context.Context) error {
currentEpoch := slots.ToEpoch(s.CurrentSlot())
// Prevent `sinceFinality` going underflow.
var sinceFinality types.Epoch
finalized := s.store.FinalizedCheckpt()
finalized, err := s.store.FinalizedCheckpt()
if err != nil {
return err
}
if finalized == nil {
return errNilFinalizedInStore
}

View File

@@ -127,7 +127,7 @@ func TestService_ReceiveBlock(t *testing.T) {
opts := []Option{
WithDatabase(beaconDB),
WithForkChoiceStore(protoarray.New(0, 0, genesisBlockRoot)),
WithForkChoiceStore(protoarray.New(0, 0)),
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, genesisBlockRoot)),
WithForkChoiceStore(protoarray.New(0, 0)),
WithAttestationPool(attestations.NewPool()),
WithExitPool(voluntaryexits.NewPool()),
WithStateNotifier(&blockchainTesting.MockStateNotifier{RecordEvents: true}),
@@ -246,11 +246,9 @@ func TestService_ReceiveBlockBatch(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
beaconDB := testDB.SetupDB(t)
genesisBlockRoot, err := genesis.HashTreeRoot(ctx)
require.NoError(t, err)
opts := []Option{
WithDatabase(beaconDB),
WithForkChoiceStore(protoarray.New(0, 0, genesisBlockRoot)),
WithForkChoiceStore(protoarray.New(0, 0)),
WithStateNotifier(&blockchainTesting.MockStateNotifier{RecordEvents: true}),
WithStateGen(stategen.New(beaconDB)),
}

View File

@@ -35,6 +35,7 @@ import (
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
prysmTime "github.com/prysmaticlabs/prysm/time"
@@ -198,7 +199,7 @@ func (s *Service) StartFromSavedState(saved state.BeaconState) error {
if features.Get().EnableForkChoiceDoublyLinkedTree {
forkChoicer = doublylinkedtree.New(justified.Epoch, finalized.Epoch)
} else {
forkChoicer = protoarray.New(justified.Epoch, finalized.Epoch, fRoot)
forkChoicer = protoarray.New(justified.Epoch, finalized.Epoch)
}
s.cfg.ForkChoiceStore = forkChoicer
fb, err := s.getBlock(s.ctx, s.ensureRootNotZeros(fRoot))
@@ -270,7 +271,7 @@ func (s *Service) originRootFromSavedState(ctx context.Context) ([32]byte, error
if err != nil {
return originRoot, errors.Wrap(err, "could not get genesis block from db")
}
if err := helpers.BeaconBlockIsNil(genesisBlock); err != nil {
if err := wrapper.BeaconBlockIsNil(genesisBlock); err != nil {
return originRoot, err
}
genesisBlkRoot, err := genesisBlock.Block().HashTreeRoot()

View File

@@ -130,7 +130,7 @@ func setupBeaconChain(t *testing.T, beaconDB db.Database) *Service {
WithAttestationPool(attestations.NewPool()),
WithP2PBroadcaster(&mockBroadcaster{}),
WithStateNotifier(&mockBeaconNode{}),
WithForkChoiceStore(protoarray.New(0, 0, params.BeaconConfig().ZeroHash)),
WithForkChoiceStore(protoarray.New(0, 0)),
WithAttestationService(attService),
WithStateGen(stateGen),
}
@@ -277,8 +277,12 @@ func TestChainService_CorrectGenesisRoots(t *testing.T) {
// Test the start function.
chainService.Start()
require.DeepEqual(t, blkRoot[:], chainService.store.FinalizedCheckpt().Root, "Finalize Checkpoint root is incorrect")
require.DeepEqual(t, params.BeaconConfig().ZeroHash[:], chainService.store.JustifiedCheckpt().Root, "Justified Checkpoint root is incorrect")
cp, err := chainService.store.FinalizedCheckpt()
require.NoError(t, err)
require.DeepEqual(t, blkRoot[:], cp.Root, "Finalize Checkpoint root is incorrect")
cp, err = chainService.store.JustifiedCheckpt()
require.NoError(t, err)
require.DeepEqual(t, params.BeaconConfig().ZeroHash[:], cp.Root, "Justified Checkpoint root is incorrect")
require.NoError(t, chainService.Stop(), "Unable to stop chain service")
@@ -501,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, [32]byte{}), BeaconDB: beaconDB},
cfg: &config{ForkChoiceStore: protoarray.New(0, 0), BeaconDB: beaconDB},
store: &store.Store{},
}
s.store.SetFinalizedCheckptAndPayloadHash(&ethpb.Checkpoint{Epoch: 0, Root: params.BeaconConfig().ZeroHash[:]}, [32]byte{})
@@ -595,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, [32]byte{}), BeaconDB: beaconDB},
cfg: &config{ForkChoiceStore: protoarray.New(0, 0), BeaconDB: beaconDB},
store: &store.Store{},
}
s.store.SetFinalizedCheckptAndPayloadHash(&ethpb.Checkpoint{Epoch: 0, Root: params.BeaconConfig().ZeroHash[:]}, [32]byte{})

View File

@@ -11,8 +11,6 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
)
var errNilStateFromStategen = errors.New("justified state can't be nil")
type stateBalanceCache struct {
sync.Mutex
balances []uint64

View File

@@ -10,7 +10,10 @@ go_library(
],
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/store",
visibility = ["//beacon-chain:__subpackages__"],
deps = ["//proto/prysm/v1alpha1:go_default_library"],
deps = [
"//proto/prysm/v1alpha1:go_default_library",
"@com_github_pkg_errors//:go_default_library",
],
)
go_test(

View File

@@ -17,9 +17,19 @@ func TestNew(t *testing.T) {
Root: []byte("hello"),
}
s := New(j, f)
require.DeepSSZEqual(t, s.JustifiedCheckpt(), j)
require.DeepSSZEqual(t, s.BestJustifiedCheckpt(), j)
require.DeepSSZEqual(t, s.PrevJustifiedCheckpt(), j)
require.DeepSSZEqual(t, s.FinalizedCheckpt(), f)
require.DeepSSZEqual(t, s.PrevFinalizedCheckpt(), f)
cp, err := s.JustifiedCheckpt()
require.NoError(t, err)
require.DeepSSZEqual(t, j, cp)
cp, err = s.BestJustifiedCheckpt()
require.NoError(t, err)
require.DeepSSZEqual(t, j, cp)
cp, err = s.PrevJustifiedCheckpt()
require.NoError(t, err)
require.DeepSSZEqual(t, j, cp)
cp, err = s.FinalizedCheckpt()
require.NoError(t, err)
require.DeepSSZEqual(t, f, cp)
cp, err = s.PrevFinalizedCheckpt()
require.NoError(t, err)
require.DeepSSZEqual(t, f, cp)
}

View File

@@ -1,26 +1,42 @@
package store
import ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
import (
"github.com/pkg/errors"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
var (
ErrNilCheckpoint = errors.New("nil checkpoint")
)
// PrevJustifiedCheckpt returns the previous justified checkpoint in the Store.
func (s *Store) PrevJustifiedCheckpt() *ethpb.Checkpoint {
func (s *Store) PrevJustifiedCheckpt() (*ethpb.Checkpoint, error) {
s.RLock()
defer s.RUnlock()
return s.prevJustifiedCheckpt
if s.prevJustifiedCheckpt == nil {
return nil, ErrNilCheckpoint
}
return s.prevJustifiedCheckpt, nil
}
// BestJustifiedCheckpt returns the best justified checkpoint in the Store.
func (s *Store) BestJustifiedCheckpt() *ethpb.Checkpoint {
func (s *Store) BestJustifiedCheckpt() (*ethpb.Checkpoint, error) {
s.RLock()
defer s.RUnlock()
return s.bestJustifiedCheckpt
if s.bestJustifiedCheckpt == nil {
return nil, ErrNilCheckpoint
}
return s.bestJustifiedCheckpt, nil
}
// JustifiedCheckpt returns the justified checkpoint in the Store.
func (s *Store) JustifiedCheckpt() *ethpb.Checkpoint {
func (s *Store) JustifiedCheckpt() (*ethpb.Checkpoint, error) {
s.RLock()
defer s.RUnlock()
return s.justifiedCheckpt
if s.justifiedCheckpt == nil {
return nil, ErrNilCheckpoint
}
return s.justifiedCheckpt, nil
}
// JustifiedPayloadBlockHash returns the justified payload block hash reflecting justified check point.
@@ -31,17 +47,23 @@ func (s *Store) JustifiedPayloadBlockHash() [32]byte {
}
// PrevFinalizedCheckpt returns the previous finalized checkpoint in the Store.
func (s *Store) PrevFinalizedCheckpt() *ethpb.Checkpoint {
func (s *Store) PrevFinalizedCheckpt() (*ethpb.Checkpoint, error) {
s.RLock()
defer s.RUnlock()
return s.prevFinalizedCheckpt
if s.prevFinalizedCheckpt == nil {
return nil, ErrNilCheckpoint
}
return s.prevFinalizedCheckpt, nil
}
// FinalizedCheckpt returns the finalized checkpoint in the Store.
func (s *Store) FinalizedCheckpt() *ethpb.Checkpoint {
func (s *Store) FinalizedCheckpt() (*ethpb.Checkpoint, error) {
s.RLock()
defer s.RUnlock()
return s.finalizedCheckpt
if s.finalizedCheckpt == nil {
return nil, ErrNilCheckpoint
}
return s.finalizedCheckpt, nil
}
// FinalizedPayloadBlockHash returns the finalized payload block hash reflecting finalized check point.

View File

@@ -10,48 +10,63 @@ import (
func Test_store_PrevJustifiedCheckpt(t *testing.T) {
s := &Store{}
var cp *ethpb.Checkpoint
require.Equal(t, cp, s.PrevJustifiedCheckpt())
_, err := s.PrevJustifiedCheckpt()
require.ErrorIs(t, ErrNilCheckpoint, err)
cp = &ethpb.Checkpoint{Epoch: 1, Root: []byte{'a'}}
s.SetPrevJustifiedCheckpt(cp)
require.Equal(t, cp, s.PrevJustifiedCheckpt())
got, err := s.PrevJustifiedCheckpt()
require.NoError(t, err)
require.Equal(t, cp, got)
}
func Test_store_BestJustifiedCheckpt(t *testing.T) {
s := &Store{}
var cp *ethpb.Checkpoint
require.Equal(t, cp, s.BestJustifiedCheckpt())
_, err := s.BestJustifiedCheckpt()
require.ErrorIs(t, ErrNilCheckpoint, err)
cp = &ethpb.Checkpoint{Epoch: 1, Root: []byte{'a'}}
s.SetBestJustifiedCheckpt(cp)
require.Equal(t, cp, s.BestJustifiedCheckpt())
got, err := s.BestJustifiedCheckpt()
require.NoError(t, err)
require.Equal(t, cp, got)
}
func Test_store_JustifiedCheckpt(t *testing.T) {
s := &Store{}
var cp *ethpb.Checkpoint
require.Equal(t, cp, s.JustifiedCheckpt())
_, err := s.JustifiedCheckpt()
require.ErrorIs(t, ErrNilCheckpoint, err)
cp = &ethpb.Checkpoint{Epoch: 1, Root: []byte{'a'}}
h := [32]byte{'b'}
s.SetJustifiedCheckptAndPayloadHash(cp, h)
require.Equal(t, cp, s.JustifiedCheckpt())
got, err := s.JustifiedCheckpt()
require.NoError(t, err)
require.Equal(t, cp, got)
require.Equal(t, h, s.JustifiedPayloadBlockHash())
}
func Test_store_FinalizedCheckpt(t *testing.T) {
s := &Store{}
var cp *ethpb.Checkpoint
require.Equal(t, cp, s.FinalizedCheckpt())
_, err := s.FinalizedCheckpt()
require.ErrorIs(t, ErrNilCheckpoint, err)
cp = &ethpb.Checkpoint{Epoch: 1, Root: []byte{'a'}}
h := [32]byte{'b'}
s.SetFinalizedCheckptAndPayloadHash(cp, h)
require.Equal(t, cp, s.FinalizedCheckpt())
got, err := s.FinalizedCheckpt()
require.NoError(t, err)
require.Equal(t, cp, got)
require.Equal(t, h, s.FinalizedPayloadBlockHash())
}
func Test_store_PrevFinalizedCheckpt(t *testing.T) {
s := &Store{}
var cp *ethpb.Checkpoint
require.Equal(t, cp, s.PrevFinalizedCheckpt())
_, err := s.PrevFinalizedCheckpt()
require.ErrorIs(t, ErrNilCheckpoint, err)
cp = &ethpb.Checkpoint{Epoch: 1, Root: []byte{'a'}}
s.SetPrevFinalizedCheckpt(cp)
require.Equal(t, cp, s.PrevFinalizedCheckpt())
got, err := s.PrevFinalizedCheckpt()
require.NoError(t, err)
require.Equal(t, cp, got)
}

View File

@@ -282,18 +282,18 @@ func (s *ChainService) CurrentFork() *ethpb.Fork {
}
// FinalizedCheckpt mocks FinalizedCheckpt method in chain service.
func (s *ChainService) FinalizedCheckpt() *ethpb.Checkpoint {
return s.FinalizedCheckPoint
func (s *ChainService) FinalizedCheckpt() (*ethpb.Checkpoint, error) {
return s.FinalizedCheckPoint, nil
}
// CurrentJustifiedCheckpt mocks CurrentJustifiedCheckpt method in chain service.
func (s *ChainService) CurrentJustifiedCheckpt() *ethpb.Checkpoint {
return s.CurrentJustifiedCheckPoint
func (s *ChainService) CurrentJustifiedCheckpt() (*ethpb.Checkpoint, error) {
return s.CurrentJustifiedCheckPoint, nil
}
// PreviousJustifiedCheckpt mocks PreviousJustifiedCheckpt method in chain service.
func (s *ChainService) PreviousJustifiedCheckpt() *ethpb.Checkpoint {
return s.PreviousJustifiedCheckPoint
func (s *ChainService) PreviousJustifiedCheckpt() (*ethpb.Checkpoint, error) {
return s.PreviousJustifiedCheckPoint, nil
}
// ReceiveAttestation mocks ReceiveAttestation method in chain service.

View File

@@ -13,9 +13,6 @@ import (
"github.com/prysmaticlabs/prysm/time/slots"
)
var errWSBlockNotFound = errors.New("weak subjectivity root not found in db")
var errWSBlockNotFoundInEpoch = errors.New("weak subjectivity root not found in db within epoch")
type weakSubjectivityDB interface {
HasBlock(ctx context.Context, blockRoot [32]byte) bool
BlockRoots(ctx context.Context, f *filters.QueryFilter) ([][32]byte, error)

View File

@@ -80,7 +80,9 @@ func TestService_VerifyWeakSubjectivityRoot(t *testing.T) {
wsVerifier: wv,
}
s.store.SetFinalizedCheckptAndPayloadHash(&ethpb.Checkpoint{Epoch: tt.finalizedEpoch}, [32]byte{})
err = s.wsVerifier.VerifyWeakSubjectivity(context.Background(), s.store.FinalizedCheckpt().Epoch)
cp, err := s.store.FinalizedCheckpt()
require.NoError(t, err)
err = s.wsVerifier.VerifyWeakSubjectivity(context.Background(), cp.Epoch)
if tt.wantErr == nil {
require.NoError(t, err)
} else {

View File

@@ -123,7 +123,7 @@ func (s *SyncCommitteeCache) idxPositionInCommittee(
// UpdatePositionsInCommittee updates caching of validators position in sync committee in respect to
// current epoch and next epoch. This should be called when `current_sync_committee` and `next_sync_committee`
// change and that happens every `EPOCHS_PER_SYNC_COMMITTEE_PERIOD`.
func (s *SyncCommitteeCache) UpdatePositionsInCommittee(syncCommitteeBoundaryRoot [32]byte, st state.BeaconStateAltair) error {
func (s *SyncCommitteeCache) UpdatePositionsInCommittee(syncCommitteeBoundaryRoot [32]byte, st state.BeaconState) error {
csc, err := st.CurrentSyncCommittee()
if err != nil {
return err

View File

@@ -28,6 +28,6 @@ func (s *FakeSyncCommitteeCache) NextPeriodIndexPosition(root [32]byte, valIdx t
}
// UpdatePositionsInCommittee -- fake.
func (s *FakeSyncCommitteeCache) UpdatePositionsInCommittee(syncCommitteeBoundaryRoot [32]byte, state state.BeaconStateAltair) error {
func (s *FakeSyncCommitteeCache) UpdatePositionsInCommittee(syncCommitteeBoundaryRoot [32]byte, state state.BeaconState) error {
return nil
}

View File

@@ -35,13 +35,13 @@ go_library(
"//config/params:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//consensus-types/primitives:go_default_library",
"//consensus-types/wrapper:go_default_library",
"//crypto/bls:go_default_library",
"//crypto/hash:go_default_library",
"//encoding/bytesutil:go_default_library",
"//math:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/attestation:go_default_library",
"//runtime/version:go_default_library",
"//time/slots:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",

View File

@@ -13,6 +13,7 @@ import (
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/attestation"
"go.opencensus.io/trace"
@@ -25,7 +26,7 @@ func ProcessAttestationsNoVerifySignature(
beaconState state.BeaconState,
b interfaces.SignedBeaconBlock,
) (state.BeaconState, error) {
if err := helpers.BeaconBlockIsNil(b); err != nil {
if err := wrapper.BeaconBlockIsNil(b); err != nil {
return nil, err
}
body := b.Block().Body()
@@ -46,10 +47,10 @@ func ProcessAttestationsNoVerifySignature(
// method is used to validate attestations whose signatures have already been verified or will be verified later.
func ProcessAttestationNoVerifySignature(
ctx context.Context,
beaconState state.BeaconStateAltair,
beaconState state.BeaconState,
att *ethpb.Attestation,
totalBalance uint64,
) (state.BeaconStateAltair, error) {
) (state.BeaconState, error) {
ctx, span := trace.StartSpan(ctx, "altair.ProcessAttestationNoVerifySignature")
defer span.End()
@@ -262,7 +263,7 @@ func RewardProposer(ctx context.Context, beaconState state.BeaconState, proposer
// participation_flag_indices.append(TIMELY_HEAD_FLAG_INDEX)
//
// return participation_flag_indices
func AttestationParticipationFlagIndices(beaconState state.BeaconStateAltair, data *ethpb.AttestationData, delay types.Slot) (map[uint8]bool, error) {
func AttestationParticipationFlagIndices(beaconState state.BeaconState, data *ethpb.AttestationData, delay types.Slot) (map[uint8]bool, error) {
currEpoch := time.CurrentEpoch(beaconState)
var justifiedCheckpt *ethpb.Checkpoint
if data.Target.Epoch == currEpoch {

View File

@@ -44,7 +44,7 @@ import (
// increase_balance(state, get_beacon_proposer_index(state), proposer_reward)
// else:
// decrease_balance(state, participant_index, participant_reward)
func ProcessSyncAggregate(ctx context.Context, s state.BeaconStateAltair, sync *ethpb.SyncAggregate) (state.BeaconStateAltair, error) {
func ProcessSyncAggregate(ctx context.Context, s state.BeaconState, sync *ethpb.SyncAggregate) (state.BeaconState, error) {
votedKeys, votedIndices, didntVoteIndices, err := FilterSyncCommitteeVotes(s, sync)
if err != nil {
return nil, err
@@ -58,7 +58,7 @@ func ProcessSyncAggregate(ctx context.Context, s state.BeaconStateAltair, sync *
}
// FilterSyncCommitteeVotes filters the validator public keys and indices for the ones that voted and didn't vote.
func FilterSyncCommitteeVotes(s state.BeaconStateAltair, sync *ethpb.SyncAggregate) (
func FilterSyncCommitteeVotes(s state.BeaconState, sync *ethpb.SyncAggregate) (
votedKeys []bls.PublicKey,
votedIndices []types.ValidatorIndex,
didntVoteIndices []types.ValidatorIndex,
@@ -100,7 +100,7 @@ func FilterSyncCommitteeVotes(s state.BeaconStateAltair, sync *ethpb.SyncAggrega
}
// VerifySyncCommitteeSig verifies sync committee signature `syncSig` is valid with respect to public keys `syncKeys`.
func VerifySyncCommitteeSig(s state.BeaconStateAltair, syncKeys []bls.PublicKey, syncSig []byte) error {
func VerifySyncCommitteeSig(s state.BeaconState, syncKeys []bls.PublicKey, syncSig []byte) error {
ps := slots.PrevSlot(s.Slot())
d, err := signing.Domain(s.Fork(), slots.ToEpoch(ps), params.BeaconConfig().DomainSyncCommittee, s.GenesisValidatorsRoot())
if err != nil {
@@ -126,7 +126,7 @@ func VerifySyncCommitteeSig(s state.BeaconStateAltair, syncKeys []bls.PublicKey,
}
// ApplySyncRewardsPenalties applies rewards and penalties for proposer and sync committee participants.
func ApplySyncRewardsPenalties(ctx context.Context, s state.BeaconStateAltair, votedIndices, didntVoteIndices []types.ValidatorIndex) (state.BeaconStateAltair, error) {
func ApplySyncRewardsPenalties(ctx context.Context, s state.BeaconState, votedIndices, didntVoteIndices []types.ValidatorIndex) (state.BeaconState, error) {
activeBalance, err := helpers.TotalActiveBalance(s)
if err != nil {
return nil, err

View File

@@ -13,9 +13,9 @@ import (
// ProcessDeposits processes validator deposits for beacon state Altair.
func ProcessDeposits(
ctx context.Context,
beaconState state.BeaconStateAltair,
beaconState state.BeaconState,
deposits []*ethpb.Deposit,
) (state.BeaconStateAltair, error) {
) (state.BeaconState, error) {
batchVerified, err := blocks.BatchVerifyDepositsSignatures(ctx, deposits)
if err != nil {
return nil, err
@@ -34,7 +34,7 @@ func ProcessDeposits(
}
// ProcessDeposit processes validator deposit for beacon state Altair.
func ProcessDeposit(ctx context.Context, beaconState state.BeaconStateAltair, deposit *ethpb.Deposit, verifySignature bool) (state.BeaconStateAltair, error) {
func ProcessDeposit(ctx context.Context, beaconState state.BeaconState, deposit *ethpb.Deposit, verifySignature bool) (state.BeaconState, error) {
beaconState, isNewValidator, err := blocks.ProcessDeposit(beaconState, deposit, verifySignature)
if err != nil {
return nil, err

View File

@@ -10,12 +10,11 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/math"
"github.com/prysmaticlabs/prysm/runtime/version"
"go.opencensus.io/trace"
)
// InitializePrecomputeValidators precomputes individual validator for its attested balances and the total sum of validators attested balances of the epoch.
func InitializePrecomputeValidators(ctx context.Context, beaconState state.BeaconStateAltair) ([]*precompute.Validator, *precompute.Balance, error) {
func InitializePrecomputeValidators(ctx context.Context, beaconState state.BeaconState) ([]*precompute.Validator, *precompute.Balance, error) {
_, span := trace.StartSpan(ctx, "altair.InitializePrecomputeValidators")
defer span.End()
vals := make([]*precompute.Validator, beaconState.NumValidators())
@@ -209,10 +208,10 @@ func ProcessEpochParticipation(
// ProcessRewardsAndPenaltiesPrecompute processes the rewards and penalties of individual validator.
// This is an optimized version by passing in precomputed validator attesting records and and total epoch balances.
func ProcessRewardsAndPenaltiesPrecompute(
beaconState state.BeaconStateAltair,
beaconState state.BeaconState,
bal *precompute.Balance,
vals []*precompute.Validator,
) (state.BeaconStateAltair, error) {
) (state.BeaconState, error) {
// Don't process rewards and penalties in genesis epoch.
cfg := params.BeaconConfig()
if time.CurrentEpoch(beaconState) == cfg.GenesisEpoch {
@@ -268,16 +267,12 @@ func AttestationsDelta(beaconState state.BeaconState, bal *precompute.Balance, v
leak := helpers.IsInInactivityLeak(prevEpoch, finalizedEpoch)
// Modified in Altair and Bellatrix.
var inactivityDenominator uint64
bias := cfg.InactivityScoreBias
switch beaconState.Version() {
case version.Altair:
inactivityDenominator = bias * cfg.InactivityPenaltyQuotientAltair
case version.Bellatrix:
inactivityDenominator = bias * cfg.InactivityPenaltyQuotientBellatrix
default:
return nil, nil, errors.Errorf("invalid state type version: %T", beaconState.Version())
inactivityPenaltyQuotient, err := beaconState.InactivityPenaltyQuotient()
if err != nil {
return nil, nil, err
}
inactivityDenominator := bias * inactivityPenaltyQuotient
for i, v := range vals {
rewards[i], penalties[i], err = attestationDelta(bal, v, baseRewardMultiplier, inactivityDenominator, leak)

View File

@@ -18,7 +18,7 @@ import (
// if next_epoch % EPOCHS_PER_SYNC_COMMITTEE_PERIOD == 0:
// state.current_sync_committee = state.next_sync_committee
// state.next_sync_committee = get_next_sync_committee(state)
func ProcessSyncCommitteeUpdates(ctx context.Context, beaconState state.BeaconStateAltair) (state.BeaconStateAltair, error) {
func ProcessSyncCommitteeUpdates(ctx context.Context, beaconState state.BeaconState) (state.BeaconState, error) {
nextEpoch := time.NextEpoch(beaconState)
if nextEpoch%params.BeaconConfig().EpochsPerSyncCommitteePeriod == 0 {
nextSyncCommittee, err := beaconState.NextSyncCommittee()
@@ -48,7 +48,7 @@ func ProcessSyncCommitteeUpdates(ctx context.Context, beaconState state.BeaconSt
// def process_participation_flag_updates(state: BeaconState) -> None:
// state.previous_epoch_participation = state.current_epoch_participation
// state.current_epoch_participation = [ParticipationFlags(0b0000_0000) for _ in range(len(state.validators))]
func ProcessParticipationFlagUpdates(beaconState state.BeaconStateAltair) (state.BeaconStateAltair, error) {
func ProcessParticipationFlagUpdates(beaconState state.BeaconState) (state.BeaconState, error) {
c, err := beaconState.CurrentEpochParticipation()
if err != nil {
return nil, err

View File

@@ -54,7 +54,7 @@ func ValidateNilSyncContribution(s *ethpb.SignedContributionAndProof) error {
// pubkeys = [state.validators[index].pubkey for index in indices]
// aggregate_pubkey = bls.AggregatePKs(pubkeys)
// return SyncCommittee(pubkeys=pubkeys, aggregate_pubkey=aggregate_pubkey)
func NextSyncCommittee(ctx context.Context, s state.BeaconStateAltair) (*ethpb.SyncCommittee, error) {
func NextSyncCommittee(ctx context.Context, s state.BeaconState) (*ethpb.SyncCommittee, error) {
indices, err := NextSyncCommitteeIndices(ctx, s)
if err != nil {
return nil, err
@@ -98,7 +98,7 @@ func NextSyncCommittee(ctx context.Context, s state.BeaconStateAltair) (*ethpb.S
// sync_committee_indices.append(candidate_index)
// i += 1
// return sync_committee_indices
func NextSyncCommitteeIndices(ctx context.Context, s state.BeaconStateAltair) ([]types.ValidatorIndex, error) {
func NextSyncCommitteeIndices(ctx context.Context, s state.BeaconState) ([]types.ValidatorIndex, error) {
epoch := coreTime.NextEpoch(s)
indices, err := helpers.ActiveValidatorIndices(ctx, s, epoch)
if err != nil {

View File

@@ -20,7 +20,7 @@ import (
)
func TestSyncCommitteeIndices_CanGet(t *testing.T) {
getState := func(t *testing.T, count uint64) state.BeaconStateAltair {
getState := func(t *testing.T, count uint64) state.BeaconState {
validators := make([]*ethpb.Validator, count)
for i := 0; i < len(validators); i++ {
validators[i] = &ethpb.Validator{
@@ -37,7 +37,7 @@ func TestSyncCommitteeIndices_CanGet(t *testing.T) {
}
type args struct {
state state.BeaconStateAltair
state state.BeaconState
epoch types.Epoch
}
tests := []struct {
@@ -95,7 +95,7 @@ func TestSyncCommitteeIndices_CanGet(t *testing.T) {
func TestSyncCommitteeIndices_DifferentPeriods(t *testing.T) {
helpers.ClearCache()
getState := func(t *testing.T, count uint64) state.BeaconStateAltair {
getState := func(t *testing.T, count uint64) state.BeaconState {
validators := make([]*ethpb.Validator, count)
for i := 0; i < len(validators); i++ {
validators[i] = &ethpb.Validator{
@@ -129,7 +129,7 @@ func TestSyncCommitteeIndices_DifferentPeriods(t *testing.T) {
}
func TestSyncCommittee_CanGet(t *testing.T) {
getState := func(t *testing.T, count uint64) state.BeaconStateAltair {
getState := func(t *testing.T, count uint64) state.BeaconState {
validators := make([]*ethpb.Validator, count)
for i := 0; i < len(validators); i++ {
blsKey, err := bls.RandKey()
@@ -149,7 +149,7 @@ func TestSyncCommittee_CanGet(t *testing.T) {
}
type args struct {
state state.BeaconStateAltair
state state.BeaconState
epoch types.Epoch
}
tests := []struct {
@@ -384,7 +384,7 @@ func Test_ValidateSyncMessageTime(t *testing.T) {
}
}
func getState(t *testing.T, count uint64) state.BeaconStateAltair {
func getState(t *testing.T, count uint64) state.BeaconState {
validators := make([]*ethpb.Validator, count)
for i := 0; i < len(validators); i++ {
blsKey, err := bls.RandKey()

View File

@@ -7,8 +7,6 @@ import (
e "github.com/prysmaticlabs/prysm/beacon-chain/core/epoch"
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/runtime/version"
"go.opencensus.io/trace"
)
@@ -29,7 +27,7 @@ import (
// process_historical_roots_update(state)
// process_participation_flag_updates(state) # [New in Altair]
// process_sync_committee_updates(state) # [New in Altair]
func ProcessEpoch(ctx context.Context, state state.BeaconState) (state.BeaconStateAltair, error) {
func ProcessEpoch(ctx context.Context, state state.BeaconState) (state.BeaconState, error) {
ctx, span := trace.StartSpan(ctx, "altair.ProcessEpoch")
defer span.End()
@@ -70,22 +68,14 @@ func ProcessEpoch(ctx context.Context, state state.BeaconState) (state.BeaconSta
}
// Modified in Altair and Bellatrix.
cfg := params.BeaconConfig()
switch state.Version() {
case version.Altair:
state, err = e.ProcessSlashings(state, cfg.ProportionalSlashingMultiplierAltair)
if err != nil {
return nil, err
}
case version.Bellatrix:
state, err = e.ProcessSlashings(state, cfg.ProportionalSlashingMultiplierBellatrix)
if err != nil {
return nil, err
}
default:
return nil, errors.Errorf("invalid state type version: %T", state.Version())
proportionalSlashingMultipler, err := state.ProportionalSlashingMultiplier()
if err != nil {
return nil, err
}
state, err = e.ProcessSlashings(state, proportionalSlashingMultipler)
if err != nil {
return nil, err
}
state, err = e.ProcessEth1DataReset(state)
if err != nil {
return nil, err

View File

@@ -62,7 +62,7 @@ import (
// post.current_sync_committee = get_next_sync_committee(post)
// post.next_sync_committee = get_next_sync_committee(post)
// return post
func UpgradeToAltair(ctx context.Context, state state.BeaconState) (state.BeaconStateAltair, error) {
func UpgradeToAltair(ctx context.Context, state state.BeaconState) (state.BeaconState, error) {
epoch := time.CurrentEpoch(state)
numValidators := state.NumValidators()
@@ -137,7 +137,7 @@ func UpgradeToAltair(ctx context.Context, state state.BeaconState) (state.Beacon
// for index in get_attesting_indices(state, data, attestation.aggregation_bits):
// for flag_index in participation_flag_indices:
// epoch_participation[index] = add_flag(epoch_participation[index], flag_index)
func TranslateParticipation(ctx context.Context, state state.BeaconStateAltair, atts []*ethpb.PendingAttestation) (state.BeaconStateAltair, error) {
func TranslateParticipation(ctx context.Context, state state.BeaconState, atts []*ethpb.PendingAttestation) (state.BeaconState, error) {
epochParticipation, err := state.PreviousEpochParticipation()
if err != nil {
return nil, err

View File

@@ -12,6 +12,7 @@ import (
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
"github.com/prysmaticlabs/prysm/crypto/bls"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/attestation"
@@ -25,7 +26,7 @@ func ProcessAttestationsNoVerifySignature(
beaconState state.BeaconState,
b interfaces.SignedBeaconBlock,
) (state.BeaconState, error) {
if err := helpers.BeaconBlockIsNil(b); err != nil {
if err := wrapper.BeaconBlockIsNil(b); err != nil {
return nil, err
}
body := b.Block().Body()

View File

@@ -10,6 +10,7 @@ import (
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
@@ -43,7 +44,7 @@ func ProcessBlockHeader(
beaconState state.BeaconState,
block interfaces.SignedBeaconBlock,
) (state.BeaconState, error) {
if err := helpers.BeaconBlockIsNil(block); err != nil {
if err := wrapper.BeaconBlockIsNil(block); err != nil {
return nil, err
}
bodyRoot, err := block.Block().Body().HashTreeRoot()

View File

@@ -4,10 +4,10 @@ import (
"context"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
"github.com/prysmaticlabs/prysm/crypto/hash"
"github.com/prysmaticlabs/prysm/time/slots"
)
@@ -31,7 +31,7 @@ func ProcessRandao(
beaconState state.BeaconState,
b interfaces.SignedBeaconBlock,
) (state.BeaconState, error) {
if err := helpers.BeaconBlockIsNil(b); err != nil {
if err := wrapper.BeaconBlockIsNil(b); err != nil {
return nil, err
}
body := b.Block().Body()

View File

@@ -22,7 +22,6 @@ go_library(
"//beacon-chain/state:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//consensus-types/primitives:go_default_library",
"//container/slice:go_default_library",
"//container/trie:go_default_library",

View File

@@ -6,31 +6,10 @@ import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/time/slots"
)
var ErrNilSignedBeaconBlock = errors.New("signed beacon block can't be nil")
var ErrNilBeaconBlock = errors.New("beacon block can't be nil")
var ErrNilBeaconBlockBody = errors.New("beacon block body can't be nil")
// BeaconBlockIsNil checks if any composite field of input signed beacon block is nil.
// Access to these nil fields will result in run time panic,
// it is recommended to run these checks as first line of defense.
func BeaconBlockIsNil(b interfaces.SignedBeaconBlock) error {
if b == nil || b.IsNil() {
return ErrNilSignedBeaconBlock
}
if b.Block().IsNil() {
return ErrNilBeaconBlock
}
if b.Block().Body().IsNil() {
return ErrNilBeaconBlockBody
}
return nil
}
// BlockRootAtSlot returns the block root stored in the BeaconState for a recent slot.
// It returns an error if the requested block root is not within the slot range.
//

View File

@@ -26,7 +26,7 @@ var (
// 1. Checks if the public key exists in the sync committee cache
// 2. If 1 fails, checks if the public key exists in the input current sync committee object
func IsCurrentPeriodSyncCommittee(
st state.BeaconStateAltair, valIdx types.ValidatorIndex,
st state.BeaconState, valIdx types.ValidatorIndex,
) (bool, error) {
root, err := syncPeriodBoundaryRoot(st)
if err != nil {
@@ -63,7 +63,7 @@ func IsCurrentPeriodSyncCommittee(
// 1. Checks if the public key exists in the sync committee cache
// 2. If 1 fails, checks if the public key exists in the input next sync committee object
func IsNextPeriodSyncCommittee(
st state.BeaconStateAltair, valIdx types.ValidatorIndex,
st state.BeaconState, valIdx types.ValidatorIndex,
) (bool, error) {
root, err := syncPeriodBoundaryRoot(st)
if err != nil {
@@ -90,7 +90,7 @@ func IsNextPeriodSyncCommittee(
// CurrentPeriodSyncSubcommitteeIndices returns the subcommittee indices of the
// current period sync committee for input validator.
func CurrentPeriodSyncSubcommitteeIndices(
st state.BeaconStateAltair, valIdx types.ValidatorIndex,
st state.BeaconState, valIdx types.ValidatorIndex,
) ([]types.CommitteeIndex, error) {
root, err := syncPeriodBoundaryRoot(st)
if err != nil {
@@ -124,7 +124,7 @@ func CurrentPeriodSyncSubcommitteeIndices(
// NextPeriodSyncSubcommitteeIndices returns the subcommittee indices of the next period sync committee for input validator.
func NextPeriodSyncSubcommitteeIndices(
st state.BeaconStateAltair, valIdx types.ValidatorIndex,
st state.BeaconState, valIdx types.ValidatorIndex,
) ([]types.CommitteeIndex, error) {
root, err := syncPeriodBoundaryRoot(st)
if err != nil {
@@ -151,7 +151,7 @@ func NextPeriodSyncSubcommitteeIndices(
// UpdateSyncCommitteeCache updates sync committee cache.
// It uses `state`'s latest block header root as key. To avoid misuse, it disallows
// block header with state root zeroed out.
func UpdateSyncCommitteeCache(st state.BeaconStateAltair) error {
func UpdateSyncCommitteeCache(st state.BeaconState) error {
nextSlot := st.Slot() + 1
if nextSlot%params.BeaconConfig().SlotsPerEpoch != 0 {
return errors.New("not at the end of the epoch to update cache")

View File

@@ -38,6 +38,7 @@ go_library(
"//config/params:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//consensus-types/primitives:go_default_library",
"//consensus-types/wrapper:go_default_library",
"//crypto/bls:go_default_library",
"//crypto/hash:go_default_library",
"//encoding/bytesutil:go_default_library",

View File

@@ -229,7 +229,7 @@ func TestProcessEpoch_BadBalanceAltair(t *testing.T) {
assert.ErrorContains(t, "addition overflows", err)
}
func createFullAltairBlockWithOperations(t *testing.T) (state.BeaconStateAltair,
func createFullAltairBlockWithOperations(t *testing.T) (state.BeaconState,
*ethpb.SignedBeaconBlockAltair) {
beaconState, privKeys := util.DeterministicGenesisStateAltair(t, 32)
sCom, err := altair.NextSyncCommittee(context.Background(), beaconState)

View File

@@ -14,12 +14,12 @@ import (
e "github.com/prysmaticlabs/prysm/beacon-chain/core/epoch"
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute"
"github.com/prysmaticlabs/prysm/beacon-chain/core/execution"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/core/time"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
"github.com/prysmaticlabs/prysm/math"
"github.com/prysmaticlabs/prysm/monitoring/tracing"
"github.com/prysmaticlabs/prysm/runtime/version"
@@ -52,7 +52,7 @@ func ExecuteStateTransition(
if ctx.Err() != nil {
return nil, ctx.Err()
}
if err := helpers.BeaconBlockIsNil(signed); err != nil {
if err := wrapper.BeaconBlockIsNil(signed); err != nil {
return nil, err
}
@@ -296,7 +296,7 @@ func ProcessSlots(ctx context.Context, state state.BeaconState, slot types.Slot)
// VerifyOperationLengths verifies that block operation lengths are valid.
func VerifyOperationLengths(_ context.Context, state state.BeaconState, b interfaces.SignedBeaconBlock) (state.BeaconState, error) {
if err := helpers.BeaconBlockIsNil(b); err != nil {
if err := wrapper.BeaconBlockIsNil(b); err != nil {
return nil, err
}
body := b.Block().Body()

View File

@@ -8,11 +8,11 @@ import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/beacon-chain/core/altair"
b "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/core/transition/interop"
v "github.com/prysmaticlabs/prysm/beacon-chain/core/validators"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
"github.com/prysmaticlabs/prysm/crypto/bls"
"github.com/prysmaticlabs/prysm/monitoring/tracing"
"github.com/prysmaticlabs/prysm/runtime/version"
@@ -160,7 +160,7 @@ func ProcessBlockNoVerifyAnySig(
) (*bls.SignatureBatch, state.BeaconState, error) {
ctx, span := trace.StartSpan(ctx, "core.state.ProcessBlockNoVerifyAnySig")
defer span.End()
if err := helpers.BeaconBlockIsNil(signed); err != nil {
if err := wrapper.BeaconBlockIsNil(signed); err != nil {
return nil, nil, err
}
@@ -223,7 +223,7 @@ func ProcessOperationsNoVerifyAttsSigs(
signedBeaconBlock interfaces.SignedBeaconBlock) (state.BeaconState, error) {
ctx, span := trace.StartSpan(ctx, "core.state.ProcessOperationsNoVerifyAttsSigs")
defer span.End()
if err := helpers.BeaconBlockIsNil(signedBeaconBlock); err != nil {
if err := wrapper.BeaconBlockIsNil(signedBeaconBlock); err != nil {
return nil, err
}
@@ -269,7 +269,7 @@ func ProcessBlockForStateRoot(
) (state.BeaconState, error) {
ctx, span := trace.StartSpan(ctx, "core.state.ProcessBlockForStateRoot")
defer span.End()
if err := helpers.BeaconBlockIsNil(signed); err != nil {
if err := wrapper.BeaconBlockIsNil(signed); err != nil {
return nil, err
}
@@ -371,7 +371,7 @@ func altairOperations(
// This calls phase 0 block operations.
func phase0Operations(
ctx context.Context,
state state.BeaconStateAltair,
state state.BeaconState,
signedBeaconBlock interfaces.SignedBeaconBlock) (state.BeaconState, error) {
state, err := b.ProcessProposerSlashings(ctx, state, signedBeaconBlock.Block().Body().ProposerSlashings(), v.SlashValidator)
if err != nil {

View File

@@ -72,7 +72,10 @@ func InitiateValidatorExit(ctx context.Context, s state.BeaconState, idx types.V
exitQueueChurn := uint64(0)
err = s.ReadFromEveryValidator(func(idx int, val state.ReadOnlyValidator) error {
if val.ExitEpoch() == exitQueueEpoch {
exitQueueChurn++
exitQueueEpoch, err = exitQueueEpoch.SafeAdd(1)
if err != nil {
return err
}
}
return nil
})
@@ -89,10 +92,16 @@ func InitiateValidatorExit(ctx context.Context, s state.BeaconState, idx types.V
}
if exitQueueChurn >= churn {
exitQueueEpoch++
exitQueueEpoch, err = exitQueueEpoch.SafeAdd(1)
if err != nil {
return nil, err
}
}
validator.ExitEpoch = exitQueueEpoch
validator.WithdrawableEpoch = exitQueueEpoch + params.BeaconConfig().MinValidatorWithdrawabilityDelay
validator.WithdrawableEpoch, err = exitQueueEpoch.SafeAddEpoch(params.BeaconConfig().MinValidatorWithdrawabilityDelay)
if err != nil {
return nil, err
}
if err := s.UpdateValidatorAtIndex(idx, validator); err != nil {
return nil, err
}

View File

@@ -99,6 +99,17 @@ func TestInitiateValidatorExit_ChurnOverflow(t *testing.T) {
assert.Equal(t, wantedEpoch, v.ExitEpoch, "Exit epoch did not cover overflow case")
}
func TestInitiateValidatorExit_WithdrawalOverflows(t *testing.T) {
base := &ethpb.BeaconState{Validators: []*ethpb.Validator{
{ExitEpoch: params.BeaconConfig().FarFutureEpoch - 1},
{EffectiveBalance: params.BeaconConfig().EjectionBalance, ExitEpoch: params.BeaconConfig().FarFutureEpoch},
}}
state, err := v1.InitializeFromProto(base)
require.NoError(t, err)
_, err = InitiateValidatorExit(context.Background(), state, 1)
require.ErrorContains(t, "addition overflows", err)
}
func TestSlashValidator_OK(t *testing.T) {
validatorCount := 100
registry := make([]*ethpb.Validator, 0, validatorCount)

View File

@@ -35,7 +35,6 @@ go_library(
],
deps = [
"//beacon-chain/core/blocks:go_default_library",
"//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/db/filters:go_default_library",
"//beacon-chain/db/iface:go_default_library",
"//beacon-chain/state:go_default_library",

View File

@@ -5,8 +5,8 @@ import (
"fmt"
"path"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
"github.com/prysmaticlabs/prysm/io/file"
bolt "go.etcd.io/bbolt"
"go.opencensus.io/trace"
@@ -34,7 +34,7 @@ func (s *Store) Backup(ctx context.Context, outputDir string, permissionOverride
if err != nil {
return err
}
if err := helpers.BeaconBlockIsNil(head); err != nil {
if err := wrapper.BeaconBlockIsNil(head); err != nil {
return err
}
// Ensure the backups directory exists.

View File

@@ -4,9 +4,9 @@ import (
"bytes"
"context"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/db/filters"
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/monitoring/tracing"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
@@ -84,7 +84,7 @@ func (s *Store) updateFinalizedBlockRoots(ctx context.Context, tx *bolt.Tx, chec
tracing.AnnotateError(span, err)
return err
}
if err := helpers.BeaconBlockIsNil(signedBlock); err != nil {
if err := wrapper.BeaconBlockIsNil(signedBlock); err != nil {
tracing.AnnotateError(span, err)
return err
}

View File

@@ -210,12 +210,12 @@ func Test_migrateStateValidators(t *testing.T) {
func Test_migrateAltairStateValidators(t *testing.T) {
tests := []struct {
name string
setup func(t *testing.T, dbStore *Store, state state.BeaconStateAltair, vals []*v1alpha1.Validator)
eval func(t *testing.T, dbStore *Store, state state.BeaconStateAltair, vals []*v1alpha1.Validator)
setup func(t *testing.T, dbStore *Store, state state.BeaconState, vals []*v1alpha1.Validator)
eval func(t *testing.T, dbStore *Store, state state.BeaconState, vals []*v1alpha1.Validator)
}{
{
name: "migrates validators and adds them to new buckets",
setup: func(t *testing.T, dbStore *Store, state state.BeaconStateAltair, vals []*v1alpha1.Validator) {
setup: func(t *testing.T, dbStore *Store, state state.BeaconState, vals []*v1alpha1.Validator) {
// create some new buckets that should be present for this migration
err := dbStore.db.Update(func(tx *bbolt.Tx) error {
_, err := tx.CreateBucketIfNotExists(stateValidatorsBucket)
@@ -226,7 +226,7 @@ func Test_migrateAltairStateValidators(t *testing.T) {
})
assert.NoError(t, err)
},
eval: func(t *testing.T, dbStore *Store, state state.BeaconStateAltair, vals []*v1alpha1.Validator) {
eval: func(t *testing.T, dbStore *Store, state state.BeaconState, vals []*v1alpha1.Validator) {
// check whether the new buckets are present
err := dbStore.db.View(func(tx *bbolt.Tx) error {
valBkt := tx.Bucket(stateValidatorsBucket)

View File

@@ -7,7 +7,6 @@ import (
"github.com/golang/snappy"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/beacon-chain/state/genesis"
state_native "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native"
@@ -664,7 +663,7 @@ func (s *Store) slotByBlockRoot(ctx context.Context, tx *bolt.Tx, blockRoot []by
if err != nil {
return 0, err
}
if err := helpers.BeaconBlockIsNil(wsb); err != nil {
if err := wrapper.BeaconBlockIsNil(wsb); err != nil {
return 0, err
}
return b.Block.Slot, nil

View File

@@ -12,6 +12,7 @@ go_library(
"proposer_boost.go",
"store.go",
"types.go",
"unrealized_justification.go",
],
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/doubly-linked-tree",
visibility = [
@@ -43,6 +44,7 @@ go_test(
"optimistic_sync_test.go",
"proposer_boost_test.go",
"store_test.go",
"unrealized_justification_test.go",
"vote_test.go",
],
embed = [":go_default_library"],
@@ -52,6 +54,7 @@ go_test(
"//consensus-types/primitives:go_default_library",
"//crypto/hash:go_default_library",
"//encoding/bytesutil:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
],

View File

@@ -9,3 +9,6 @@ var errUnknownFinalizedRoot = errors.New("unknown finalized root")
var errUnknownJustifiedRoot = errors.New("unknown justified root")
var errInvalidOptimisticStatus = errors.New("invalid optimistic status")
var errUnknownPayloadHash = errors.New("unknown payload hash")
var errInvalidNilCheckpoint = errors.New("invalid nil checkpoint")
var errInvalidUnrealizedJustifiedEpoch = errors.New("invalid unrealized justified epoch")
var errInvalidUnrealizedFinalizedEpoch = errors.New("invalid unrealized finalized epoch")

View File

@@ -15,7 +15,7 @@ func TestFFGUpdates_OneBranch(t *testing.T) {
f := setup(0, 0)
// The head should always start at the finalized block.
r, err := f.Head(context.Background(), 0, params.BeaconConfig().ZeroHash, balances, 0)
r, err := f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, params.BeaconConfig().ZeroHash, r, "Incorrect head with genesis")
@@ -39,7 +39,7 @@ func TestFFGUpdates_OneBranch(t *testing.T) {
// 2
// |
// 3 <- head
r, err = f.Head(context.Background(), 0, params.BeaconConfig().ZeroHash, balances, 0)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(3), r, "Incorrect head for with justified epoch at 0")
@@ -51,7 +51,8 @@ func TestFFGUpdates_OneBranch(t *testing.T) {
// 2 <- head
// |
// 3
r, err = f.Head(context.Background(), 1, indexToHash(2), balances, 0)
f.store.justifiedEpoch = 1
r, err = f.Head(context.Background(), indexToHash(2), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head with justified epoch at 1")
@@ -63,7 +64,8 @@ func TestFFGUpdates_OneBranch(t *testing.T) {
// 2 <- start
// |
// 3 <- head
r, err = f.Head(context.Background(), 2, indexToHash(3), balances, 1)
f.store.justifiedEpoch = 2
r, err = f.Head(context.Background(), indexToHash(3), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(3), r, "Incorrect head with justified epoch at 2")
}
@@ -72,7 +74,7 @@ func TestFFGUpdates_TwoBranches(t *testing.T) {
balances := []uint64{1, 1}
f := setup(0, 0)
r, err := f.Head(context.Background(), 0, params.BeaconConfig().ZeroHash, balances, 0)
r, err := f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, params.BeaconConfig().ZeroHash, r, "Incorrect head with genesis")
@@ -113,7 +115,7 @@ func TestFFGUpdates_TwoBranches(t *testing.T) {
// 7 8
// | |
// 9 10 <-- head
r, err = f.Head(context.Background(), 0, params.BeaconConfig().ZeroHash, balances, 0)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(10), r, "Incorrect head with justified epoch at 0")
@@ -143,7 +145,7 @@ func TestFFGUpdates_TwoBranches(t *testing.T) {
// 7 8
// | |
// head -> 9 10
r, err = f.Head(context.Background(), 0, params.BeaconConfig().ZeroHash, balances, 0)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(9), r, "Incorrect head with justified epoch at 0")
@@ -173,11 +175,12 @@ func TestFFGUpdates_TwoBranches(t *testing.T) {
// 7 8
// | |
// 9 10 <-- head
r, err = f.Head(context.Background(), 0, params.BeaconConfig().ZeroHash, balances, 0)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(10), r, "Incorrect head with justified epoch at 0")
r, err = f.Head(context.Background(), 1, indexToHash(1), balances, 0)
f.store.justifiedEpoch = 1
r, err = f.Head(context.Background(), indexToHash(1), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(7), r, "Incorrect head with justified epoch at 0")
}

View File

@@ -42,10 +42,8 @@ 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,
justifiedEpoch types.Epoch,
justifiedRoot [32]byte,
justifiedStateBalances []uint64,
finalizedEpoch types.Epoch,
) ([32]byte, error) {
ctx, span := trace.StartSpan(ctx, "doublyLinkedForkchoice.Head")
defer span.End()
@@ -58,8 +56,6 @@ func (f *ForkChoice) Head(
f.store.nodesLock.Lock()
defer f.store.nodesLock.Unlock()
f.store.updateCheckpoints(justifiedEpoch, finalizedEpoch)
if err := f.updateBalances(justifiedStateBalances); err != nil {
return [32]byte{}, errors.Wrap(err, "could not update balances")
}
@@ -72,10 +68,9 @@ func (f *ForkChoice) Head(
return [32]byte{}, errors.Wrap(err, "could not apply weight changes")
}
if err := f.store.treeRootNode.updateBestDescendant(ctx, justifiedEpoch, finalizedEpoch); err != nil {
if err := f.store.treeRootNode.updateBestDescendant(ctx, f.store.justifiedEpoch, f.store.finalizedEpoch); err != nil {
return [32]byte{}, errors.Wrap(err, "could not update best descendant")
}
return f.store.head(ctx, justifiedRoot)
}
@@ -362,3 +357,25 @@ func (f *ForkChoice) InsertSlashedIndex(_ context.Context, index types.Validator
node.balance -= f.balances[index]
}
}
// UpdateJustifiedCheckpoint sets the justified epoch to the given one
func (f *ForkChoice) UpdateJustifiedCheckpoint(jc *pbrpc.Checkpoint) error {
if jc == nil {
return errInvalidNilCheckpoint
}
f.store.nodesLock.Lock()
defer f.store.nodesLock.Unlock()
f.store.justifiedEpoch = jc.Epoch
return nil
}
// UpdateFinalizedCheckpoint sets the finalized epoch to the given one
func (f *ForkChoice) UpdateFinalizedCheckpoint(fc *pbrpc.Checkpoint) error {
if fc == nil {
return errInvalidNilCheckpoint
}
f.store.nodesLock.Lock()
defer f.store.nodesLock.Unlock()
f.store.finalizedEpoch = fc.Epoch
return nil
}

View File

@@ -9,6 +9,7 @@ import (
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/crypto/hash"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/testing/assert"
"github.com/prysmaticlabs/prysm/testing/require"
)
@@ -191,28 +192,28 @@ func TestForkChoice_RemoveEquivocating(t *testing.T) {
f := setup(1, 1)
// Insert a block it will be head
require.NoError(t, f.InsertOptimisticBlock(ctx, 1, [32]byte{'a'}, params.BeaconConfig().ZeroHash, [32]byte{'A'}, 1, 1))
head, err := f.Head(ctx, 1, params.BeaconConfig().ZeroHash, []uint64{}, 1)
head, err := f.Head(ctx, params.BeaconConfig().ZeroHash, []uint64{})
require.NoError(t, err)
require.Equal(t, [32]byte{'a'}, head)
// Insert two extra blocks
require.NoError(t, f.InsertOptimisticBlock(ctx, 2, [32]byte{'b'}, [32]byte{'a'}, [32]byte{'B'}, 1, 1))
require.NoError(t, f.InsertOptimisticBlock(ctx, 3, [32]byte{'c'}, [32]byte{'a'}, [32]byte{'C'}, 1, 1))
head, err = f.Head(ctx, 1, params.BeaconConfig().ZeroHash, []uint64{}, 1)
head, err = f.Head(ctx, params.BeaconConfig().ZeroHash, []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, 1, params.BeaconConfig().ZeroHash, []uint64{100, 200, 200, 300}, 1)
head, err = f.Head(ctx, params.BeaconConfig().ZeroHash, []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, 1, params.BeaconConfig().ZeroHash, []uint64{100, 200, 200, 300}, 1)
head, err = f.Head(ctx, params.BeaconConfig().ZeroHash, []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)
@@ -221,7 +222,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, 1, params.BeaconConfig().ZeroHash, []uint64{100, 200, 200, 300}, 1)
head, err = f.Head(ctx, params.BeaconConfig().ZeroHash, []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)
@@ -238,3 +239,15 @@ func indexToHash(i uint64) [32]byte {
binary.LittleEndian.PutUint64(b[:], i)
return hash.Hash(b[:])
}
func TestStore_UpdateCheckpoints(t *testing.T) {
f := setup(1, 1)
jr := [32]byte{'j'}
fr := [32]byte{'f'}
jc := &ethpb.Checkpoint{Root: jr[:], Epoch: 3}
fc := &ethpb.Checkpoint{Root: fr[:], Epoch: 2}
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)
}

View File

@@ -14,7 +14,7 @@ func TestNoVote_CanFindHead(t *testing.T) {
f := setup(1, 1)
// The head should always start at the finalized block.
r, err := f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err := f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
if r != params.BeaconConfig().ZeroHash {
t.Errorf("Incorrect head with genesis")
@@ -25,7 +25,7 @@ func TestNoVote_CanFindHead(t *testing.T) {
// /
// 2 <- head
require.NoError(t, f.InsertOptimisticBlock(context.Background(), 0, indexToHash(2), params.BeaconConfig().ZeroHash, params.BeaconConfig().ZeroHash, 1, 1))
r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -34,7 +34,7 @@ func TestNoVote_CanFindHead(t *testing.T) {
// / \
// head -> 2 1
require.NoError(t, f.InsertOptimisticBlock(context.Background(), 0, indexToHash(1), params.BeaconConfig().ZeroHash, params.BeaconConfig().ZeroHash, 1, 1))
r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -45,7 +45,7 @@ func TestNoVote_CanFindHead(t *testing.T) {
// |
// 3
require.NoError(t, f.InsertOptimisticBlock(context.Background(), 0, indexToHash(3), indexToHash(1), params.BeaconConfig().ZeroHash, 1, 1))
r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -56,7 +56,7 @@ func TestNoVote_CanFindHead(t *testing.T) {
// | |
// head -> 4 3
require.NoError(t, f.InsertOptimisticBlock(context.Background(), 0, indexToHash(4), indexToHash(2), params.BeaconConfig().ZeroHash, 1, 1))
r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(4), r, "Incorrect head for with justified epoch at 1")
@@ -69,7 +69,7 @@ func TestNoVote_CanFindHead(t *testing.T) {
// |
// 5 <- justified epoch = 2
require.NoError(t, f.InsertOptimisticBlock(context.Background(), 0, indexToHash(5), indexToHash(4), params.BeaconConfig().ZeroHash, 2, 1))
r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(4), r, "Incorrect head for with justified epoch at 1")
@@ -81,7 +81,7 @@ func TestNoVote_CanFindHead(t *testing.T) {
// head -> 4 3
// |
// 5 <- starting from 5 with justified epoch 0 should error
_, err = f.Head(context.Background(), 1, indexToHash(5), balances, 1)
_, err = f.Head(context.Background(), indexToHash(5), balances)
wanted := "head at slot 0 with weight 0 is not eligible, finalizedEpoch 1 != 1, justifiedEpoch 2 != 1"
require.ErrorContains(t, wanted, err)
@@ -93,7 +93,8 @@ func TestNoVote_CanFindHead(t *testing.T) {
// 4 3
// |
// 5 <- head
r, err = f.Head(context.Background(), 2, indexToHash(5), balances, 1)
f.store.justifiedEpoch = 2
r, err = f.Head(context.Background(), indexToHash(5), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(5), r, "Incorrect head for with justified epoch at 2")
@@ -108,7 +109,7 @@ func TestNoVote_CanFindHead(t *testing.T) {
// |
// 6 <- head
require.NoError(t, f.InsertOptimisticBlock(context.Background(), 0, indexToHash(6), indexToHash(5), params.BeaconConfig().ZeroHash, 2, 1))
r, err = f.Head(context.Background(), 2, indexToHash(5), balances, 1)
r, err = f.Head(context.Background(), indexToHash(5), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(6), r, "Incorrect head for with justified epoch at 2")
}

View File

@@ -35,7 +35,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
f := setup(jEpoch, fEpoch)
// The head should always start at the finalized block.
headRoot, err := f.Head(ctx, jEpoch, zeroHash, balances, fEpoch)
headRoot, err := f.Head(ctx, zeroHash, 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) {
),
)
f.ProcessAttestation(ctx, []uint64{0}, newRoot, fEpoch)
headRoot, err = f.Head(ctx, jEpoch, zeroHash, balances, fEpoch)
headRoot, err = f.Head(ctx, zeroHash, 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) {
),
)
f.ProcessAttestation(ctx, []uint64{1}, newRoot, fEpoch)
headRoot, err = f.Head(ctx, jEpoch, zeroHash, balances, fEpoch)
headRoot, err = f.Head(ctx, zeroHash, 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) {
),
)
f.ProcessAttestation(ctx, []uint64{2}, newRoot, fEpoch)
headRoot, err = f.Head(ctx, jEpoch, zeroHash, balances, fEpoch)
headRoot, err = f.Head(ctx, zeroHash, balances)
require.NoError(t, err)
assert.Equal(t, newRoot, headRoot, "Incorrect head for justified epoch at slot 3")
@@ -143,7 +143,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
}
require.NoError(t, f.BoostProposerRoot(ctx, args))
headRoot, err = f.Head(ctx, jEpoch, zeroHash, balances, fEpoch)
headRoot, err = f.Head(ctx, zeroHash, balances)
require.NoError(t, err)
assert.Equal(t, newRoot, headRoot, "Incorrect head for justified epoch at slot 3")
@@ -185,7 +185,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, jEpoch, zeroHash, balances, fEpoch)
headRoot, err = f.Head(ctx, zeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(3), headRoot, "Incorrect head for justified epoch at slot 4")
@@ -194,7 +194,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, jEpoch, zeroHash, balances, fEpoch)
r, err := f.Head(ctx, zeroHash, balances)
require.NoError(t, err)
assert.Equal(t, zeroHash, r, "Incorrect head with genesis")
@@ -219,7 +219,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
fEpoch,
),
)
r, err = f.Head(ctx, jEpoch, zeroHash, balances, fEpoch)
r, err = f.Head(ctx, zeroHash, balances)
require.NoError(t, err)
assert.Equal(t, honestBlock, r, "Incorrect head for justified epoch at slot 2")
@@ -238,7 +238,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
)
// Ensure the head is C, the honest block.
r, err = f.Head(ctx, jEpoch, zeroHash, balances, fEpoch)
r, err = f.Head(ctx, zeroHash, balances)
require.NoError(t, err)
assert.Equal(t, honestBlock, r, "Incorrect head for justified epoch at slot 2")
@@ -256,7 +256,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
f.ProcessAttestation(ctx, votes, maliciouslyWithheldBlock, fEpoch)
// Ensure the head is STILL C, the honest block, as the honest block had proposer boost.
r, err = f.Head(ctx, jEpoch, zeroHash, balances, fEpoch)
r, err = f.Head(ctx, zeroHash, balances)
require.NoError(t, err)
assert.Equal(t, honestBlock, r, "Incorrect head for justified epoch at slot 2")
})
@@ -264,7 +264,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, jEpoch, zeroHash, balances, fEpoch)
r, err := f.Head(ctx, zeroHash, balances)
require.NoError(t, err)
assert.Equal(t, zeroHash, r, "Incorrect head with genesis")
@@ -291,7 +291,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
)
// Ensure C is the head.
r, err = f.Head(ctx, jEpoch, zeroHash, balances, fEpoch)
r, err = f.Head(ctx, zeroHash, balances)
require.NoError(t, err)
assert.Equal(t, honestBlock, r, "Incorrect head for justified epoch at slot 2")
@@ -310,7 +310,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
)
// Ensure C is still the head after the malicious proposer reveals their block.
r, err = f.Head(ctx, jEpoch, zeroHash, balances, fEpoch)
r, err = f.Head(ctx, zeroHash, balances)
require.NoError(t, err)
assert.Equal(t, honestBlock, r, "Incorrect head for justified epoch at slot 2")
@@ -329,7 +329,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, jEpoch, zeroHash, balances, fEpoch)
r, err = f.Head(ctx, zeroHash, balances)
require.NoError(t, err)
assert.Equal(t, maliciouslyWithheldBlock, r, "Expected B to become the head")
})
@@ -351,7 +351,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
a := zeroHash
// The head should always start at the finalized block.
r, err := f.Head(ctx, jEpoch, zeroHash, balances, fEpoch)
r, err := f.Head(ctx, zeroHash, balances)
require.NoError(t, err)
assert.Equal(t, zeroHash, r, "Incorrect head with genesis")
@@ -370,7 +370,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
)
// Ensure C is the head.
r, err = f.Head(ctx, jEpoch, zeroHash, balances, fEpoch)
r, err = f.Head(ctx, zeroHash, balances)
require.NoError(t, err)
assert.Equal(t, c, r, "Incorrect head for justified epoch at slot 2")
@@ -398,7 +398,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
)
// Ensure C is still the head.
r, err = f.Head(ctx, jEpoch, zeroHash, balances, fEpoch)
r, err = f.Head(ctx, zeroHash, balances)
require.NoError(t, err)
assert.Equal(t, c, r, "Incorrect head for justified epoch at slot 2")
@@ -422,7 +422,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
)
// D cannot win without a boost.
r, err = f.Head(ctx, jEpoch, zeroHash, balances, fEpoch)
r, err = f.Head(ctx, zeroHash, balances)
require.NoError(t, err)
assert.Equal(t, c, r, "Expected C to remain the head")
@@ -436,7 +436,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, jEpoch, zeroHash, balances, fEpoch)
r, err = f.Head(ctx, zeroHash, balances)
require.NoError(t, err)
assert.Equal(t, d, r, "Expected D to become the head")
})

View File

@@ -112,13 +112,15 @@ func (s *Store) insert(ctx context.Context,
parent := s.nodeByRoot[parentRoot]
n := &Node{
slot: slot,
root: root,
parent: parent,
justifiedEpoch: justifiedEpoch,
finalizedEpoch: finalizedEpoch,
optimistic: true,
payloadHash: payloadHash,
slot: slot,
root: root,
parent: parent,
justifiedEpoch: justifiedEpoch,
unrealizedJustifiedEpoch: justifiedEpoch,
finalizedEpoch: finalizedEpoch,
unrealizedFinalizedEpoch: finalizedEpoch,
optimistic: true,
payloadHash: payloadHash,
}
s.nodeByPayload[payloadHash] = n
@@ -143,12 +145,6 @@ func (s *Store) insert(ctx context.Context,
return nil
}
// updateCheckpoints Update the justified / finalized epochs in store if necessary.
func (s *Store) updateCheckpoints(justifiedEpoch, finalizedEpoch types.Epoch) {
s.justifiedEpoch = justifiedEpoch
s.finalizedEpoch = finalizedEpoch
}
// pruneFinalizedNodeByRootMap prunes the `nodeByRoot` map
// starting from `node` down to the finalized Node or to a leaf of the Fork
// choice store. This method assumes a lock on nodesLock.

View File

@@ -121,15 +121,6 @@ func TestStore_Insert(t *testing.T) {
assert.Equal(t, indexToHash(100), child.root, "Incorrect root")
}
func TestStore_updateCheckpoints(t *testing.T) {
f := setup(0, 0)
s := f.store
s.updateCheckpoints(1, 1)
assert.Equal(t, types.Epoch(1), s.justifiedEpoch, "Did not update justified epoch")
assert.Equal(t, types.Epoch(1), s.finalizedEpoch, "Did not update finalized epoch")
}
func TestStore_Prune_LessThanThreshold(t *testing.T) {
// Define 100 nodes in store.
numOfNodes := uint64(100)

View File

@@ -35,17 +35,19 @@ type Store struct {
// Node defines the individual block which includes its block parent, ancestor and how much weight accounted for it.
// This is used as an array based stateful DAG for efficient fork choice look up.
type Node struct {
slot types.Slot // slot of the block converted to the node.
root [fieldparams.RootLength]byte // root of the block converted to the node.
payloadHash [fieldparams.RootLength]byte // payloadHash of the block converted to the node.
parent *Node // parent index of this node.
children []*Node // the list of direct children of this Node
justifiedEpoch types.Epoch // justifiedEpoch of this node.
finalizedEpoch types.Epoch // finalizedEpoch of this node.
balance uint64 // the balance that voted for this node directly
weight uint64 // weight of this node: the total balance including children
bestDescendant *Node // bestDescendant node of this node.
optimistic bool // whether the block has been fully validated or not
slot types.Slot // slot of the block converted to the node.
root [fieldparams.RootLength]byte // root of the block converted to the node.
payloadHash [fieldparams.RootLength]byte // payloadHash of the block converted to the node.
parent *Node // parent index of this node.
children []*Node // the list of direct children of this Node
justifiedEpoch types.Epoch // justifiedEpoch of this node.
unrealizedJustifiedEpoch types.Epoch // the epoch that would be justified if the block would be advanced to the next epoch.
finalizedEpoch types.Epoch // finalizedEpoch of this node.
unrealizedFinalizedEpoch types.Epoch // the epoch that would be finalized if the block would be advanced to the next epoch.
balance uint64 // the balance that voted for this node directly
weight uint64 // weight of this node: the total balance including children
bestDescendant *Node // bestDescendant node of this node.
optimistic bool // whether the block has been fully validated or not
}
// Vote defines an individual validator's vote.

View File

@@ -0,0 +1,51 @@
package doublylinkedtree
import types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
func (s *Store) setUnrealizedJustifiedEpoch(root [32]byte, epoch types.Epoch) error {
s.nodesLock.Lock()
defer s.nodesLock.Unlock()
node, ok := s.nodeByRoot[root]
if !ok || node == nil {
return ErrNilNode
}
if epoch < node.unrealizedJustifiedEpoch {
return errInvalidUnrealizedJustifiedEpoch
}
node.unrealizedJustifiedEpoch = epoch
return nil
}
func (s *Store) setUnrealizedFinalizedEpoch(root [32]byte, epoch types.Epoch) error {
s.nodesLock.Lock()
defer s.nodesLock.Unlock()
node, ok := s.nodeByRoot[root]
if !ok || node == nil {
return ErrNilNode
}
if epoch < node.unrealizedFinalizedEpoch {
return errInvalidUnrealizedFinalizedEpoch
}
node.unrealizedFinalizedEpoch = epoch
return nil
}
// UpdateUnrealizedCheckpoints "realizes" the unrealized justified and finalized
// epochs stored within nodes. It should be called at the beginning of each
// epoch
func (f *ForkChoice) UpdateUnrealizedCheckpoints() {
f.store.nodesLock.Lock()
defer f.store.nodesLock.Unlock()
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.finalizedEpoch > f.store.finalizedEpoch {
f.store.finalizedEpoch = node.finalizedEpoch
}
}
}

View File

@@ -0,0 +1,191 @@
package doublylinkedtree
import (
"context"
"testing"
"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"
)
func TestStore_SetUnrealizedEpochs(t *testing.T) {
f := setup(1, 1)
ctx := context.Background()
require.NoError(t, f.InsertOptimisticBlock(ctx, 100, [32]byte{'a'}, params.BeaconConfig().ZeroHash, [32]byte{'A'}, 1, 1))
require.NoError(t, f.InsertOptimisticBlock(ctx, 101, [32]byte{'b'}, [32]byte{'a'}, [32]byte{'B'}, 1, 1))
require.NoError(t, f.InsertOptimisticBlock(ctx, 102, [32]byte{'c'}, [32]byte{'b'}, [32]byte{'C'}, 1, 1))
f.store.nodesLock.RLock()
require.Equal(t, types.Epoch(1), f.store.nodeByRoot[[32]byte{'b'}].unrealizedJustifiedEpoch)
require.Equal(t, types.Epoch(1), f.store.nodeByRoot[[32]byte{'b'}].unrealizedFinalizedEpoch)
f.store.nodesLock.RUnlock()
require.NoError(t, f.store.setUnrealizedJustifiedEpoch([32]byte{'b'}, 2))
require.NoError(t, f.store.setUnrealizedFinalizedEpoch([32]byte{'b'}, 2))
f.store.nodesLock.RLock()
require.Equal(t, types.Epoch(2), f.store.nodeByRoot[[32]byte{'b'}].unrealizedJustifiedEpoch)
require.Equal(t, types.Epoch(2), f.store.nodeByRoot[[32]byte{'b'}].unrealizedFinalizedEpoch)
f.store.nodesLock.RUnlock()
require.ErrorIs(t, errInvalidUnrealizedJustifiedEpoch, f.store.setUnrealizedJustifiedEpoch([32]byte{'b'}, 0))
require.ErrorIs(t, errInvalidUnrealizedFinalizedEpoch, f.store.setUnrealizedFinalizedEpoch([32]byte{'b'}, 0))
}
func TestStore_UpdateUnrealizedCheckpoints(t *testing.T) {
f := setup(1, 1)
ctx := context.Background()
require.NoError(t, f.InsertOptimisticBlock(ctx, 100, [32]byte{'a'}, params.BeaconConfig().ZeroHash, [32]byte{'A'}, 1, 1))
require.NoError(t, f.InsertOptimisticBlock(ctx, 101, [32]byte{'b'}, [32]byte{'a'}, [32]byte{'B'}, 1, 1))
require.NoError(t, f.InsertOptimisticBlock(ctx, 102, [32]byte{'c'}, [32]byte{'b'}, [32]byte{'C'}, 1, 1))
}
//
// Epoch 2 | Epoch 3
// |
// C |
// / |
// A <-- B |
// \ |
// ---- D
//
// B is the first block that justifies A.
//
func TestStore_LongFork(t *testing.T) {
f := setup(1, 1)
ctx := context.Background()
require.NoError(t, f.InsertOptimisticBlock(ctx, 100, [32]byte{'a'}, params.BeaconConfig().ZeroHash, [32]byte{'A'}, 1, 1))
require.NoError(t, f.InsertOptimisticBlock(ctx, 101, [32]byte{'b'}, [32]byte{'a'}, [32]byte{'B'}, 1, 1))
require.NoError(t, f.store.setUnrealizedJustifiedEpoch([32]byte{'b'}, 2))
require.NoError(t, f.InsertOptimisticBlock(ctx, 102, [32]byte{'c'}, [32]byte{'b'}, [32]byte{'C'}, 1, 1))
require.NoError(t, f.store.setUnrealizedJustifiedEpoch([32]byte{'c'}, 2))
// 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})
require.NoError(t, err)
require.Equal(t, [32]byte{'c'}, headRoot)
// D is head even though its weight is lower.
hr := [32]byte{'d'}
require.NoError(t, f.InsertOptimisticBlock(ctx, 103, hr, [32]byte{'b'}, [32]byte{'D'}, 2, 1))
require.NoError(t, f.UpdateJustifiedCheckpoint(&ethpb.Checkpoint{Epoch: 2, Root: hr[:]}))
headRoot, err = f.Head(ctx, [32]byte{}, []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)
require.Equal(t, uint64(100), f.store.nodeByRoot[[32]byte{'c'}].weight)
// Update unrealized justification, c becomes head
f.UpdateUnrealizedCheckpoints()
headRoot, err = f.Head(ctx, [32]byte{}, []uint64{100})
require.NoError(t, err)
require.Equal(t, [32]byte{'c'}, headRoot)
}
//
//
// Epoch 1 Epoch 2 Epoch 3
// | |
// | |
// A <-- B <-- C <-- D <-- E <-- F <-- G <-- H |
// | \ |
// | --------------- I
// | |
//
// E justifies A. G justifies E.
//
func TestStore_NoDeadLock(t *testing.T) {
f := setup(0, 0)
ctx := context.Background()
// Epoch 1 blocks
require.NoError(t, f.InsertOptimisticBlock(ctx, 100, [32]byte{'a'}, params.BeaconConfig().ZeroHash, [32]byte{'A'}, 0, 0))
require.NoError(t, f.InsertOptimisticBlock(ctx, 101, [32]byte{'b'}, [32]byte{'a'}, [32]byte{'B'}, 0, 0))
require.NoError(t, f.InsertOptimisticBlock(ctx, 102, [32]byte{'c'}, [32]byte{'b'}, [32]byte{'C'}, 0, 0))
require.NoError(t, f.InsertOptimisticBlock(ctx, 103, [32]byte{'d'}, [32]byte{'c'}, [32]byte{'D'}, 0, 0))
// Epoch 2 Blocks
require.NoError(t, f.InsertOptimisticBlock(ctx, 104, [32]byte{'e'}, [32]byte{'d'}, [32]byte{'E'}, 0, 0))
require.NoError(t, f.store.setUnrealizedJustifiedEpoch([32]byte{'e'}, 1))
require.NoError(t, f.InsertOptimisticBlock(ctx, 105, [32]byte{'f'}, [32]byte{'e'}, [32]byte{'F'}, 0, 0))
require.NoError(t, f.store.setUnrealizedJustifiedEpoch([32]byte{'f'}, 1))
require.NoError(t, f.InsertOptimisticBlock(ctx, 106, [32]byte{'g'}, [32]byte{'f'}, [32]byte{'G'}, 0, 0))
require.NoError(t, f.store.setUnrealizedJustifiedEpoch([32]byte{'g'}, 2))
require.NoError(t, f.store.setUnrealizedFinalizedEpoch([32]byte{'g'}, 1))
require.NoError(t, f.InsertOptimisticBlock(ctx, 107, [32]byte{'h'}, [32]byte{'g'}, [32]byte{'H'}, 0, 0))
require.NoError(t, f.store.setUnrealizedJustifiedEpoch([32]byte{'h'}, 2))
require.NoError(t, f.store.setUnrealizedFinalizedEpoch([32]byte{'h'}, 1))
// Add an attestation for h
f.ProcessAttestation(ctx, []uint64{0}, [32]byte{'h'}, 1)
// Epoch 3
// Current Head is H
headRoot, err := f.Head(ctx, [32]byte{}, []uint64{100})
require.NoError(t, err)
require.Equal(t, [32]byte{'h'}, headRoot)
require.Equal(t, types.Epoch(0), f.JustifiedEpoch())
// Insert Block I, it becomes Head
hr := [32]byte{'i'}
require.NoError(t, f.InsertOptimisticBlock(ctx, 108, hr, [32]byte{'f'}, [32]byte{'I'}, 1, 0))
require.NoError(t, f.UpdateJustifiedCheckpoint(&ethpb.Checkpoint{Epoch: 1, Root: hr[:]}))
headRoot, err = f.Head(ctx, [32]byte{}, []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())
// Realized Justified checkpoints, H becomes head
f.UpdateUnrealizedCheckpoints()
headRoot, err = f.Head(ctx, [32]byte{}, []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())
}
// Epoch 1 | Epoch 2
// |
// -- D (late)
// / |
// A <- B <- C |
// \ |
// -- -- -- E <- F <- G <- H
// |
//
// D justifies and comes late.
//
func TestStore_ForkNextEpoch(t *testing.T) {
f := setup(0, 0)
ctx := context.Background()
// Epoch 1 blocks (D does not arrive)
require.NoError(t, f.InsertOptimisticBlock(ctx, 100, [32]byte{'a'}, params.BeaconConfig().ZeroHash, [32]byte{'A'}, 0, 0))
require.NoError(t, f.InsertOptimisticBlock(ctx, 101, [32]byte{'b'}, [32]byte{'a'}, [32]byte{'B'}, 0, 0))
require.NoError(t, f.InsertOptimisticBlock(ctx, 102, [32]byte{'c'}, [32]byte{'b'}, [32]byte{'C'}, 0, 0))
// Epoch 2 blocks
require.NoError(t, f.InsertOptimisticBlock(ctx, 104, [32]byte{'e'}, [32]byte{'c'}, [32]byte{'E'}, 0, 0))
require.NoError(t, f.InsertOptimisticBlock(ctx, 105, [32]byte{'f'}, [32]byte{'e'}, [32]byte{'F'}, 0, 0))
require.NoError(t, f.InsertOptimisticBlock(ctx, 106, [32]byte{'g'}, [32]byte{'f'}, [32]byte{'G'}, 0, 0))
require.NoError(t, f.InsertOptimisticBlock(ctx, 107, [32]byte{'h'}, [32]byte{'g'}, [32]byte{'H'}, 0, 0))
// 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})
require.NoError(t, err)
require.Equal(t, [32]byte{'h'}, headRoot)
require.Equal(t, types.Epoch(0), f.JustifiedEpoch())
// D arrives late, D is head
require.NoError(t, f.InsertOptimisticBlock(ctx, 103, [32]byte{'d'}, [32]byte{'c'}, [32]byte{'D'}, 0, 0))
require.NoError(t, f.store.setUnrealizedJustifiedEpoch([32]byte{'d'}, 1))
f.UpdateUnrealizedCheckpoints()
headRoot, err = f.Head(ctx, [32]byte{}, []uint64{100})
require.NoError(t, err)
require.Equal(t, [32]byte{'d'}, headRoot)
require.Equal(t, types.Epoch(1), f.JustifiedEpoch())
require.Equal(t, uint64(0), f.store.nodeByRoot[[32]byte{'d'}].weight)
require.Equal(t, uint64(100), f.store.nodeByRoot[[32]byte{'h'}].weight)
}

View File

@@ -14,7 +14,7 @@ func TestVotes_CanFindHead(t *testing.T) {
f := setup(1, 1)
// The head should always start at the finalized block.
r, err := f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err := f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, params.BeaconConfig().ZeroHash, r, "Incorrect head with genesis")
@@ -24,7 +24,7 @@ func TestVotes_CanFindHead(t *testing.T) {
// 2 <- head
require.NoError(t, f.InsertOptimisticBlock(context.Background(), 0, indexToHash(2), params.BeaconConfig().ZeroHash, params.BeaconConfig().ZeroHash, 1, 1))
r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -34,7 +34,7 @@ func TestVotes_CanFindHead(t *testing.T) {
// head -> 2 1
require.NoError(t, f.InsertOptimisticBlock(context.Background(), 0, indexToHash(1), params.BeaconConfig().ZeroHash, params.BeaconConfig().ZeroHash, 1, 1))
r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -43,7 +43,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(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(1), r, "Incorrect head for with justified epoch at 1")
@@ -52,7 +52,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(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -64,7 +64,7 @@ func TestVotes_CanFindHead(t *testing.T) {
// 3
require.NoError(t, f.InsertOptimisticBlock(context.Background(), 0, indexToHash(3), indexToHash(1), params.BeaconConfig().ZeroHash, 1, 1))
r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -75,7 +75,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(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -86,7 +86,7 @@ func TestVotes_CanFindHead(t *testing.T) {
// |
// 3 <- head
f.ProcessAttestation(context.Background(), []uint64{1}, indexToHash(1), 3)
r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(3), r, "Incorrect head for with justified epoch at 1")
@@ -100,7 +100,7 @@ func TestVotes_CanFindHead(t *testing.T) {
// 4 <- head
require.NoError(t, f.InsertOptimisticBlock(context.Background(), 0, indexToHash(4), indexToHash(3), params.BeaconConfig().ZeroHash, 1, 1))
r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(4), r, "Incorrect head for with justified epoch at 1")
@@ -116,7 +116,7 @@ func TestVotes_CanFindHead(t *testing.T) {
// 5 <- justified epoch = 2
require.NoError(t, f.InsertOptimisticBlock(context.Background(), 0, indexToHash(5), indexToHash(4), params.BeaconConfig().ZeroHash, 2, 2))
r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(4), r, "Incorrect head for with justified epoch at 1")
@@ -167,11 +167,11 @@ func TestVotes_CanFindHead(t *testing.T) {
require.NoError(t, f.InsertOptimisticBlock(context.Background(), 0, indexToHash(8), indexToHash(7), params.BeaconConfig().ZeroHash, 2, 2))
require.NoError(t, f.InsertOptimisticBlock(context.Background(), 0, indexToHash(9), indexToHash(8), params.BeaconConfig().ZeroHash, 2, 2))
r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(6), r, "Incorrect head for with justified epoch at 1")
// Update fork choice justified epoch to 1 and start block to 5.
// Update fork choice justified epoch to 2 and start block to 5.
// Verify 9 is the head:
// 0
// / \
@@ -188,7 +188,9 @@ func TestVotes_CanFindHead(t *testing.T) {
// 8
// |
// 9 <- head
r, err = f.Head(context.Background(), 2, indexToHash(5), balances, 2)
f.store.justifiedEpoch = 2
f.store.finalizedEpoch = 2
r, err = f.Head(context.Background(), indexToHash(5), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(9), r, "Incorrect head for with justified epoch at 2")
@@ -212,7 +214,7 @@ func TestVotes_CanFindHead(t *testing.T) {
f.ProcessAttestation(context.Background(), []uint64{0, 1}, indexToHash(9), 5)
require.NoError(t, f.InsertOptimisticBlock(context.Background(), 0, indexToHash(10), indexToHash(8), params.BeaconConfig().ZeroHash, 2, 2))
r, err = f.Head(context.Background(), 2, indexToHash(5), balances, 2)
r, err = f.Head(context.Background(), indexToHash(5), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(9), r, "Incorrect head for with justified epoch at 2")
@@ -221,28 +223,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(), 2, indexToHash(5), balances, 2)
r, err = f.Head(context.Background(), indexToHash(5), 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(), 2, indexToHash(5), balances, 2)
r, err = f.Head(context.Background(), indexToHash(5), 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(), 2, indexToHash(5), balances, 2)
r, err = f.Head(context.Background(), indexToHash(5), 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(), 2, indexToHash(5), balances, 2)
r, err = f.Head(context.Background(), indexToHash(5), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(9), r, "Incorrect head for with justified epoch at 1")
@@ -251,7 +253,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(), 2, indexToHash(5), balances, 2)
r, err = f.Head(context.Background(), indexToHash(5), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(9), r, "Incorrect head for with justified epoch at 2")
@@ -275,7 +277,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(), 2, indexToHash(5), balances, 2)
r, err = f.Head(context.Background(), indexToHash(5), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(9), r, "Incorrect head for with justified epoch at 2")
@@ -291,7 +293,7 @@ func TestVotes_CanFindHead(t *testing.T) {
// head-> 11
require.NoError(t, f.InsertOptimisticBlock(context.Background(), 0, indexToHash(11), indexToHash(9), params.BeaconConfig().ZeroHash, 2, 2))
r, err = f.Head(context.Background(), 2, indexToHash(5), balances, 2)
r, err = f.Head(context.Background(), indexToHash(5), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(11), r, "Incorrect head for with justified epoch at 2")
}

View File

@@ -6,7 +6,7 @@ import (
forkchoicetypes "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/types"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
pbrpc "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
// ForkChoicer represents the full fork choice interface composed of all the sub-interfaces.
@@ -22,7 +22,7 @@ type ForkChoicer interface {
// HeadRetriever retrieves head root and optimistic info of the current chain.
type HeadRetriever interface {
Head(context.Context, types.Epoch, [32]byte, []uint64, types.Epoch) ([32]byte, error)
Head(context.Context, [32]byte, []uint64) ([32]byte, error)
Tips() ([][32]byte, []types.Slot)
IsOptimistic(root [32]byte) (bool, error)
}
@@ -65,7 +65,7 @@ type Getter interface {
IsCanonical(root [32]byte) bool
FinalizedEpoch() types.Epoch
JustifiedEpoch() types.Epoch
ForkChoiceNodes() []*pbrpc.ForkChoiceNode
ForkChoiceNodes() []*ethpb.ForkChoiceNode
NodeCount() int
}
@@ -73,4 +73,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
}

View File

@@ -12,6 +12,7 @@ go_library(
"proposer_boost.go",
"store.go",
"types.go",
"unrealized_justification.go",
],
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray",
visibility = [
@@ -44,6 +45,7 @@ go_test(
"optimistic_sync_test.go",
"proposer_boost_test.go",
"store_test.go",
"unrealized_justification_test.go",
"vote_test.go",
],
embed = [":go_default_library"],
@@ -53,6 +55,7 @@ go_test(
"//consensus-types/primitives:go_default_library",
"//crypto/hash:go_default_library",
"//encoding/bytesutil:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
],

View File

@@ -13,3 +13,6 @@ var errInvalidParentDelta = errors.New("parent delta is invalid")
var errInvalidNodeDelta = errors.New("node delta is invalid")
var errInvalidDeltaLength = errors.New("delta length is invalid")
var errInvalidOptimisticStatus = errors.New("invalid optimistic status")
var errInvalidNilCheckpoint = errors.New("invalid nil checkpoint")
var errInvalidUnrealizedJustifiedEpoch = errors.New("invalid unrealized justified epoch")
var errInvalidUnrealizedFinalizedEpoch = errors.New("invalid unrealized finalized epoch")

View File

@@ -15,7 +15,7 @@ func TestFFGUpdates_OneBranch(t *testing.T) {
f := setup(0, 0)
// The head should always start at the finalized block.
r, err := f.Head(context.Background(), 0, params.BeaconConfig().ZeroHash, balances, 0)
r, err := f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, params.BeaconConfig().ZeroHash, r, "Incorrect head with genesis")
@@ -39,7 +39,7 @@ func TestFFGUpdates_OneBranch(t *testing.T) {
// 2
// |
// 3 <- head
r, err = f.Head(context.Background(), 0, params.BeaconConfig().ZeroHash, balances, 0)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(3), r, "Incorrect head for with justified epoch at 0")
@@ -51,7 +51,8 @@ func TestFFGUpdates_OneBranch(t *testing.T) {
// 2 <- head
// |
// 3
r, err = f.Head(context.Background(), 1, indexToHash(2), balances, 0)
f.store.justifiedEpoch = 1
r, err = f.Head(context.Background(), indexToHash(2), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head with justified epoch at 1")
@@ -63,7 +64,8 @@ func TestFFGUpdates_OneBranch(t *testing.T) {
// 2 <- start
// |
// 3 <- head
r, err = f.Head(context.Background(), 2, indexToHash(3), balances, 1)
f.store.justifiedEpoch = 2
r, err = f.Head(context.Background(), indexToHash(3), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(3), r, "Incorrect head with justified epoch at 2")
}
@@ -72,7 +74,7 @@ func TestFFGUpdates_TwoBranches(t *testing.T) {
balances := []uint64{1, 1}
f := setup(0, 0)
r, err := f.Head(context.Background(), 0, params.BeaconConfig().ZeroHash, balances, 0)
r, err := f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, params.BeaconConfig().ZeroHash, r, "Incorrect head with genesis")
@@ -113,7 +115,7 @@ func TestFFGUpdates_TwoBranches(t *testing.T) {
// 7 8
// | |
// 9 10 <-- head
r, err = f.Head(context.Background(), 0, params.BeaconConfig().ZeroHash, balances, 0)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(10), r, "Incorrect head with justified epoch at 0")
@@ -143,7 +145,7 @@ func TestFFGUpdates_TwoBranches(t *testing.T) {
// 7 8
// | |
// head -> 9 10
r, err = f.Head(context.Background(), 0, params.BeaconConfig().ZeroHash, balances, 0)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(9), r, "Incorrect head with justified epoch at 0")
@@ -173,17 +175,18 @@ func TestFFGUpdates_TwoBranches(t *testing.T) {
// 7 8
// | |
// 9 10 <-- head
r, err = f.Head(context.Background(), 0, params.BeaconConfig().ZeroHash, balances, 0)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(10), r, "Incorrect head with justified epoch at 0")
r, err = f.Head(context.Background(), 1, indexToHash(1), balances, 0)
f.store.justifiedEpoch = 1
r, err = f.Head(context.Background(), indexToHash(1), 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, params.BeaconConfig().ZeroHash)
f := New(justifiedEpoch, finalizedEpoch)
f.store.nodesIndices[params.BeaconConfig().ZeroHash] = 0
f.store.nodes = append(f.store.nodes, &Node{
slot: 0,

View File

@@ -14,7 +14,7 @@ func TestNoVote_CanFindHead(t *testing.T) {
f := setup(1, 1)
// The head should always start at the finalized block.
r, err := f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err := f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
if r != params.BeaconConfig().ZeroHash {
t.Errorf("Incorrect head with genesis")
@@ -25,7 +25,7 @@ func TestNoVote_CanFindHead(t *testing.T) {
// /
// 2 <- head
require.NoError(t, f.InsertOptimisticBlock(context.Background(), 0, indexToHash(2), params.BeaconConfig().ZeroHash, params.BeaconConfig().ZeroHash, 1, 1))
r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -34,7 +34,7 @@ func TestNoVote_CanFindHead(t *testing.T) {
// / \
// head -> 2 1
require.NoError(t, f.InsertOptimisticBlock(context.Background(), 0, indexToHash(1), params.BeaconConfig().ZeroHash, params.BeaconConfig().ZeroHash, 1, 1))
r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -45,7 +45,7 @@ func TestNoVote_CanFindHead(t *testing.T) {
// |
// 3
require.NoError(t, f.InsertOptimisticBlock(context.Background(), 0, indexToHash(3), indexToHash(1), params.BeaconConfig().ZeroHash, 1, 1))
r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -56,7 +56,7 @@ func TestNoVote_CanFindHead(t *testing.T) {
// | |
// head -> 4 3
require.NoError(t, f.InsertOptimisticBlock(context.Background(), 0, indexToHash(4), indexToHash(2), params.BeaconConfig().ZeroHash, 1, 1))
r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(4), r, "Incorrect head for with justified epoch at 1")
@@ -69,7 +69,7 @@ func TestNoVote_CanFindHead(t *testing.T) {
// |
// 5 <- justified epoch = 2
require.NoError(t, f.InsertOptimisticBlock(context.Background(), 0, indexToHash(5), indexToHash(4), params.BeaconConfig().ZeroHash, 2, 1))
r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(4), r, "Incorrect head for with justified epoch at 1")
@@ -81,7 +81,7 @@ func TestNoVote_CanFindHead(t *testing.T) {
// head -> 4 3
// |
// 5 <- starting from 5 with justified epoch 0 should error
_, err = f.Head(context.Background(), 1, indexToHash(5), balances, 1)
_, err = f.Head(context.Background(), indexToHash(5), balances)
wanted := "head at slot 0 with weight 0 is not eligible, finalizedEpoch 1 != 1, justifiedEpoch 2 != 1"
require.ErrorContains(t, wanted, err)
@@ -93,7 +93,8 @@ func TestNoVote_CanFindHead(t *testing.T) {
// 4 3
// |
// 5 <- head
r, err = f.Head(context.Background(), 2, indexToHash(5), balances, 1)
f.store.justifiedEpoch = 2
r, err = f.Head(context.Background(), indexToHash(5), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(5), r, "Incorrect head for with justified epoch at 2")
@@ -108,7 +109,7 @@ func TestNoVote_CanFindHead(t *testing.T) {
// |
// 6 <- head
require.NoError(t, f.InsertOptimisticBlock(context.Background(), 0, indexToHash(6), indexToHash(5), params.BeaconConfig().ZeroHash, 2, 1))
r, err = f.Head(context.Background(), 2, indexToHash(5), balances, 1)
r, err = f.Head(context.Background(), indexToHash(5), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(6), r, "Incorrect head for with justified epoch at 2")
}

View File

@@ -35,7 +35,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
f := setup(jEpoch, fEpoch)
// The head should always start at the finalized block.
headRoot, err := f.Head(ctx, jEpoch, zeroHash, balances, fEpoch)
headRoot, err := f.Head(ctx, zeroHash, 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) {
),
)
f.ProcessAttestation(ctx, []uint64{0}, newRoot, fEpoch)
headRoot, err = f.Head(ctx, jEpoch, zeroHash, balances, fEpoch)
headRoot, err = f.Head(ctx, zeroHash, 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) {
),
)
f.ProcessAttestation(ctx, []uint64{1}, newRoot, fEpoch)
headRoot, err = f.Head(ctx, jEpoch, zeroHash, balances, fEpoch)
headRoot, err = f.Head(ctx, zeroHash, 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) {
),
)
f.ProcessAttestation(ctx, []uint64{2}, newRoot, fEpoch)
headRoot, err = f.Head(ctx, jEpoch, zeroHash, balances, fEpoch)
headRoot, err = f.Head(ctx, zeroHash, 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, jEpoch, zeroHash, balances, fEpoch)
headRoot, err = f.Head(ctx, zeroHash, 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, jEpoch, zeroHash, balances, fEpoch)
headRoot, err = f.Head(ctx, zeroHash, 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, jEpoch, zeroHash, balances, fEpoch)
r, err := f.Head(ctx, zeroHash, 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) {
fEpoch,
),
)
r, err = f.Head(ctx, jEpoch, zeroHash, balances, fEpoch)
r, err = f.Head(ctx, zeroHash, 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) {
)
// Ensure the head is C, the honest block.
r, err = f.Head(ctx, jEpoch, zeroHash, balances, fEpoch)
r, err = f.Head(ctx, zeroHash, balances)
require.NoError(t, err)
assert.Equal(t, honestBlock, r, "Incorrect head for justified epoch at slot 2")
@@ -250,7 +250,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
f.ProcessAttestation(ctx, votes, maliciouslyWithheldBlock, fEpoch)
// Ensure the head is STILL C, the honest block, as the honest block had proposer boost.
r, err = f.Head(ctx, jEpoch, zeroHash, balances, fEpoch)
r, err = f.Head(ctx, zeroHash, balances)
require.NoError(t, err)
assert.Equal(t, honestBlock, r, "Incorrect head for justified epoch at slot 2")
})
@@ -258,7 +258,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, jEpoch, zeroHash, balances, fEpoch)
r, err := f.Head(ctx, zeroHash, balances)
require.NoError(t, err)
assert.Equal(t, zeroHash, r, "Incorrect head with genesis")
@@ -285,7 +285,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
)
// Ensure C is the head.
r, err = f.Head(ctx, jEpoch, zeroHash, balances, fEpoch)
r, err = f.Head(ctx, zeroHash, balances)
require.NoError(t, err)
assert.Equal(t, honestBlock, r, "Incorrect head for justified epoch at slot 2")
@@ -304,7 +304,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
)
// Ensure C is still the head after the malicious proposer reveals their block.
r, err = f.Head(ctx, jEpoch, zeroHash, balances, fEpoch)
r, err = f.Head(ctx, zeroHash, balances)
require.NoError(t, err)
assert.Equal(t, honestBlock, r, "Incorrect head for justified epoch at slot 2")
@@ -323,7 +323,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, jEpoch, zeroHash, balances, fEpoch)
r, err = f.Head(ctx, zeroHash, balances)
require.NoError(t, err)
assert.Equal(t, maliciouslyWithheldBlock, r, "Expected B to become the head")
})
@@ -345,7 +345,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
a := zeroHash
// The head should always start at the finalized block.
r, err := f.Head(ctx, jEpoch, zeroHash, balances, fEpoch)
r, err := f.Head(ctx, zeroHash, balances)
require.NoError(t, err)
assert.Equal(t, zeroHash, r, "Incorrect head with genesis")
@@ -364,7 +364,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
)
// Ensure C is the head.
r, err = f.Head(ctx, jEpoch, zeroHash, balances, fEpoch)
r, err = f.Head(ctx, zeroHash, balances)
require.NoError(t, err)
assert.Equal(t, c, r, "Incorrect head for justified epoch at slot 2")
@@ -392,7 +392,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
)
// Ensure C is still the head.
r, err = f.Head(ctx, jEpoch, zeroHash, balances, fEpoch)
r, err = f.Head(ctx, zeroHash, balances)
require.NoError(t, err)
assert.Equal(t, c, r, "Incorrect head for justified epoch at slot 2")
@@ -416,7 +416,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
)
// D cannot win without a boost.
r, err = f.Head(ctx, jEpoch, zeroHash, balances, fEpoch)
r, err = f.Head(ctx, zeroHash, balances)
require.NoError(t, err)
assert.Equal(t, c, r, "Expected C to remain the head")
@@ -430,7 +430,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, jEpoch, zeroHash, balances, fEpoch)
r, err = f.Head(ctx, zeroHash, balances)
require.NoError(t, err)
assert.Equal(t, d, r, "Expected D to become the head")
})

View File

@@ -24,11 +24,10 @@ const defaultPruneThreshold = 256
var lastHeadRoot [32]byte
// New initializes a new fork choice store.
func New(justifiedEpoch, finalizedEpoch types.Epoch, finalizedRoot [32]byte) *ForkChoice {
func New(justifiedEpoch, finalizedEpoch types.Epoch) *ForkChoice {
s := &Store{
justifiedEpoch: justifiedEpoch,
finalizedEpoch: finalizedEpoch,
finalizedRoot: finalizedRoot,
proposerBoostRoot: [32]byte{},
nodes: make([]*Node, 0),
nodesIndices: make(map[[32]byte]uint64),
@@ -47,10 +46,8 @@ func New(justifiedEpoch, finalizedEpoch types.Epoch, finalizedRoot [32]byte) *Fo
// It firsts computes validator's balance changes then recalculates block tree from leaves to root.
func (f *ForkChoice) Head(
ctx context.Context,
justifiedEpoch types.Epoch,
justifiedRoot [32]byte,
justifiedStateBalances []uint64,
finalizedEpoch types.Epoch,
) ([32]byte, error) {
ctx, span := trace.StartSpan(ctx, "protoArrayForkChoice.Head")
defer span.End()
@@ -58,7 +55,6 @@ func (f *ForkChoice) Head(
defer f.votesLock.Unlock()
calledHeadCount.Inc()
newBalances := justifiedStateBalances
// Using the write lock here because `updateCanonicalNodes` that gets called subsequently requires a write operation.
@@ -70,7 +66,7 @@ func (f *ForkChoice) Head(
}
f.votes = newVotes
if err := f.store.applyWeightChanges(ctx, justifiedEpoch, finalizedEpoch, newBalances, deltas); err != nil {
if err := f.store.applyWeightChanges(ctx, newBalances, deltas); err != nil {
return [32]byte{}, errors.Wrap(err, "Could not apply score changes")
}
f.balances = newBalances
@@ -337,15 +333,17 @@ func (s *Store) insert(ctx context.Context,
}
n := &Node{
slot: slot,
root: root,
parent: parentIndex,
justifiedEpoch: justifiedEpoch,
finalizedEpoch: finalizedEpoch,
bestChild: NonExistentNode,
bestDescendant: NonExistentNode,
weight: 0,
payloadHash: payloadHash,
slot: slot,
root: root,
parent: parentIndex,
justifiedEpoch: justifiedEpoch,
unrealizedJustifiedEpoch: justifiedEpoch,
finalizedEpoch: finalizedEpoch,
unrealizedFinalizedEpoch: finalizedEpoch,
bestChild: NonExistentNode,
bestDescendant: NonExistentNode,
weight: 0,
payloadHash: payloadHash,
}
s.nodesIndices[root] = index
@@ -371,7 +369,7 @@ func (s *Store) insert(ctx context.Context,
// back propagate the nodes' delta to its parents' delta. After scoring changes,
// the best child is then updated along with the best descendant.
func (s *Store) applyWeightChanges(
ctx context.Context, justifiedEpoch, finalizedEpoch types.Epoch, newBalances []uint64, delta []int,
ctx context.Context, newBalances []uint64, delta []int,
) error {
_, span := trace.StartSpan(ctx, "protoArrayForkChoice.applyWeightChanges")
defer span.End()
@@ -381,12 +379,6 @@ func (s *Store) applyWeightChanges(
return errInvalidDeltaLength
}
// Update the justified / finalized epochs in store if necessary.
if s.justifiedEpoch != justifiedEpoch || s.finalizedEpoch != finalizedEpoch {
s.justifiedEpoch = justifiedEpoch
s.finalizedEpoch = finalizedEpoch
}
// Proposer score defaults to 0.
proposerScore := uint64(0)
@@ -791,3 +783,25 @@ func (f *ForkChoice) InsertSlashedIndex(ctx context.Context, index types.Validat
nodeIndex = node.parent
}
}
// UpdateJustifiedCheckpoint sets the justified epoch to the given one
func (f *ForkChoice) UpdateJustifiedCheckpoint(jc *pbrpc.Checkpoint) error {
if jc == nil {
return errInvalidNilCheckpoint
}
f.store.nodesLock.Lock()
defer f.store.nodesLock.Unlock()
f.store.justifiedEpoch = jc.Epoch
return nil
}
// UpdateFinalizedCheckpoint sets the finalized epoch to the given one
func (f *ForkChoice) UpdateFinalizedCheckpoint(fc *pbrpc.Checkpoint) error {
if fc == nil {
return errInvalidNilCheckpoint
}
f.store.nodesLock.Lock()
defer f.store.nodesLock.Unlock()
f.store.finalizedEpoch = fc.Epoch
return nil
}

View File

@@ -7,6 +7,7 @@ import (
"github.com/prysmaticlabs/prysm/config/params"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/testing/assert"
"github.com/prysmaticlabs/prysm/testing/require"
)
@@ -132,19 +133,10 @@ func TestStore_ApplyScoreChanges_InvalidDeltaLength(t *testing.T) {
s := &Store{}
// This will fail because node indices has length of 0, and delta list has a length of 1.
err := s.applyWeightChanges(context.Background(), 0, 0, []uint64{}, []int{1})
err := s.applyWeightChanges(context.Background(), []uint64{}, []int{1})
assert.ErrorContains(t, errInvalidDeltaLength.Error(), err)
}
func TestStore_ApplyScoreChanges_UpdateEpochs(t *testing.T) {
s := &Store{}
// The justified and finalized epochs in Store should be updated to 1 and 1 given the following input.
require.NoError(t, s.applyWeightChanges(context.Background(), 1, 1, []uint64{}, []int{}))
assert.Equal(t, types.Epoch(1), s.justifiedEpoch, "Did not update justified epoch")
assert.Equal(t, types.Epoch(1), s.finalizedEpoch, "Did not update finalized epoch")
}
func TestStore_ApplyScoreChanges_UpdateWeightsPositiveDelta(t *testing.T) {
// Construct 3 nodes with weight 100 on each node. The 3 nodes linked to each other.
s := &Store{nodes: []*Node{
@@ -154,7 +146,7 @@ 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.
require.NoError(t, s.applyWeightChanges(context.Background(), 0, 0, []uint64{}, []int{1, 1, 1}))
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)
assert.Equal(t, uint64(101), s.nodes[2].weight)
@@ -169,7 +161,7 @@ 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.
require.NoError(t, s.applyWeightChanges(context.Background(), 0, 0, []uint64{}, []int{-1, -1, -1}))
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)
assert.Equal(t, uint64(99), s.nodes[2].weight)
@@ -183,7 +175,7 @@ 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.
require.NoError(t, s.applyWeightChanges(context.Background(), 0, 0, []uint64{}, []int{-100, -50, 150}))
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)
assert.Equal(t, uint64(250), s.nodes[2].weight)
@@ -779,27 +771,27 @@ func TestStore_RemoveEquivocating(t *testing.T) {
f := setup(1, 1)
// Insert a block it will be head
require.NoError(t, f.InsertOptimisticBlock(ctx, 1, [32]byte{'a'}, params.BeaconConfig().ZeroHash, [32]byte{'A'}, 1, 1))
head, err := f.Head(ctx, 1, params.BeaconConfig().ZeroHash, []uint64{}, 1)
head, err := f.Head(ctx, params.BeaconConfig().ZeroHash, []uint64{})
require.NoError(t, err)
require.Equal(t, [32]byte{'a'}, head)
// Insert two extra blocks
require.NoError(t, f.InsertOptimisticBlock(ctx, 2, [32]byte{'b'}, [32]byte{'a'}, [32]byte{'B'}, 1, 1))
require.NoError(t, f.InsertOptimisticBlock(ctx, 3, [32]byte{'c'}, [32]byte{'a'}, [32]byte{'C'}, 1, 1))
head, err = f.Head(ctx, 1, params.BeaconConfig().ZeroHash, []uint64{}, 1)
head, err = f.Head(ctx, params.BeaconConfig().ZeroHash, []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, 1, params.BeaconConfig().ZeroHash, []uint64{100, 200, 200, 300}, 1)
head, err = f.Head(ctx, params.BeaconConfig().ZeroHash, []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, 1, params.BeaconConfig().ZeroHash, []uint64{100, 200, 200, 300}, 1)
head, err = f.Head(ctx, params.BeaconConfig().ZeroHash, []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)
@@ -807,7 +799,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, 1, params.BeaconConfig().ZeroHash, []uint64{100, 200, 200, 300}, 1)
head, err = f.Head(ctx, params.BeaconConfig().ZeroHash, []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)
@@ -818,3 +810,15 @@ func TestStore_RemoveEquivocating(t *testing.T) {
f.InsertSlashedIndex(ctx, types.ValidatorIndex(len(f.votes)))
require.Equal(t, true, len(f.store.slashedIndices) > 0)
}
func TestStore_UpdateCheckpoints(t *testing.T) {
f := setup(1, 1)
jr := [32]byte{'j'}
fr := [32]byte{'f'}
jc := &ethpb.Checkpoint{Root: jr[:], Epoch: 3}
fc := &ethpb.Checkpoint{Root: fr[:], Epoch: 2}
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)
}

View File

@@ -20,7 +20,6 @@ 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.
finalizedRoot [fieldparams.RootLength]byte // latest finalized root 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.
@@ -36,16 +35,18 @@ type Store struct {
// Node defines the individual block which includes its block parent, ancestor and how much weight accounted for it.
// This is used as an array based stateful DAG for efficient fork choice look up.
type Node struct {
slot types.Slot // slot of the block converted to the node.
root [fieldparams.RootLength]byte // root of the block converted to the node.
payloadHash [fieldparams.RootLength]byte // payloadHash of the block converted to the node.
parent uint64 // parent index of this node.
justifiedEpoch types.Epoch // justifiedEpoch of this node.
finalizedEpoch types.Epoch // finalizedEpoch of this node.
weight uint64 // weight of this node.
bestChild uint64 // bestChild index of this node.
bestDescendant uint64 // bestDescendant of this node.
status status // optimistic status of this node
slot types.Slot // slot of the block converted to the node.
root [fieldparams.RootLength]byte // root of the block converted to the node.
payloadHash [fieldparams.RootLength]byte // payloadHash of the block converted to the node.
parent uint64 // parent index of this node.
justifiedEpoch types.Epoch // justifiedEpoch of this node.
unrealizedJustifiedEpoch types.Epoch // the epoch that would be justified if the block would be advanced to the next epoch.
finalizedEpoch types.Epoch // finalizedEpoch of this node.
unrealizedFinalizedEpoch types.Epoch // the epoch that would be finalized if the block would be advanced to the next epoch.
weight uint64 // weight of this node.
bestChild uint64 // bestChild index of this node.
bestDescendant uint64 // bestDescendant of this node.
status status // optimistic status of this node
}
// enum used as optimistic status of a node

View File

@@ -0,0 +1,65 @@
package protoarray
import (
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
)
func (s *Store) setUnrealizedJustifiedEpoch(root [32]byte, epoch types.Epoch) error {
s.nodesLock.Lock()
defer s.nodesLock.Unlock()
index, ok := s.nodesIndices[root]
if !ok {
return ErrUnknownNodeRoot
}
if index >= uint64(len(s.nodes)) {
return errInvalidNodeIndex
}
node := s.nodes[index]
if node == nil {
return errInvalidNodeIndex
}
if epoch < node.unrealizedJustifiedEpoch {
return errInvalidUnrealizedJustifiedEpoch
}
node.unrealizedJustifiedEpoch = epoch
return nil
}
func (s *Store) setUnrealizedFinalizedEpoch(root [32]byte, epoch types.Epoch) error {
s.nodesLock.Lock()
defer s.nodesLock.Unlock()
index, ok := s.nodesIndices[root]
if !ok {
return ErrUnknownNodeRoot
}
if index >= uint64(len(s.nodes)) {
return errInvalidNodeIndex
}
node := s.nodes[index]
if node == nil {
return errInvalidNodeIndex
}
if epoch < node.unrealizedFinalizedEpoch {
return errInvalidUnrealizedFinalizedEpoch
}
node.unrealizedFinalizedEpoch = epoch
return nil
}
// UpdateUnrealizedCheckpoints "realizes" the unrealized justified and finalized
// epochs stored within nodes. It should be called at the beginning of each
// epoch
func (f *ForkChoice) UpdateUnrealizedCheckpoints() {
f.store.nodesLock.Lock()
defer f.store.nodesLock.Unlock()
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.finalizedEpoch > f.store.finalizedEpoch {
f.store.finalizedEpoch = node.finalizedEpoch
}
}
}

View File

@@ -0,0 +1,193 @@
package protoarray
import (
"testing"
"context"
"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"
)
func TestStore_SetUnrealizedEpochs(t *testing.T) {
f := setup(1, 1)
ctx := context.Background()
require.NoError(t, f.InsertOptimisticBlock(ctx, 100, [32]byte{'a'}, params.BeaconConfig().ZeroHash, [32]byte{'A'}, 1, 1))
require.NoError(t, f.InsertOptimisticBlock(ctx, 101, [32]byte{'b'}, [32]byte{'a'}, [32]byte{'B'}, 1, 1))
require.NoError(t, f.InsertOptimisticBlock(ctx, 102, [32]byte{'c'}, [32]byte{'b'}, [32]byte{'C'}, 1, 1))
f.store.nodesLock.RLock()
require.Equal(t, types.Epoch(1), f.store.nodes[2].unrealizedJustifiedEpoch)
require.Equal(t, types.Epoch(1), f.store.nodes[2].unrealizedFinalizedEpoch)
f.store.nodesLock.RUnlock()
require.NoError(t, f.store.setUnrealizedJustifiedEpoch([32]byte{'b'}, 2))
require.NoError(t, f.store.setUnrealizedFinalizedEpoch([32]byte{'b'}, 2))
f.store.nodesLock.RLock()
require.Equal(t, types.Epoch(2), f.store.nodes[2].unrealizedJustifiedEpoch)
require.Equal(t, types.Epoch(2), f.store.nodes[2].unrealizedFinalizedEpoch)
f.store.nodesLock.RUnlock()
require.ErrorIs(t, errInvalidUnrealizedJustifiedEpoch, f.store.setUnrealizedJustifiedEpoch([32]byte{'b'}, 0))
require.ErrorIs(t, errInvalidUnrealizedFinalizedEpoch, f.store.setUnrealizedFinalizedEpoch([32]byte{'b'}, 0))
}
func TestStore_UpdateUnrealizedCheckpoints(t *testing.T) {
f := setup(1, 1)
ctx := context.Background()
require.NoError(t, f.InsertOptimisticBlock(ctx, 100, [32]byte{'a'}, params.BeaconConfig().ZeroHash, [32]byte{'A'}, 1, 1))
require.NoError(t, f.InsertOptimisticBlock(ctx, 101, [32]byte{'b'}, [32]byte{'a'}, [32]byte{'B'}, 1, 1))
require.NoError(t, f.InsertOptimisticBlock(ctx, 102, [32]byte{'c'}, [32]byte{'b'}, [32]byte{'C'}, 1, 1))
}
//
// Epoch 2 | Epoch 3
// |
// C |
// / |
// A <-- B |
// \ |
// ---- D
//
// B is the first block that justifies A.
//
func TestStore_LongFork(t *testing.T) {
f := setup(1, 1)
ctx := context.Background()
require.NoError(t, f.InsertOptimisticBlock(ctx, 100, [32]byte{'a'}, params.BeaconConfig().ZeroHash, [32]byte{'A'}, 1, 1))
require.NoError(t, f.InsertOptimisticBlock(ctx, 101, [32]byte{'b'}, [32]byte{'a'}, [32]byte{'B'}, 1, 1))
require.NoError(t, f.store.setUnrealizedJustifiedEpoch([32]byte{'b'}, 2))
require.NoError(t, f.InsertOptimisticBlock(ctx, 102, [32]byte{'c'}, [32]byte{'b'}, [32]byte{'C'}, 1, 1))
require.NoError(t, f.store.setUnrealizedJustifiedEpoch([32]byte{'c'}, 2))
// 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})
require.NoError(t, err)
require.Equal(t, [32]byte{'c'}, headRoot)
// D is head even though its weight is lower.
hr := [32]byte{'d'}
require.NoError(t, f.InsertOptimisticBlock(ctx, 103, hr, [32]byte{'b'}, [32]byte{'D'}, 2, 1))
require.NoError(t, f.UpdateJustifiedCheckpoint(&ethpb.Checkpoint{Epoch: 2, Root: hr[:]}))
headRoot, err = f.Head(ctx, [32]byte{}, []uint64{100})
require.NoError(t, err)
require.Equal(t, hr, 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})
require.NoError(t, err)
require.Equal(t, [32]byte{'c'}, headRoot)
}
//
//
// Epoch 1 Epoch 2 Epoch 3
// | |
// | |
// A <-- B <-- C <-- D <-- E <-- F <-- G <-- H |
// | \ |
// | --------------- I
// | |
//
// E justifies A. G justifies E.
//
func TestStore_NoDeadLock(t *testing.T) {
f := setup(0, 0)
ctx := context.Background()
// Epoch 1 blocks
require.NoError(t, f.InsertOptimisticBlock(ctx, 100, [32]byte{'a'}, params.BeaconConfig().ZeroHash, [32]byte{'A'}, 0, 0))
require.NoError(t, f.InsertOptimisticBlock(ctx, 101, [32]byte{'b'}, [32]byte{'a'}, [32]byte{'B'}, 0, 0))
require.NoError(t, f.InsertOptimisticBlock(ctx, 102, [32]byte{'c'}, [32]byte{'b'}, [32]byte{'C'}, 0, 0))
require.NoError(t, f.InsertOptimisticBlock(ctx, 103, [32]byte{'d'}, [32]byte{'c'}, [32]byte{'D'}, 0, 0))
// Epoch 2 Blocks
require.NoError(t, f.InsertOptimisticBlock(ctx, 104, [32]byte{'e'}, [32]byte{'d'}, [32]byte{'E'}, 0, 0))
require.NoError(t, f.store.setUnrealizedJustifiedEpoch([32]byte{'e'}, 1))
require.NoError(t, f.InsertOptimisticBlock(ctx, 105, [32]byte{'f'}, [32]byte{'e'}, [32]byte{'F'}, 0, 0))
require.NoError(t, f.store.setUnrealizedJustifiedEpoch([32]byte{'f'}, 1))
require.NoError(t, f.InsertOptimisticBlock(ctx, 106, [32]byte{'g'}, [32]byte{'f'}, [32]byte{'G'}, 0, 0))
require.NoError(t, f.store.setUnrealizedJustifiedEpoch([32]byte{'g'}, 2))
require.NoError(t, f.store.setUnrealizedFinalizedEpoch([32]byte{'g'}, 1))
require.NoError(t, f.InsertOptimisticBlock(ctx, 107, [32]byte{'h'}, [32]byte{'g'}, [32]byte{'H'}, 0, 0))
require.NoError(t, f.store.setUnrealizedJustifiedEpoch([32]byte{'h'}, 2))
require.NoError(t, f.store.setUnrealizedFinalizedEpoch([32]byte{'h'}, 1))
// Add an attestation for h
f.ProcessAttestation(ctx, []uint64{0}, [32]byte{'h'}, 1)
// Epoch 3
// Current Head is H
headRoot, err := f.Head(ctx, [32]byte{}, []uint64{100})
require.NoError(t, err)
require.Equal(t, [32]byte{'h'}, headRoot)
require.Equal(t, types.Epoch(0), f.JustifiedEpoch())
// Insert Block I, it becomes Head
hr := [32]byte{'i'}
require.NoError(t, f.InsertOptimisticBlock(ctx, 108, hr, [32]byte{'f'}, [32]byte{'I'}, 1, 0))
require.NoError(t, f.UpdateJustifiedCheckpoint(&ethpb.Checkpoint{Epoch: 1, Root: hr[:]}))
headRoot, err = f.Head(ctx, [32]byte{}, []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())
// Realized Justified checkpoints, H becomes head
f.UpdateUnrealizedCheckpoints()
headRoot, err = f.Head(ctx, [32]byte{}, []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())
}
// Epoch 1 | Epoch 2
// |
// -- D (late) --
// / |
// A <- B <- C |
// \ |
// -- -- -- E <- F <- G <- H
// |
//
// D justifies and comes late.
//
func TestStore_ForkNextEpoch(t *testing.T) {
f := setup(0, 0)
ctx := context.Background()
// Epoch 1 blocks (D does not arrive)
require.NoError(t, f.InsertOptimisticBlock(ctx, 100, [32]byte{'a'}, params.BeaconConfig().ZeroHash, [32]byte{'A'}, 0, 0))
require.NoError(t, f.InsertOptimisticBlock(ctx, 101, [32]byte{'b'}, [32]byte{'a'}, [32]byte{'B'}, 0, 0))
require.NoError(t, f.InsertOptimisticBlock(ctx, 102, [32]byte{'c'}, [32]byte{'b'}, [32]byte{'C'}, 0, 0))
// Epoch 2 blocks
require.NoError(t, f.InsertOptimisticBlock(ctx, 104, [32]byte{'e'}, [32]byte{'c'}, [32]byte{'E'}, 0, 0))
require.NoError(t, f.InsertOptimisticBlock(ctx, 105, [32]byte{'f'}, [32]byte{'e'}, [32]byte{'F'}, 0, 0))
require.NoError(t, f.InsertOptimisticBlock(ctx, 106, [32]byte{'g'}, [32]byte{'f'}, [32]byte{'G'}, 0, 0))
require.NoError(t, f.InsertOptimisticBlock(ctx, 107, [32]byte{'h'}, [32]byte{'g'}, [32]byte{'H'}, 0, 0))
// 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})
require.NoError(t, err)
require.Equal(t, [32]byte{'h'}, headRoot)
require.Equal(t, types.Epoch(0), f.JustifiedEpoch())
// D arrives late, D is head
require.NoError(t, f.InsertOptimisticBlock(ctx, 103, [32]byte{'d'}, [32]byte{'c'}, [32]byte{'D'}, 0, 0))
require.NoError(t, f.store.setUnrealizedJustifiedEpoch([32]byte{'d'}, 1))
f.UpdateUnrealizedCheckpoints()
headRoot, err = f.Head(ctx, [32]byte{}, []uint64{100})
require.NoError(t, err)
require.Equal(t, [32]byte{'d'}, headRoot)
require.Equal(t, types.Epoch(1), f.JustifiedEpoch())
// nodes[8] = D since it's late!
require.Equal(t, uint64(0), f.store.nodes[8].weight)
require.Equal(t, uint64(100), f.store.nodes[7].weight)
}

View File

@@ -14,7 +14,7 @@ func TestVotes_CanFindHead(t *testing.T) {
f := setup(1, 1)
// The head should always start at the finalized block.
r, err := f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err := f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, params.BeaconConfig().ZeroHash, r, "Incorrect head with genesis")
@@ -24,7 +24,7 @@ func TestVotes_CanFindHead(t *testing.T) {
// 2 <- head
require.NoError(t, f.InsertOptimisticBlock(context.Background(), 0, indexToHash(2), params.BeaconConfig().ZeroHash, params.BeaconConfig().ZeroHash, 1, 1))
r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -34,7 +34,7 @@ func TestVotes_CanFindHead(t *testing.T) {
// head -> 2 1
require.NoError(t, f.InsertOptimisticBlock(context.Background(), 0, indexToHash(1), params.BeaconConfig().ZeroHash, params.BeaconConfig().ZeroHash, 1, 1))
r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -43,7 +43,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(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(1), r, "Incorrect head for with justified epoch at 1")
@@ -52,7 +52,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(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -64,7 +64,7 @@ func TestVotes_CanFindHead(t *testing.T) {
// 3
require.NoError(t, f.InsertOptimisticBlock(context.Background(), 0, indexToHash(3), indexToHash(1), params.BeaconConfig().ZeroHash, 1, 1))
r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -75,7 +75,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(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1")
@@ -86,7 +86,7 @@ func TestVotes_CanFindHead(t *testing.T) {
// |
// 3 <- head
f.ProcessAttestation(context.Background(), []uint64{1}, indexToHash(1), 3)
r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(3), r, "Incorrect head for with justified epoch at 1")
@@ -100,7 +100,7 @@ func TestVotes_CanFindHead(t *testing.T) {
// 4 <- head
require.NoError(t, f.InsertOptimisticBlock(context.Background(), 0, indexToHash(4), indexToHash(3), params.BeaconConfig().ZeroHash, 1, 1))
r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(4), r, "Incorrect head for with justified epoch at 1")
@@ -116,7 +116,7 @@ func TestVotes_CanFindHead(t *testing.T) {
// 5 <- justified epoch = 2
require.NoError(t, f.InsertOptimisticBlock(context.Background(), 0, indexToHash(5), indexToHash(4), params.BeaconConfig().ZeroHash, 2, 2))
r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(4), r, "Incorrect head for with justified epoch at 1")
@@ -167,7 +167,7 @@ func TestVotes_CanFindHead(t *testing.T) {
require.NoError(t, f.InsertOptimisticBlock(context.Background(), 0, indexToHash(8), indexToHash(7), params.BeaconConfig().ZeroHash, 2, 2))
require.NoError(t, f.InsertOptimisticBlock(context.Background(), 0, indexToHash(9), indexToHash(8), params.BeaconConfig().ZeroHash, 2, 2))
r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1)
r, err = f.Head(context.Background(), params.BeaconConfig().ZeroHash, balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(6), r, "Incorrect head for with justified epoch at 1")
@@ -188,7 +188,9 @@ func TestVotes_CanFindHead(t *testing.T) {
// 8
// |
// 9 <- head
r, err = f.Head(context.Background(), 2, indexToHash(5), balances, 2)
f.store.justifiedEpoch = 2
f.store.finalizedEpoch = 2
r, err = f.Head(context.Background(), indexToHash(5), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(9), r, "Incorrect head for with justified epoch at 2")
@@ -212,7 +214,7 @@ func TestVotes_CanFindHead(t *testing.T) {
f.ProcessAttestation(context.Background(), []uint64{0, 1}, indexToHash(9), 5)
require.NoError(t, f.InsertOptimisticBlock(context.Background(), 0, indexToHash(10), indexToHash(8), params.BeaconConfig().ZeroHash, 2, 2))
r, err = f.Head(context.Background(), 2, indexToHash(5), balances, 2)
r, err = f.Head(context.Background(), indexToHash(5), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(9), r, "Incorrect head for with justified epoch at 2")
@@ -221,28 +223,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(), 2, indexToHash(5), balances, 2)
r, err = f.Head(context.Background(), indexToHash(5), 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(), 2, indexToHash(5), balances, 2)
r, err = f.Head(context.Background(), indexToHash(5), 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(), 2, indexToHash(5), balances, 2)
r, err = f.Head(context.Background(), indexToHash(5), 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(), 2, indexToHash(5), balances, 2)
r, err = f.Head(context.Background(), indexToHash(5), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(9), r, "Incorrect head for with justified epoch at 1")
@@ -251,7 +253,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(), 2, indexToHash(5), balances, 2)
r, err = f.Head(context.Background(), indexToHash(5), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(9), r, "Incorrect head for with justified epoch at 2")
@@ -275,7 +277,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(), 2, indexToHash(5), balances, 2)
r, err = f.Head(context.Background(), indexToHash(5), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(9), r, "Incorrect head for with justified epoch at 2")
@@ -291,7 +293,7 @@ func TestVotes_CanFindHead(t *testing.T) {
// head-> 11
require.NoError(t, f.InsertOptimisticBlock(context.Background(), 0, indexToHash(11), indexToHash(9), params.BeaconConfig().ZeroHash, 2, 2))
r, err = f.Head(context.Background(), 2, indexToHash(5), balances, 2)
r, err = f.Head(context.Background(), indexToHash(5), balances)
require.NoError(t, err)
assert.Equal(t, indexToHash(11), r, "Incorrect head for with justified epoch at 2")
}

View File

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

View File

@@ -320,8 +320,12 @@ func handleRPCError(err error) error {
return ErrInvalidParams
case -32603:
return ErrInternal
case -32001:
case -38001:
return ErrUnknownPayload
case -38002:
return ErrInvalidForkchoiceState
case -38003:
return ErrInvalidPayloadAttributes
case -32000:
// Only -32000 status codes are data errors in the RPC specification.
errWithData, ok := err.(rpc.DataError)

View File

@@ -688,7 +688,17 @@ func Test_handleRPCError(t *testing.T) {
{
name: "ErrUnknownPayload",
expectedContains: ErrUnknownPayload.Error(),
given: &customError{code: -32001},
given: &customError{code: -38001},
},
{
name: "ErrInvalidForkchoiceState",
expectedContains: ErrInvalidForkchoiceState.Error(),
given: &customError{code: -38002},
},
{
name: "ErrInvalidPayloadAttributes",
expectedContains: ErrInvalidPayloadAttributes.Error(),
given: &customError{code: -38003},
},
{
name: "ErrServer unexpected no data",

View File

@@ -15,8 +15,12 @@ var (
ErrInternal = errors.New("internal JSON-RPC error")
// ErrServer corresponds to JSON-RPC code -32000.
ErrServer = errors.New("client error while processing request")
// ErrUnknownPayload corresponds to JSON-RPC code -32001.
// ErrUnknownPayload corresponds to JSON-RPC code -38001.
ErrUnknownPayload = errors.New("payload does not exist or is not available")
// ErrInvalidForkchoiceState corresponds to JSON-RPC code -38002.
ErrInvalidForkchoiceState = errors.New("invalid forkchoice state")
// ErrInvalidPayloadAttributes corresponds to JSON-RPC code -38003.
ErrInvalidPayloadAttributes = errors.New("payload attributes are invalid / inconsistent")
// ErrUnknownPayloadStatus when the payload status is unknown.
ErrUnknownPayloadStatus = errors.New("unknown payload status")
// ErrConfigMismatch when the execution node's terminal total difficulty or

View File

@@ -574,14 +574,17 @@ func (bs *Server) GetBlockRoot(ctx context.Context, req *ethpbv1.BlockRequest) (
return nil, status.Errorf(codes.NotFound, "No head root was found")
}
case "finalized":
finalized := bs.ChainInfoFetcher.FinalizedCheckpt()
finalized, err := bs.ChainInfoFetcher.FinalizedCheckpt()
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not retrieve finalized checkpoint: %v", err)
}
root = finalized.Root
case "genesis":
blk, err := bs.BeaconDB.GenesisBlock(ctx)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not retrieve blocks for genesis slot: %v", err)
}
if err := helpers.BeaconBlockIsNil(blk); err != nil {
if err := wrapper.BeaconBlockIsNil(blk); err != nil {
return nil, status.Errorf(codes.NotFound, "Could not find genesis block: %v", err)
}
blkRoot, err := blk.Block().HashTreeRoot()
@@ -595,7 +598,7 @@ func (bs *Server) GetBlockRoot(ctx context.Context, req *ethpbv1.BlockRequest) (
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not retrieve block for block root %#x: %v", req.BlockId, err)
}
if err := helpers.BeaconBlockIsNil(blk); err != nil {
if err := wrapper.BeaconBlockIsNil(blk); err != nil {
return nil, status.Errorf(codes.NotFound, "Could not find block: %v", err)
}
root = req.BlockId
@@ -725,7 +728,10 @@ func (bs *Server) blockFromBlockID(ctx context.Context, blockId []byte) (interfa
return nil, errors.Wrap(err, "could not retrieve head block")
}
case "finalized":
finalized := bs.ChainInfoFetcher.FinalizedCheckpt()
finalized, err := bs.ChainInfoFetcher.FinalizedCheckpt()
if err != nil {
return nil, errors.Wrap(err, "could not retrieve finalized checkpoint")
}
finalizedRoot := bytesutil.ToBytes32(finalized.Root)
blk, err = bs.BeaconDB.Block(ctx, finalizedRoot)
if err != nil {
@@ -787,7 +793,7 @@ func handleGetBlockError(blk interfaces.SignedBeaconBlock, err error) error {
if err != nil {
return status.Errorf(codes.Internal, "Could not get block from block ID: %v", err)
}
if err := helpers.BeaconBlockIsNil(blk); err != nil {
if err := wrapper.BeaconBlockIsNil(blk); err != nil {
return status.Errorf(codes.NotFound, "Could not find requested block: %v", err)
}
return nil

View File

@@ -13,7 +13,6 @@ go_library(
"//beacon-chain/db:go_default_library",
"//beacon-chain/rpc/eth/helpers:go_default_library",
"//beacon-chain/rpc/statefetcher:go_default_library",
"//beacon-chain/state:go_default_library",
"//proto/eth/v1:go_default_library",
"//proto/eth/v2:go_default_library",
"//proto/migration:go_default_library",

View File

@@ -4,7 +4,6 @@ import (
"context"
"github.com/prysmaticlabs/prysm/beacon-chain/rpc/eth/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
ethpbv1 "github.com/prysmaticlabs/prysm/proto/eth/v1"
ethpbv2 "github.com/prysmaticlabs/prysm/proto/eth/v2"
"github.com/prysmaticlabs/prysm/proto/migration"
@@ -84,11 +83,7 @@ func (ds *Server) GetBeaconStateV2(ctx context.Context, req *ethpbv2.StateReques
ExecutionOptimistic: isOptimistic,
}, nil
case version.Altair:
altairState, ok := beaconSt.(state.BeaconStateAltair)
if !ok {
return nil, status.Error(codes.Internal, "Altair state type assertion failed")
}
protoState, err := migration.BeaconStateAltairToProto(altairState)
protoState, err := migration.BeaconStateAltairToProto(beaconSt)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not convert state to proto: %v", err)
}
@@ -100,11 +95,7 @@ func (ds *Server) GetBeaconStateV2(ctx context.Context, req *ethpbv2.StateReques
ExecutionOptimistic: isOptimistic,
}, nil
case version.Bellatrix:
bellatrixState, ok := beaconSt.(state.BeaconStateBellatrix)
if !ok {
return nil, status.Error(codes.Internal, "Bellatrix state type assertion failed")
}
protoState, err := migration.BeaconStateBellatrixToProto(bellatrixState)
protoState, err := migration.BeaconStateBellatrixToProto(beaconSt)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not convert state to proto: %v", err)
}

View File

@@ -47,6 +47,7 @@ go_library(
"//config/params:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//consensus-types/primitives:go_default_library",
"//consensus-types/wrapper:go_default_library",
"//container/slice:go_default_library",
"//encoding/bytesutil:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",

View File

@@ -11,11 +11,11 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
blockfeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/block"
statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/db/filters"
"github.com/prysmaticlabs/prysm/cmd"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/runtime/version"
@@ -250,7 +250,7 @@ func (bs *Server) listBlocksForGenesis(ctx context.Context, _ *ethpb.ListBlocksR
if err != nil {
return nil, 0, strconv.Itoa(0), status.Errorf(codes.Internal, "Could not retrieve blocks for genesis slot: %v", err)
}
if err := helpers.BeaconBlockIsNil(genBlk); err != nil {
if err := wrapper.BeaconBlockIsNil(genBlk); err != nil {
return []blockContainer{}, 0, strconv.Itoa(0), status.Errorf(codes.NotFound, "Could not find genesis block: %v", err)
}
root, err := genBlk.Block().HashTreeRoot()
@@ -393,7 +393,7 @@ func (bs *Server) chainHeadRetrieval(ctx context.Context) (*ethpb.ChainHead, err
if err != nil {
return nil, status.Error(codes.Internal, "Could not get head block")
}
if err := helpers.BeaconBlockIsNil(headBlock); err != nil {
if err := wrapper.BeaconBlockIsNil(headBlock); err != nil {
return nil, status.Errorf(codes.NotFound, "Head block of chain was nil: %v", err)
}
headBlockRoot, err := headBlock.Block().HashTreeRoot()
@@ -409,7 +409,7 @@ func (bs *Server) chainHeadRetrieval(ctx context.Context) (*ethpb.ChainHead, err
}
// Retrieve genesis block in the event we have genesis checkpoints.
genBlock, err := bs.BeaconDB.GenesisBlock(ctx)
if err != nil || helpers.BeaconBlockIsNil(genBlock) != nil {
if err != nil || wrapper.BeaconBlockIsNil(genBlock) != nil {
return status.Error(codes.Internal, "Could not get genesis block")
}
validGenesis = true
@@ -419,23 +419,32 @@ func (bs *Server) chainHeadRetrieval(ctx context.Context) (*ethpb.ChainHead, err
if err != nil {
return status.Errorf(codes.Internal, "Could not get %s block: %v", name, err)
}
if err := helpers.BeaconBlockIsNil(b); err != nil {
if err := wrapper.BeaconBlockIsNil(b); err != nil {
return status.Errorf(codes.Internal, "Could not get %s block: %v", name, err)
}
return nil
}
finalizedCheckpoint := bs.FinalizationFetcher.FinalizedCheckpt()
finalizedCheckpoint, err := bs.FinalizationFetcher.FinalizedCheckpt()
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get finalized checkpoint: %v", err)
}
if err := validateCP(finalizedCheckpoint, "finalized"); err != nil {
return nil, err
}
justifiedCheckpoint := bs.FinalizationFetcher.CurrentJustifiedCheckpt()
justifiedCheckpoint, err := bs.FinalizationFetcher.CurrentJustifiedCheckpt()
if err != nil {
return nil, err
}
if err := validateCP(justifiedCheckpoint, "justified"); err != nil {
return nil, err
}
prevJustifiedCheckpoint := bs.FinalizationFetcher.PreviousJustifiedCheckpt()
prevJustifiedCheckpoint, err := bs.FinalizationFetcher.PreviousJustifiedCheckpt()
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get previous justified checkpoint: %v", err)
}
if err := validateCP(prevJustifiedCheckpoint, "prev justified"); err != nil {
return nil, err
}

View File

@@ -540,10 +540,13 @@ func (bs *Server) GetValidatorParticipation(
default:
return nil, status.Errorf(codes.Internal, "Invalid state type retrieved with a version of %d", beaconState.Version())
}
cp, err := bs.FinalizationFetcher.FinalizedCheckpt()
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get finalized checkpoint: %v", err)
}
p := &ethpb.ValidatorParticipationResponse{
Epoch: requestedEpoch,
Finalized: requestedEpoch <= bs.FinalizationFetcher.FinalizedCheckpt().Epoch,
Finalized: requestedEpoch <= cp.Epoch,
Participation: &ethpb.ValidatorParticipation{
// TODO(7130): Remove these three deprecated fields.
GlobalParticipationRate: float32(b.PrevEpochTargetAttested) / float32(b.ActivePrevEpoch),

View File

@@ -12,7 +12,7 @@ import (
)
func TestServer_GetForkChoice_ProtoArray(t *testing.T) {
store := protoarray.New(0, 0, [32]byte{'a'})
store := protoarray.New(0, 0)
bs := &Server{ForkFetcher: &mock.ChainService{ForkChoiceStore: store}}
res, err := bs.GetForkChoice(context.Background(), &empty.Empty{})
require.NoError(t, err)

View File

@@ -27,81 +27,12 @@ func (vs *Server) StreamBlocksAltair(req *ethpb.StreamBlocksRequest, stream ethp
select {
case blockEvent := <-blocksChannel:
if req.VerifiedOnly {
if blockEvent.Type == statefeed.BlockProcessed {
data, ok := blockEvent.Data.(*statefeed.BlockProcessedData)
if !ok || data == nil {
continue
}
b := &ethpb.StreamBlocksResponse{}
switch data.SignedBlock.Version() {
case version.Phase0:
phBlk, ok := data.SignedBlock.Proto().(*ethpb.SignedBeaconBlock)
if !ok {
log.Warn("Mismatch between version and block type, was expecting SignedBeaconBlock")
continue
}
b.Block = &ethpb.StreamBlocksResponse_Phase0Block{Phase0Block: phBlk}
case version.Altair:
phBlk, ok := data.SignedBlock.Proto().(*ethpb.SignedBeaconBlockAltair)
if !ok {
log.Warn("Mismatch between version and block type, was expecting SignedBeaconBlockAltair")
continue
}
b.Block = &ethpb.StreamBlocksResponse_AltairBlock{AltairBlock: phBlk}
case version.Bellatrix:
phBlk, ok := data.SignedBlock.Proto().(*ethpb.SignedBeaconBlockBellatrix)
if !ok {
log.Warn("Mismatch between version and block type, was expecting SignedBeaconBlockBellatrix")
continue
}
b.Block = &ethpb.StreamBlocksResponse_BellatrixBlock{BellatrixBlock: phBlk}
}
if err := stream.Send(b); err != nil {
return status.Errorf(codes.Unavailable, "Could not send over stream: %v", err)
}
if err := sendVerifiedBlocks(stream, blockEvent); err != nil {
return err
}
} else {
if blockEvent.Type == blockfeed.ReceivedBlock {
data, ok := blockEvent.Data.(*blockfeed.ReceivedBlockData)
if !ok {
// Got bad data over the stream.
continue
}
if data.SignedBlock == nil {
// One nil block shouldn't stop the stream.
continue
}
headState, err := vs.HeadFetcher.HeadState(vs.Ctx)
if err != nil {
log.WithError(err).WithField("blockSlot", data.SignedBlock.Block().Slot()).Error("Could not get head state")
continue
}
signed := data.SignedBlock
if err := blocks.VerifyBlockSignature(headState, signed.Block().ProposerIndex(), signed.Signature(), signed.Block().HashTreeRoot); err != nil {
log.WithError(err).WithField("blockSlot", data.SignedBlock.Block().Slot()).Error("Could not verify block signature")
continue
}
b := &ethpb.StreamBlocksResponse{}
switch data.SignedBlock.Version() {
case version.Phase0:
phBlk, ok := data.SignedBlock.Proto().(*ethpb.SignedBeaconBlock)
if !ok {
log.Warn("Mismatch between version and block type, was expecting *ethpb.SignedBeaconBlock")
continue
}
b.Block = &ethpb.StreamBlocksResponse_Phase0Block{Phase0Block: phBlk}
case version.Altair:
phBlk, ok := data.SignedBlock.Proto().(*ethpb.SignedBeaconBlockAltair)
if !ok {
log.Warn("Mismatch between version and block type, was expecting *v2.SignedBeaconBlockAltair")
continue
}
b.Block = &ethpb.StreamBlocksResponse_AltairBlock{AltairBlock: phBlk}
}
if err := stream.Send(b); err != nil {
return status.Errorf(codes.Unavailable, "Could not send over stream: %v", err)
}
if err := vs.sendBlocks(stream, blockEvent); err != nil {
return err
}
}
case <-blockSub.Err():
@@ -113,3 +44,86 @@ func (vs *Server) StreamBlocksAltair(req *ethpb.StreamBlocksRequest, stream ethp
}
}
}
func sendVerifiedBlocks(stream ethpb.BeaconNodeValidator_StreamBlocksAltairServer, blockEvent *feed.Event) error {
if blockEvent.Type != statefeed.BlockProcessed {
return nil
}
data, ok := blockEvent.Data.(*statefeed.BlockProcessedData)
if !ok || data == nil {
return nil
}
b := &ethpb.StreamBlocksResponse{}
switch data.SignedBlock.Version() {
case version.Phase0:
phBlk, ok := data.SignedBlock.Proto().(*ethpb.SignedBeaconBlock)
if !ok {
log.Warn("Mismatch between version and block type, was expecting SignedBeaconBlock")
return nil
}
b.Block = &ethpb.StreamBlocksResponse_Phase0Block{Phase0Block: phBlk}
case version.Altair:
phBlk, ok := data.SignedBlock.Proto().(*ethpb.SignedBeaconBlockAltair)
if !ok {
log.Warn("Mismatch between version and block type, was expecting SignedBeaconBlockAltair")
return nil
}
b.Block = &ethpb.StreamBlocksResponse_AltairBlock{AltairBlock: phBlk}
case version.Bellatrix:
phBlk, ok := data.SignedBlock.Proto().(*ethpb.SignedBeaconBlockBellatrix)
if !ok {
log.Warn("Mismatch between version and block type, was expecting SignedBeaconBlockBellatrix")
return nil
}
b.Block = &ethpb.StreamBlocksResponse_BellatrixBlock{BellatrixBlock: phBlk}
}
if err := stream.Send(b); err != nil {
return status.Errorf(codes.Unavailable, "Could not send over stream: %v", err)
}
return nil
}
func (vs *Server) sendBlocks(stream ethpb.BeaconNodeValidator_StreamBlocksAltairServer, blockEvent *feed.Event) error {
if blockEvent.Type != blockfeed.ReceivedBlock {
return nil
}
data, ok := blockEvent.Data.(*blockfeed.ReceivedBlockData)
if !ok || data == nil {
// Got bad data over the stream.
return nil
}
if data.SignedBlock == nil {
// One nil block shouldn't stop the stream.
return nil
}
log := log.WithField("blockSlot", data.SignedBlock.Block().Slot())
headState, err := vs.HeadFetcher.HeadState(vs.Ctx)
if err != nil {
log.WithError(err).Error("Could not get head state")
return nil
}
signed := data.SignedBlock
if err := blocks.VerifyBlockSignature(headState, signed.Block().ProposerIndex(), signed.Signature(), signed.Block().HashTreeRoot); err != nil {
log.WithError(err).Error("Could not verify block signature")
return nil
}
b := &ethpb.StreamBlocksResponse{}
switch p := data.SignedBlock.Proto().(type) {
case *ethpb.SignedBeaconBlock:
b.Block = &ethpb.StreamBlocksResponse_Phase0Block{Phase0Block: p}
case *ethpb.SignedBeaconBlockAltair:
b.Block = &ethpb.StreamBlocksResponse_AltairBlock{AltairBlock: p}
case *ethpb.SignedBeaconBlockBellatrix:
b.Block = &ethpb.StreamBlocksResponse_BellatrixBlock{BellatrixBlock: p}
default:
log.Errorf("Unknown block type %T", p)
}
if err := stream.Send(b); err != nil {
return status.Errorf(codes.Unavailable, "Could not send over stream: %v", err)
}
return nil
}

View File

@@ -16,6 +16,7 @@ import (
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
"github.com/prysmaticlabs/prysm/config/params"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
"github.com/prysmaticlabs/prysm/runtime/version"
@@ -98,7 +99,7 @@ func (vs *Server) getExecutionPayload(ctx context.Context, slot types.Slot, vIdx
if err != nil {
return nil, err
}
if err := helpers.BeaconBlockIsNil(finalizedBlock); err != nil {
if err := wrapper.BeaconBlockIsNil(finalizedBlock); err != nil {
return nil, err
}
switch finalizedBlock.Version() {

Some files were not shown because too many files have changed in this diff Show More