Compare commits

...

14 Commits

Author SHA1 Message Date
terence tsao
a3a7c1adda Pingoleon 2022-06-27 17:05:46 -07:00
terence tsao
62c1ea082e Fix context 2022-06-27 16:56:37 -07:00
terencechain
e8a6b2ceae Merge branch 'develop' into unrealized_justification 2022-06-27 16:39:06 -07:00
Potuz
ccee33ffd3 fix test 2022-06-27 09:54:16 -03:00
Potuz
de8c1a1fe5 do not call precompute 2022-06-27 09:50:18 -03:00
Potuz
a695024e48 gaz 2022-06-26 16:47:55 -03:00
Potuz
18626fea6b state tests 2022-06-26 16:46:54 -03:00
Potuz
42b51232ae mod tidy 2022-06-26 16:37:03 -03:00
Potuz
125e4a1340 restore testvectors 2022-06-26 16:34:04 -03:00
Potuz
518229d0a4 phase0 test 2022-06-26 16:33:39 -03:00
Potuz
0bec71dc80 add feature flag 2022-06-26 11:10:19 -03:00
Potuz
c827fb70ea Add Phase0 support 2022-06-25 21:19:11 -03:00
Potuz
8d152e8781 bellatrix + altair tests passing 2022-06-25 17:56:14 -03:00
Potuz
7734a5ec8b init 2022-06-25 17:56:14 -03:00
43 changed files with 450 additions and 124 deletions

View File

@@ -247,8 +247,8 @@ filegroup(
visibility = ["//visibility:public"],
)
""",
sha256 = "52f2c52415228cee8a4de5a09abff785f439a77dfef8f03e834e4e16857673c1",
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/minimal.tar.gz" % consensus_spec_version,
sha256 = "b670fc56ddc4d376b58b21f3db134136edc8853c77b4601919b92b3fc5acee7b",
urls = ["file:///tmp/minimal-pr-4-20220622.tar.gz"],
)
http_archive(

View File

@@ -212,7 +212,9 @@ func (s *Service) onBlock(ctx context.Context, signed interfaces.SignedBeaconBlo
// Save justified check point to db.
if justified.Epoch > currJustifiedEpoch {
if err := s.cfg.BeaconDB.SaveJustifiedCheckpoint(ctx, postState.CurrentJustifiedCheckpoint()); err != nil {
if err := s.cfg.BeaconDB.SaveJustifiedCheckpoint(ctx, &ethpb.Checkpoint{
Epoch: justified.Epoch, Root: justified.Root[:],
}); err != nil {
return err
}
}
@@ -220,7 +222,7 @@ func (s *Service) onBlock(ctx context.Context, signed interfaces.SignedBeaconBlo
// Update finalized check point.
finalized := s.ForkChoicer().FinalizedCheckpoint()
if finalized.Epoch > currFinalizedEpoch {
if err := s.updateFinalized(ctx, postState.FinalizedCheckpoint()); err != nil {
if err := s.updateFinalized(ctx, &ethpb.Checkpoint{Epoch: finalized.Epoch, Root: finalized.Root[:]}); err != nil {
return err
}
isOptimistic, err := s.cfg.ForkChoiceStore.IsOptimistic(finalized.Root)

View File

@@ -1,11 +1,14 @@
package precompute
import (
"context"
"github.com/pkg/errors"
"github.com/prysmaticlabs/go-bitfield"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/core/time"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/config/params"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/time/slots"
)
@@ -14,12 +17,18 @@ var errNilState = errors.New("nil state")
// UnrealizedCheckpoints returns the justification and finalization checkpoints of the
// given state as if it was progressed with empty slots until the next epoch.
func UnrealizedCheckpoints(st state.BeaconState) (*ethpb.Checkpoint, *ethpb.Checkpoint, error) {
func UnrealizedCheckpoints(ctx context.Context, st state.BeaconState) (*ethpb.Checkpoint, *ethpb.Checkpoint, error) {
if st == nil || st.IsNil() {
return nil, nil, errNilState
}
activeBalance, prevTarget, currentTarget, err := st.UnrealizedCheckpointBalances()
if slots.ToEpoch(st.Slot()) <= params.BeaconConfig().GenesisEpoch+1 {
jc := st.CurrentJustifiedCheckpoint()
fc := st.FinalizedCheckpoint()
return jc, fc, nil
}
activeBalance, prevTarget, currentTarget, err := st.UnrealizedCheckpointBalances(ctx)
if err != nil {
return nil, nil, err
}

View File

@@ -243,7 +243,7 @@ func TestUnrealizedCheckpoints(t *testing.T) {
_, _, err = altair.InitializePrecomputeValidators(context.Background(), state)
require.NoError(t, err)
jc, fc, err := precompute.UnrealizedCheckpoints(state)
jc, fc, err := precompute.UnrealizedCheckpoints(context.Background(), state)
require.NoError(t, err)
require.DeepEqual(t, test.expectedJustified, jc.Epoch)
require.DeepEqual(t, test.expectedFinalized, fc.Epoch)

View File

@@ -22,9 +22,12 @@ go_library(
],
deps = [
"//beacon-chain/core/blocks:go_default_library",
"//beacon-chain/core/epoch/precompute:go_default_library",
"//beacon-chain/core/time:go_default_library",
"//beacon-chain/forkchoice:go_default_library",
"//beacon-chain/forkchoice/types:go_default_library",
"//beacon-chain/state:go_default_library",
"//config/features:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//consensus-types/primitives:go_default_library",

View File

@@ -6,9 +6,12 @@ import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute"
"github.com/prysmaticlabs/prysm/beacon-chain/core/time"
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice"
forkchoicetypes "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/types"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/config/features"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
"github.com/prysmaticlabs/prysm/config/params"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
@@ -23,15 +26,17 @@ import (
// New initializes a new fork choice store.
func New() *ForkChoice {
s := &Store{
justifiedCheckpoint: &forkchoicetypes.Checkpoint{},
bestJustifiedCheckpoint: &forkchoicetypes.Checkpoint{},
prevJustifiedCheckpoint: &forkchoicetypes.Checkpoint{},
finalizedCheckpoint: &forkchoicetypes.Checkpoint{},
proposerBoostRoot: [32]byte{},
nodeByRoot: make(map[[fieldparams.RootLength]byte]*Node),
nodeByPayload: make(map[[fieldparams.RootLength]byte]*Node),
slashedIndices: make(map[types.ValidatorIndex]bool),
pruneThreshold: defaultPruneThreshold,
justifiedCheckpoint: &forkchoicetypes.Checkpoint{},
bestJustifiedCheckpoint: &forkchoicetypes.Checkpoint{},
unrealizedJustifiedCheckpoint: &forkchoicetypes.Checkpoint{},
unrealizedFinalizedCheckpoint: &forkchoicetypes.Checkpoint{},
prevJustifiedCheckpoint: &forkchoicetypes.Checkpoint{},
finalizedCheckpoint: &forkchoicetypes.Checkpoint{},
proposerBoostRoot: [32]byte{},
nodeByRoot: make(map[[fieldparams.RootLength]byte]*Node),
nodeByPayload: make(map[[fieldparams.RootLength]byte]*Node),
slashedIndices: make(map[types.ValidatorIndex]bool),
pruneThreshold: defaultPruneThreshold,
}
b := make([]uint64, 0)
@@ -112,7 +117,7 @@ func (f *ForkChoice) ProcessAttestation(ctx context.Context, validatorIndices []
}
// InsertNode processes a new block by inserting it to the fork choice store.
func (f *ForkChoice) InsertNode(ctx context.Context, state state.ReadOnlyBeaconState, root [32]byte) error {
func (f *ForkChoice) InsertNode(ctx context.Context, state state.BeaconState, root [32]byte) error {
ctx, span := trace.StartSpan(ctx, "doublyLinkedForkchoice.InsertNode")
defer span.End()
@@ -142,10 +147,41 @@ func (f *ForkChoice) InsertNode(ctx context.Context, state state.ReadOnlyBeaconS
return errInvalidNilCheckpoint
}
finalizedEpoch := fc.Epoch
err := f.store.insert(ctx, slot, root, parentRoot, payloadHash, justifiedEpoch, finalizedEpoch)
node, err := f.store.insert(ctx, slot, root, parentRoot, payloadHash, justifiedEpoch, finalizedEpoch)
if err != nil {
return err
}
if features.Get().PullTips {
uj, uf, err := precompute.UnrealizedCheckpoints(ctx, state)
if err != nil {
log.WithError(err).Debug("could not compute unrealized checkpoints")
} else {
node.unrealizedJustifiedEpoch, node.unrealizedFinalizedEpoch = uj.Epoch, uf.Epoch
f.store.checkpointsLock.Lock()
if uj.Epoch > f.store.unrealizedJustifiedCheckpoint.Epoch {
f.store.unrealizedJustifiedCheckpoint = &forkchoicetypes.Checkpoint{
Epoch: uj.Epoch, Root: bytesutil.ToBytes32(uj.Root),
}
}
if uf.Epoch > f.store.unrealizedFinalizedCheckpoint.Epoch {
f.store.unrealizedJustifiedCheckpoint = &forkchoicetypes.Checkpoint{
Epoch: uj.Epoch, Root: bytesutil.ToBytes32(uj.Root),
}
f.store.unrealizedFinalizedCheckpoint = &forkchoicetypes.Checkpoint{
Epoch: uf.Epoch, Root: bytesutil.ToBytes32(uf.Root),
}
}
currentSlot := slots.CurrentSlot(f.store.genesisTime)
if time.CurrentEpoch(state) < slots.ToEpoch(currentSlot) {
jc, fc = uj, uf
node.justifiedEpoch = uj.Epoch
node.finalizedEpoch = uf.Epoch
}
f.store.checkpointsLock.Unlock()
}
}
return f.updateCheckpoints(ctx, jc, fc)
}
@@ -546,7 +582,7 @@ func (f *ForkChoice) InsertOptimisticChain(ctx context.Context, chain []*forkcho
if err != nil {
return err
}
if err := f.store.insert(ctx,
if _, err := f.store.insert(ctx,
b.Slot(), r, parentRoot, payloadHash,
chain[i].JustifiedCheckpoint.Epoch, chain[i].FinalizedCheckpoint.Epoch); err != nil {
return err

View File

@@ -4,6 +4,7 @@ import (
"context"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/config/features"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/time/slots"
)
@@ -64,5 +65,8 @@ func (f *ForkChoice) NewSlot(ctx context.Context, slot types.Slot) error {
f.store.justifiedCheckpoint = bjcp
}
}
if features.Get().PullTips {
f.UpdateUnrealizedCheckpoints()
}
return nil
}

View File

@@ -108,7 +108,7 @@ func (s *Store) head(ctx context.Context) ([32]byte, error) {
func (s *Store) insert(ctx context.Context,
slot types.Slot,
root, parentRoot, payloadHash [fieldparams.RootLength]byte,
justifiedEpoch, finalizedEpoch types.Epoch) error {
justifiedEpoch, finalizedEpoch types.Epoch) (*Node, error) {
_, span := trace.StartSpan(ctx, "doublyLinkedForkchoice.insert")
defer span.End()
@@ -116,8 +116,8 @@ func (s *Store) insert(ctx context.Context,
defer s.nodesLock.Unlock()
// Return if the block has been inserted into Store before.
if _, ok := s.nodeByRoot[root]; ok {
return nil
if n, ok := s.nodeByRoot[root]; ok {
return n, nil
}
parent := s.nodeByRoot[parentRoot]
@@ -141,14 +141,14 @@ func (s *Store) insert(ctx context.Context,
s.treeRootNode = n
s.headNode = n
} else {
return errInvalidParentRoot
return n, errInvalidParentRoot
}
} else {
parent.children = append(parent.children, n)
// Apply proposer boost
timeNow := uint64(time.Now().Unix())
if timeNow < s.genesisTime {
return nil
return n, nil
}
secondsIntoSlot := (timeNow - s.genesisTime) % params.BeaconConfig().SecondsPerSlot
currentSlot := slots.CurrentSlot(s.genesisTime)
@@ -162,14 +162,14 @@ func (s *Store) insert(ctx context.Context,
// Update best descendants
if err := s.treeRootNode.updateBestDescendant(ctx,
s.justifiedCheckpoint.Epoch, s.finalizedCheckpoint.Epoch); err != nil {
return err
return n, err
}
}
// Update metrics.
processedBlockCount.Inc()
nodeCount.Set(float64(len(s.nodeByRoot)))
return nil
return n, nil
}
// pruneFinalizedNodeByRootMap prunes the `nodeByRoot` map

View File

@@ -141,7 +141,8 @@ func TestStore_Insert(t *testing.T) {
fc := &forkchoicetypes.Checkpoint{Epoch: 0}
s := &Store{nodeByRoot: nodeByRoot, treeRootNode: treeRootNode, nodeByPayload: nodeByPayload, justifiedCheckpoint: jc, finalizedCheckpoint: fc}
payloadHash := [32]byte{'a'}
require.NoError(t, s.insert(context.Background(), 100, indexToHash(100), indexToHash(0), payloadHash, 1, 1))
_, err := s.insert(context.Background(), 100, indexToHash(100), indexToHash(0), payloadHash, 1, 1)
require.NoError(t, err)
assert.Equal(t, 2, len(s.nodeByRoot), "Did not insert block")
assert.Equal(t, (*Node)(nil), treeRootNode.parent, "Incorrect parent")
assert.Equal(t, 1, len(treeRootNode.children), "Incorrect children number")

View File

@@ -18,24 +18,26 @@ type ForkChoice struct {
// Store defines the fork choice store which includes block nodes and the last view of checkpoint information.
type Store struct {
justifiedCheckpoint *forkchoicetypes.Checkpoint // latest justified epoch in store.
bestJustifiedCheckpoint *forkchoicetypes.Checkpoint // best justified checkpoint in store.
prevJustifiedCheckpoint *forkchoicetypes.Checkpoint // previous justified checkpoint in store.
finalizedCheckpoint *forkchoicetypes.Checkpoint // latest finalized epoch in store.
pruneThreshold uint64 // do not prune tree unless threshold is reached.
proposerBoostRoot [fieldparams.RootLength]byte // latest block root that was boosted after being received in a timely manner.
previousProposerBoostRoot [fieldparams.RootLength]byte // previous block root that was boosted after being received in a timely manner.
previousProposerBoostScore uint64 // previous proposer boosted root score.
treeRootNode *Node // the root node of the store tree.
headNode *Node // last head Node
nodeByRoot map[[fieldparams.RootLength]byte]*Node // nodes indexed by roots.
nodeByPayload map[[fieldparams.RootLength]byte]*Node // nodes indexed by payload Hash
slashedIndices map[types.ValidatorIndex]bool // the list of equivocating validator indices
originRoot [fieldparams.RootLength]byte // The genesis block root
nodesLock sync.RWMutex
proposerBoostLock sync.RWMutex
checkpointsLock sync.RWMutex
genesisTime uint64
justifiedCheckpoint *forkchoicetypes.Checkpoint // latest justified epoch in store.
bestJustifiedCheckpoint *forkchoicetypes.Checkpoint // best justified checkpoint in store.
unrealizedJustifiedCheckpoint *forkchoicetypes.Checkpoint // best unrealized justified checkpoint in store.
unrealizedFinalizedCheckpoint *forkchoicetypes.Checkpoint // best unrealized finalized Checkpoint
prevJustifiedCheckpoint *forkchoicetypes.Checkpoint // previous justified checkpoint in store.
finalizedCheckpoint *forkchoicetypes.Checkpoint // latest finalized epoch in store.
pruneThreshold uint64 // do not prune tree unless threshold is reached.
proposerBoostRoot [fieldparams.RootLength]byte // latest block root that was boosted after being received in a timely manner.
previousProposerBoostRoot [fieldparams.RootLength]byte // previous block root that was boosted after being received in a timely manner.
previousProposerBoostScore uint64 // previous proposer boosted root score.
treeRootNode *Node // the root node of the store tree.
headNode *Node // last head Node
nodeByRoot map[[fieldparams.RootLength]byte]*Node // nodes indexed by roots.
nodeByPayload map[[fieldparams.RootLength]byte]*Node // nodes indexed by payload Hash
slashedIndices map[types.ValidatorIndex]bool // the list of equivocating validator indices
originRoot [fieldparams.RootLength]byte // The genesis block root
nodesLock sync.RWMutex
proposerBoostLock sync.RWMutex
checkpointsLock sync.RWMutex
genesisTime uint64
}
// Node defines the individual block which includes its block parent, ancestor and how much weight accounted for it.

View File

@@ -45,10 +45,15 @@ func (f *ForkChoice) UpdateUnrealizedCheckpoints() {
node.justifiedEpoch = node.unrealizedJustifiedEpoch
node.finalizedEpoch = node.unrealizedFinalizedEpoch
if node.justifiedEpoch > f.store.justifiedCheckpoint.Epoch {
f.store.justifiedCheckpoint.Epoch = node.justifiedEpoch
if node.justifiedEpoch > f.store.bestJustifiedCheckpoint.Epoch {
f.store.bestJustifiedCheckpoint = f.store.unrealizedJustifiedCheckpoint
}
// shouldUpdate will always be true in slot 0
f.store.justifiedCheckpoint = f.store.unrealizedJustifiedCheckpoint
}
if node.finalizedEpoch > f.store.finalizedCheckpoint.Epoch {
f.store.finalizedCheckpoint.Epoch = node.finalizedEpoch
f.store.justifiedCheckpoint = f.store.unrealizedJustifiedCheckpoint
f.store.finalizedCheckpoint = f.store.unrealizedFinalizedCheckpoint
}
}
}

View File

@@ -147,6 +147,8 @@ func TestStore_NoDeadLock(t *testing.T) {
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
require.NoError(t, f.store.setUnrealizedJustifiedEpoch([32]byte{'g'}, 2))
require.NoError(t, f.store.setUnrealizedFinalizedEpoch([32]byte{'g'}, 1))
f.store.unrealizedJustifiedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: 2}
f.store.unrealizedFinalizedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: 1}
state, blkRoot, err = prepareForkchoiceState(ctx, 107, [32]byte{'h'}, [32]byte{'g'}, [32]byte{'H'}, 0, 0)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
@@ -236,6 +238,7 @@ func TestStore_ForkNextEpoch(t *testing.T) {
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
require.NoError(t, f.store.setUnrealizedJustifiedEpoch([32]byte{'d'}, 1))
f.store.unrealizedJustifiedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: 1}
f.UpdateUnrealizedCheckpoints()
headRoot, err = f.Head(ctx, []uint64{100})
require.NoError(t, err)

View File

@@ -30,7 +30,7 @@ type HeadRetriever interface {
// BlockProcessor processes the block that's used for accounting fork choice.
type BlockProcessor interface {
InsertNode(context.Context, state.ReadOnlyBeaconState, [32]byte) error
InsertNode(context.Context, state.BeaconState, [32]byte) error
InsertOptimisticChain(context.Context, []*forkchoicetypes.BlockAndCheckpoints) error
}

View File

@@ -22,9 +22,12 @@ go_library(
],
deps = [
"//beacon-chain/core/blocks:go_default_library",
"//beacon-chain/core/epoch/precompute:go_default_library",
"//beacon-chain/core/time:go_default_library",
"//beacon-chain/forkchoice:go_default_library",
"//beacon-chain/forkchoice/types:go_default_library",
"//beacon-chain/state:go_default_library",
"//config/features:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//consensus-types/primitives:go_default_library",

View File

@@ -4,6 +4,7 @@ import (
"context"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/config/features"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/time/slots"
)
@@ -64,5 +65,8 @@ func (f *ForkChoice) NewSlot(ctx context.Context, slot types.Slot) error {
f.store.justifiedCheckpoint = bjcp
}
}
if features.Get().PullTips {
f.UpdateUnrealizedCheckpoints()
}
return nil
}

View File

@@ -8,9 +8,12 @@ import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute"
prysmtime "github.com/prysmaticlabs/prysm/beacon-chain/core/time"
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice"
forkchoicetypes "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/types"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/config/features"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
"github.com/prysmaticlabs/prysm/config/params"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
@@ -30,17 +33,19 @@ const defaultPruneThreshold = 256
// New initializes a new fork choice store.
func New() *ForkChoice {
s := &Store{
justifiedCheckpoint: &forkchoicetypes.Checkpoint{},
bestJustifiedCheckpoint: &forkchoicetypes.Checkpoint{},
prevJustifiedCheckpoint: &forkchoicetypes.Checkpoint{},
finalizedCheckpoint: &forkchoicetypes.Checkpoint{},
proposerBoostRoot: [32]byte{},
nodes: make([]*Node, 0),
nodesIndices: make(map[[32]byte]uint64),
payloadIndices: make(map[[32]byte]uint64),
canonicalNodes: make(map[[32]byte]bool),
slashedIndices: make(map[types.ValidatorIndex]bool),
pruneThreshold: defaultPruneThreshold,
justifiedCheckpoint: &forkchoicetypes.Checkpoint{},
bestJustifiedCheckpoint: &forkchoicetypes.Checkpoint{},
unrealizedJustifiedCheckpoint: &forkchoicetypes.Checkpoint{},
prevJustifiedCheckpoint: &forkchoicetypes.Checkpoint{},
finalizedCheckpoint: &forkchoicetypes.Checkpoint{},
unrealizedFinalizedCheckpoint: &forkchoicetypes.Checkpoint{},
proposerBoostRoot: [32]byte{},
nodes: make([]*Node, 0),
nodesIndices: make(map[[32]byte]uint64),
payloadIndices: make(map[[32]byte]uint64),
canonicalNodes: make(map[[32]byte]bool),
slashedIndices: make(map[types.ValidatorIndex]bool),
pruneThreshold: defaultPruneThreshold,
}
b := make([]uint64, 0)
@@ -117,7 +122,7 @@ func (f *ForkChoice) ProposerBoost() [fieldparams.RootLength]byte {
}
// InsertNode processes a new block by inserting it to the fork choice store.
func (f *ForkChoice) InsertNode(ctx context.Context, state state.ReadOnlyBeaconState, root [32]byte) error {
func (f *ForkChoice) InsertNode(ctx context.Context, state state.BeaconState, root [32]byte) error {
ctx, span := trace.StartSpan(ctx, "protoArrayForkChoice.InsertNode")
defer span.End()
@@ -147,10 +152,41 @@ func (f *ForkChoice) InsertNode(ctx context.Context, state state.ReadOnlyBeaconS
return errInvalidNilCheckpoint
}
finalizedEpoch := fc.Epoch
err := f.store.insert(ctx, slot, root, parentRoot, payloadHash, justifiedEpoch, finalizedEpoch)
node, err := f.store.insert(ctx, slot, root, parentRoot, payloadHash, justifiedEpoch, finalizedEpoch)
if err != nil {
return err
}
if features.Get().PullTips {
uj, uf, err := precompute.UnrealizedCheckpoints(ctx, state)
if err != nil {
log.WithError(err).Debug("could not compute unrealized checkpoints")
} else {
node.unrealizedJustifiedEpoch, node.unrealizedFinalizedEpoch = uj.Epoch, uf.Epoch
f.store.checkpointsLock.Lock()
if uj.Epoch > f.store.unrealizedJustifiedCheckpoint.Epoch {
f.store.unrealizedJustifiedCheckpoint = &forkchoicetypes.Checkpoint{
Epoch: uj.Epoch, Root: bytesutil.ToBytes32(uj.Root),
}
}
if uf.Epoch > f.store.unrealizedFinalizedCheckpoint.Epoch {
f.store.unrealizedJustifiedCheckpoint = &forkchoicetypes.Checkpoint{
Epoch: uj.Epoch, Root: bytesutil.ToBytes32(uj.Root),
}
f.store.unrealizedFinalizedCheckpoint = &forkchoicetypes.Checkpoint{
Epoch: uf.Epoch, Root: bytesutil.ToBytes32(uf.Root),
}
}
currentSlot := slots.CurrentSlot(f.store.genesisTime)
if prysmtime.CurrentEpoch(state) < slots.ToEpoch(currentSlot) {
jc, fc = uj, uf
node.justifiedEpoch = uj.Epoch
node.finalizedEpoch = uf.Epoch
}
f.store.checkpointsLock.Unlock()
}
}
return f.updateCheckpoints(ctx, jc, fc)
}
@@ -462,7 +498,7 @@ func (s *Store) updateCanonicalNodes(ctx context.Context, root [32]byte) error {
func (s *Store) insert(ctx context.Context,
slot types.Slot,
root, parent, payloadHash [32]byte,
justifiedEpoch, finalizedEpoch types.Epoch) error {
justifiedEpoch, finalizedEpoch types.Epoch) (*Node, error) {
_, span := trace.StartSpan(ctx, "protoArrayForkChoice.insert")
defer span.End()
@@ -470,8 +506,8 @@ func (s *Store) insert(ctx context.Context,
defer s.nodesLock.Unlock()
// Return if the block has been inserted into Store before.
if _, ok := s.nodesIndices[root]; ok {
return nil
if idx, ok := s.nodesIndices[root]; ok {
return s.nodes[idx], nil
}
index := uint64(len(s.nodes))
@@ -502,7 +538,7 @@ func (s *Store) insert(ctx context.Context,
// Apply proposer boost
timeNow := uint64(time.Now().Unix())
if timeNow < s.genesisTime {
return nil
return n, nil
}
secondsIntoSlot := (timeNow - s.genesisTime) % params.BeaconConfig().SecondsPerSlot
currentSlot := slots.CurrentSlot(s.genesisTime)
@@ -516,7 +552,7 @@ func (s *Store) insert(ctx context.Context,
// Update parent with the best child and descendant only if it's available.
if n.parent != NonExistentNode {
if err := s.updateBestChildAndDescendant(parentIndex, index); err != nil {
return err
return n, err
}
}
@@ -524,7 +560,7 @@ func (s *Store) insert(ctx context.Context,
processedBlockCount.Inc()
nodeCount.Set(float64(len(s.nodes)))
return nil
return n, nil
}
// applyWeightChanges iterates backwards through the nodes in store. It checks all nodes parent
@@ -991,7 +1027,7 @@ func (f *ForkChoice) InsertOptimisticChain(ctx context.Context, chain []*forkcho
if err != nil {
return err
}
if err := f.store.insert(ctx,
if _, err := f.store.insert(ctx,
b.Slot(), r, parentRoot, payloadHash,
chain[i].JustifiedCheckpoint.Epoch, chain[i].FinalizedCheckpoint.Epoch); err != nil {
return err

View File

@@ -114,7 +114,8 @@ func TestStore_Head_ContextCancelled(t *testing.T) {
func TestStore_Insert_UnknownParent(t *testing.T) {
// The new node does not have a parent.
s := &Store{nodesIndices: make(map[[32]byte]uint64), payloadIndices: make(map[[32]byte]uint64)}
require.NoError(t, s.insert(context.Background(), 100, [32]byte{'A'}, [32]byte{'B'}, params.BeaconConfig().ZeroHash, 1, 1))
_, err := s.insert(context.Background(), 100, [32]byte{'A'}, [32]byte{'B'}, params.BeaconConfig().ZeroHash, 1, 1)
require.NoError(t, err)
assert.Equal(t, 1, len(s.nodes), "Did not insert block")
assert.Equal(t, 1, len(s.nodesIndices), "Did not insert block")
assert.Equal(t, NonExistentNode, s.nodes[0].parent, "Incorrect parent")
@@ -133,7 +134,8 @@ func TestStore_Insert_KnownParent(t *testing.T) {
payloadHash := [32]byte{'c'}
s.justifiedCheckpoint = &forkchoicetypes.Checkpoint{}
s.finalizedCheckpoint = &forkchoicetypes.Checkpoint{}
require.NoError(t, s.insert(context.Background(), 100, [32]byte{'A'}, p, payloadHash, 1, 1))
_, err := s.insert(context.Background(), 100, [32]byte{'A'}, p, payloadHash, 1, 1)
require.NoError(t, err)
assert.Equal(t, 2, len(s.nodes), "Did not insert block")
assert.Equal(t, 2, len(s.nodesIndices), "Did not insert block")
assert.Equal(t, uint64(0), s.nodes[1].parent, "Incorrect parent")

View File

@@ -18,25 +18,27 @@ type ForkChoice struct {
// Store defines the fork choice store which includes block nodes and the last view of checkpoint information.
type Store struct {
pruneThreshold uint64 // do not prune tree unless threshold is reached.
justifiedCheckpoint *forkchoicetypes.Checkpoint // latest justified checkpoint in store.
bestJustifiedCheckpoint *forkchoicetypes.Checkpoint // best justified checkpoint in store.
prevJustifiedCheckpoint *forkchoicetypes.Checkpoint // previous justified checkpoint in store.
finalizedCheckpoint *forkchoicetypes.Checkpoint // latest finalized checkpoint in store.
proposerBoostRoot [fieldparams.RootLength]byte // latest block root that was boosted after being received in a timely manner.
previousProposerBoostRoot [fieldparams.RootLength]byte // previous block root that was boosted after being received in a timely manner.
previousProposerBoostScore uint64 // previous proposer boosted root score.
nodes []*Node // list of block nodes, each node is a representation of one block.
nodesIndices map[[fieldparams.RootLength]byte]uint64 // the root of block node and the nodes index in the list.
canonicalNodes map[[fieldparams.RootLength]byte]bool // the canonical block nodes.
payloadIndices map[[fieldparams.RootLength]byte]uint64 // the payload hash of block node and the index in the list
slashedIndices map[types.ValidatorIndex]bool // The list of equivocating validators
originRoot [fieldparams.RootLength]byte // The genesis block root
lastHeadRoot [fieldparams.RootLength]byte // The last cached head block root
nodesLock sync.RWMutex
proposerBoostLock sync.RWMutex
checkpointsLock sync.RWMutex
genesisTime uint64
pruneThreshold uint64 // do not prune tree unless threshold is reached.
justifiedCheckpoint *forkchoicetypes.Checkpoint // latest justified checkpoint in store.
bestJustifiedCheckpoint *forkchoicetypes.Checkpoint // best justified checkpoint in store.
unrealizedJustifiedCheckpoint *forkchoicetypes.Checkpoint // best justified checkpoint in store.
unrealizedFinalizedCheckpoint *forkchoicetypes.Checkpoint // best justified checkpoint in store.
prevJustifiedCheckpoint *forkchoicetypes.Checkpoint // previous justified checkpoint in store.
finalizedCheckpoint *forkchoicetypes.Checkpoint // latest finalized checkpoint in store.
proposerBoostRoot [fieldparams.RootLength]byte // latest block root that was boosted after being received in a timely manner.
previousProposerBoostRoot [fieldparams.RootLength]byte // previous block root that was boosted after being received in a timely manner.
previousProposerBoostScore uint64 // previous proposer boosted root score.
nodes []*Node // list of block nodes, each node is a representation of one block.
nodesIndices map[[fieldparams.RootLength]byte]uint64 // the root of block node and the nodes index in the list.
canonicalNodes map[[fieldparams.RootLength]byte]bool // the canonical block nodes.
payloadIndices map[[fieldparams.RootLength]byte]uint64 // the payload hash of block node and the index in the list
slashedIndices map[types.ValidatorIndex]bool // The list of equivocating validators
originRoot [fieldparams.RootLength]byte // The genesis block root
lastHeadRoot [fieldparams.RootLength]byte // The last cached head block root
nodesLock sync.RWMutex
proposerBoostLock sync.RWMutex
checkpointsLock sync.RWMutex
genesisTime uint64
}
// Node defines the individual block which includes its block parent, ancestor and how much weight accounted for it.

View File

@@ -56,10 +56,15 @@ func (f *ForkChoice) UpdateUnrealizedCheckpoints() {
node.justifiedEpoch = node.unrealizedJustifiedEpoch
node.finalizedEpoch = node.unrealizedFinalizedEpoch
if node.justifiedEpoch > f.store.justifiedCheckpoint.Epoch {
f.store.justifiedCheckpoint.Epoch = node.justifiedEpoch
if node.justifiedEpoch > f.store.bestJustifiedCheckpoint.Epoch {
f.store.bestJustifiedCheckpoint = f.store.unrealizedJustifiedCheckpoint
}
// shouldUpdate will always be true in slot 0
f.store.justifiedCheckpoint = f.store.unrealizedJustifiedCheckpoint
}
if node.finalizedEpoch > f.store.finalizedCheckpoint.Epoch {
f.store.finalizedCheckpoint.Epoch = node.finalizedEpoch
f.store.justifiedCheckpoint = f.store.unrealizedJustifiedCheckpoint
f.store.finalizedCheckpoint = f.store.unrealizedFinalizedCheckpoint
}
}
}

View File

@@ -147,6 +147,8 @@ func TestStore_NoDeadLock(t *testing.T) {
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
require.NoError(t, f.store.setUnrealizedJustifiedEpoch([32]byte{'g'}, 2))
require.NoError(t, f.store.setUnrealizedFinalizedEpoch([32]byte{'g'}, 1))
f.store.unrealizedJustifiedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: 2}
f.store.unrealizedFinalizedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: 1}
state, blkRoot, err = prepareForkchoiceState(ctx, 107, [32]byte{'h'}, [32]byte{'g'}, [32]byte{'H'}, 0, 0)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
@@ -236,6 +238,7 @@ func TestStore_ForkNextEpoch(t *testing.T) {
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
require.NoError(t, f.store.setUnrealizedJustifiedEpoch([32]byte{'d'}, 1))
f.store.unrealizedJustifiedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: 1}
f.UpdateUnrealizedCheckpoints()
headRoot, err = f.Head(ctx, []uint64{100})
require.NoError(t, err)

View File

@@ -224,7 +224,7 @@ type FutureForkStub interface {
AppendInactivityScore(s uint64) error
CurrentEpochParticipation() ([]byte, error)
PreviousEpochParticipation() ([]byte, error)
UnrealizedCheckpointBalances() (uint64, uint64, uint64, error)
UnrealizedCheckpointBalances(context.Context) (uint64, uint64, uint64, error)
InactivityScores() ([]uint64, error)
SetInactivityScores(val []uint64) error
CurrentSyncCommittee() (*ethpb.SyncCommittee, error)

View File

@@ -71,6 +71,7 @@ go_library(
"//encoding/ssz:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/attestation:go_default_library",
"//runtime/version:go_default_library",
"@com_github_ferranbt_fastssz//:go_default_library",
"@com_github_pkg_errors//:go_default_library",

View File

@@ -1,8 +1,15 @@
package state_native
import (
"bytes"
"context"
"errors"
"github.com/prysmaticlabs/prysm/beacon-chain/core/time"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
"github.com/prysmaticlabs/prysm/config/params"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/attestation"
"github.com/prysmaticlabs/prysm/runtime/version"
)
@@ -41,21 +48,67 @@ func (b *BeaconState) PreviousEpochParticipation() ([]byte, error) {
// UnrealizedCheckpointBalances returns the total balances: active, target attested in
// current epoch and target attested in previous epoch. This function is used to
// compute the "unrealized justification" that a synced Beacon Block will have.
func (b *BeaconState) UnrealizedCheckpointBalances() (uint64, uint64, uint64, error) {
if b.version == version.Phase0 {
return 0, 0, 0, errNotSupported("UnrealizedCheckpointBalances", b.version)
}
func (b *BeaconState) UnrealizedCheckpointBalances(ctx context.Context) (uint64, uint64, uint64, error) {
b.lock.RLock()
defer b.lock.RUnlock()
cp := b.currentEpochParticipation
pp := b.previousEpochParticipation
if cp == nil || pp == nil {
return 0, 0, 0, ErrNilParticipation
}
var cp, pp []byte
currentEpoch := time.CurrentEpoch(b)
if b.version == version.Phase0 {
targetIdx := params.BeaconConfig().TimelyTargetFlagIndex
//currentRoot, err := helpers.BlockRoot(b, currentEpoch)
//if err != nil {
// return 0, 0, 0, err
//}
cp := make([]byte, len(b.validators))
currAtt := b.currentEpochAttestations
pp := make([]byte, len(b.validators))
prevEpoch := currentEpoch
if prevEpoch > 0 {
prevEpoch--
}
//prevRoot, err := helpers.BlockRoot(b, prevEpoch)
//if err != nil {
// return 0, 0, 0, err
//}
prevAtt := b.previousEpochAttestations
for _, a := range append(prevAtt, currAtt...) {
if a.InclusionDelay == 0 {
return 0, 0, 0, errors.New("attestation with inclusion delay of 0")
}
currTarget := a.Data.Target.Epoch == currentEpoch && bytes.Equal(a.Data.Target.Root, []byte{})
prevTarget := a.Data.Target.Epoch == prevEpoch && bytes.Equal(a.Data.Target.Root, []byte{})
if currTarget || prevTarget {
//committee, err := helpers.BeaconCommitteeFromState(ctx, b, a.Data.Slot, a.Data.CommitteeIndex)
//if err != nil {
// return 0, 0, 0, err
//}
indices, err := attestation.AttestingIndices(a.AggregationBits, []types.ValidatorIndex{})
if err != nil {
return 0, 0, 0, err
}
for _, i := range indices {
if currTarget {
cp[i] = (1 << targetIdx)
}
if prevTarget {
pp[i] = (1 << targetIdx)
}
}
}
}
} else {
cp = b.currentEpochParticipation
pp = b.previousEpochParticipation
if cp == nil || pp == nil {
return 0, 0, 0, ErrNilParticipation
}
}
return stateutil.UnrealizedCheckpointBalances(cp, pp, b.validators, currentEpoch)
}

View File

@@ -1,6 +1,7 @@
package state_native
import (
"context"
"testing"
"github.com/prysmaticlabs/prysm/config/params"
@@ -9,6 +10,7 @@ import (
)
func TestState_UnrealizedCheckpointBalances(t *testing.T) {
ctx := context.Background()
validators := make([]*ethpb.Validator, params.BeaconConfig().MinGenesisActiveValidatorCount)
balances := make([]uint64, params.BeaconConfig().MinGenesisActiveValidatorCount)
for i := 0; i < len(validators); i++ {
@@ -32,7 +34,7 @@ func TestState_UnrealizedCheckpointBalances(t *testing.T) {
// No one voted in the last two epochs
allActive := params.BeaconConfig().MinGenesisActiveValidatorCount * params.BeaconConfig().MaxEffectiveBalance
active, previous, current, err := state.UnrealizedCheckpointBalances()
active, previous, current, err := state.UnrealizedCheckpointBalances(ctx)
require.NoError(t, err)
require.Equal(t, allActive, active)
require.Equal(t, uint64(0), current)
@@ -45,7 +47,7 @@ func TestState_UnrealizedCheckpointBalances(t *testing.T) {
state, err = InitializeFromProtoAltair(base)
require.NoError(t, err)
active, previous, current, err = state.UnrealizedCheckpointBalances()
active, previous, current, err = state.UnrealizedCheckpointBalances(ctx)
require.NoError(t, err)
require.Equal(t, allActive, active)
require.Equal(t, params.BeaconConfig().MaxEffectiveBalance, current)
@@ -55,7 +57,7 @@ func TestState_UnrealizedCheckpointBalances(t *testing.T) {
validators[0].Slashed = true
state, err = InitializeFromProtoAltair(base)
require.NoError(t, err)
active, previous, current, err = state.UnrealizedCheckpointBalances()
active, previous, current, err = state.UnrealizedCheckpointBalances(ctx)
require.NoError(t, err)
require.Equal(t, allActive-params.BeaconConfig().MaxEffectiveBalance, active)
require.Equal(t, uint64(0), current)

View File

@@ -8,6 +8,11 @@ import (
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
// UnrealizedCheckpointBalances returns the total current active balance, the
// total previous epoch correctly attested for target balance, and the total
// current epoch correctly attested for target balance. It takes the current and
// previous epoch participation bits as parameters so implicitly only works for
// beacon states post-Altair.
func UnrealizedCheckpointBalances(cp, pp []byte, validators []*ethpb.Validator, currentEpoch types.Epoch) (uint64, uint64, uint64, error) {
targetIdx := params.BeaconConfig().TimelyTargetFlagIndex
activeBalance := uint64(0)

View File

@@ -4,6 +4,7 @@ go_library(
name = "go_default_library",
srcs = [
"doc.go",
"error.go",
"field_roots.go",
"getters_attestation.go",
"getters_block.go",
@@ -32,6 +33,7 @@ go_library(
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/state/v1",
visibility = ["//visibility:public"],
deps = [
"//beacon-chain/core/time:go_default_library",
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/fieldtrie:go_default_library",
"//beacon-chain/state/state-native:go_default_library",
@@ -47,7 +49,9 @@ go_library(
"//encoding/ssz:go_default_library",
"//proto/engine/v1: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_prysmaticlabs_go_bitfield//:go_default_library",
"@io_opencensus_go//trace:go_default_library",

View File

@@ -0,0 +1,5 @@
package v1
import "errors"
var ErrNilParticipation = errors.New("nil epoch participation in state")

View File

@@ -1,10 +1,17 @@
package v1
import (
"bytes"
"context"
"errors"
"github.com/prysmaticlabs/prysm/beacon-chain/core/time"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
"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/proto/prysm/v1alpha1/attestation"
"github.com/prysmaticlabs/prysm/runtime/version"
)
@@ -161,3 +168,67 @@ func (b *BeaconState) balancesLength() int {
return len(b.state.Balances)
}
// UnrealizedCheckpointBalances returns the total balances: active, target attested in
// previous epoch and target attested in current epoch. This function is used to
// compute the "unrealized justification" that a synced Beacon Block will have.
// This function is less efficient than the corresponding function for Altair
// and Bellatrix types as it will not be used except in syncing from genesis and
// spectests.
func (b *BeaconState) UnrealizedCheckpointBalances(ctx context.Context) (uint64, uint64, uint64, error) {
if !b.hasInnerState() {
return 0, 0, 0, ErrNilInnerState
}
b.lock.RLock()
defer b.lock.RUnlock()
targetIdx := params.BeaconConfig().TimelyTargetFlagIndex
currentEpoch := time.CurrentEpoch(b)
var currentRoot []byte
//if slots.SinceEpochStarts(b.Slot()) > 0 {
// //currentRoot, err = helpers.BlockRoot(b, currentEpoch)
// //if err != nil {
// // return 0, 0, 0, err
// //}
//}
cp := make([]byte, len(b.state.Validators))
pp := make([]byte, len(b.state.Validators))
currAtt := b.state.CurrentEpochAttestations
prevEpoch := time.PrevEpoch(b)
//prevRoot, err := helpers.BlockRoot(b, prevEpoch)
//if err != nil {
// return 0, 0, 0, err
//}
prevAtt := b.state.PreviousEpochAttestations
for _, a := range append(prevAtt, currAtt...) {
if a.InclusionDelay == 0 {
return 0, 0, 0, errors.New("attestation with inclusion delay of 0")
}
currTarget := a.Data.Target.Epoch == currentEpoch && bytes.Equal(a.Data.Target.Root, currentRoot)
prevTarget := a.Data.Target.Epoch == prevEpoch && bytes.Equal(a.Data.Target.Root, []byte{})
if currTarget || prevTarget {
//committee, err := helpers.BeaconCommitteeFromState(ctx, b, a.Data.Slot, a.Data.CommitteeIndex)
//if err != nil {
// return 0, 0, 0, err
//}
indices, err := attestation.AttestingIndices(a.AggregationBits, []types.ValidatorIndex{})
if err != nil {
return 0, 0, 0, err
}
for _, i := range indices {
if currTarget {
cp[i] = (1 << targetIdx)
}
if prevTarget {
pp[i] = (1 << targetIdx)
}
}
}
}
return stateutil.UnrealizedCheckpointBalances(cp, pp, b.state.Validators, currentEpoch)
}

View File

@@ -1,12 +1,15 @@
package v1
import (
"context"
"runtime/debug"
"testing"
"time"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
testtmpl "github.com/prysmaticlabs/prysm/beacon-chain/state/testing"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
"github.com/prysmaticlabs/prysm/config/params"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/testing/require"
)
@@ -63,7 +66,7 @@ func TestNilState_NoPanic(t *testing.T) {
_ = st.PreviousJustifiedCheckpoint()
_ = st.CurrentJustifiedCheckpoint()
_ = st.FinalizedCheckpoint()
_, _, _, err = st.UnrealizedCheckpointBalances()
_, _, _, err = st.UnrealizedCheckpointBalances(context.Background())
_ = err
}
@@ -120,3 +123,35 @@ func TestBeaconState_ValidatorByPubkey(t *testing.T) {
return InitializeFromProto(&ethpb.BeaconState{})
})
}
func TestBeaconState_UnrealizedCheckpointBalances(t *testing.T) {
vals := make([]*ethpb.Validator, 10)
for i := 0; i < len(vals); i++ {
vals[i] = &ethpb.Validator{
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
}
}
prevAtt := &ethpb.PendingAttestation{
InclusionDelay: 1,
Data: &ethpb.AttestationData{
Slot: 65,
Target: &ethpb.Checkpoint{Epoch: 1},
Source: &ethpb.Checkpoint{Epoch: 0},
},
}
base := &ethpb.BeaconState{
GenesisTime: uint64(time.Now().Unix()) - 96*params.BeaconConfig().SecondsPerSlot,
Slot: 96,
Validators: vals,
PreviousEpochAttestations: []*ethpb.PendingAttestation{prevAtt},
}
b, err := InitializeFromProto(base)
require.NoError(t, err)
active, curr, prev, err := b.UnrealizedCheckpointBalances(context.Background())
require.NoError(t, err)
require.Equal(t, 10*params.BeaconConfig().MaxEffectiveBalance, active)
require.Equal(t, params.BeaconConfig().MinDepositAmount, curr)
require.Equal(t, params.BeaconConfig().MinDepositAmount, prev)
}

View File

@@ -16,11 +16,6 @@ func (*BeaconState) PreviousEpochParticipation() ([]byte, error) {
return nil, errors.New("PreviousEpochParticipation is not supported for phase 0 beacon state")
}
// UnrealizedCheckpointBalances is not supported for phase 0 beacon state.
func (*BeaconState) UnrealizedCheckpointBalances() (uint64, uint64, uint64, error) {
return 0, 0, 0, errors.New("UnrealizedCheckpointBalances is not supported for phase0 beacon state")
}
// InactivityScores is not supported for phase 0 beacon state.
func (*BeaconState) InactivityScores() ([]uint64, error) {
return nil, errors.New("InactivityScores is not supported for phase 0 beacon state")

View File

@@ -1,6 +1,8 @@
package v2
import (
"context"
"github.com/prysmaticlabs/prysm/beacon-chain/core/time"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
)
@@ -38,7 +40,7 @@ func (b *BeaconState) PreviousEpochParticipation() ([]byte, error) {
// UnrealizedCheckpointBalances returns the total balances: active, target attested in
// current epoch and target attested in previous epoch. This function is used to
// compute the "unrealized justification" that a synced Beacon Block will have.
func (b *BeaconState) UnrealizedCheckpointBalances() (uint64, uint64, uint64, error) {
func (b *BeaconState) UnrealizedCheckpointBalances(_ context.Context) (uint64, uint64, uint64, error) {
if !b.hasInnerState() {
return 0, 0, 0, ErrNilInnerState
}

View File

@@ -1,6 +1,7 @@
package v2
import (
"context"
"testing"
"github.com/prysmaticlabs/prysm/config/params"
@@ -32,7 +33,7 @@ func TestState_UnrealizedCheckpointBalances(t *testing.T) {
// No one voted in the last two epochs
allActive := params.BeaconConfig().MinGenesisActiveValidatorCount * params.BeaconConfig().MaxEffectiveBalance
active, previous, current, err := state.UnrealizedCheckpointBalances()
active, previous, current, err := state.UnrealizedCheckpointBalances(context.Background())
require.NoError(t, err)
require.Equal(t, allActive, active)
require.Equal(t, uint64(0), current)
@@ -45,7 +46,7 @@ func TestState_UnrealizedCheckpointBalances(t *testing.T) {
state, err = InitializeFromProto(base)
require.NoError(t, err)
active, previous, current, err = state.UnrealizedCheckpointBalances()
active, previous, current, err = state.UnrealizedCheckpointBalances(context.Background())
require.NoError(t, err)
require.Equal(t, allActive, active)
require.Equal(t, params.BeaconConfig().MaxEffectiveBalance, current)
@@ -55,7 +56,7 @@ func TestState_UnrealizedCheckpointBalances(t *testing.T) {
validators[0].Slashed = true
state, err = InitializeFromProto(base)
require.NoError(t, err)
active, previous, current, err = state.UnrealizedCheckpointBalances()
active, previous, current, err = state.UnrealizedCheckpointBalances(context.Background())
require.NoError(t, err)
require.Equal(t, allActive-params.BeaconConfig().MaxEffectiveBalance, active)
require.Equal(t, uint64(0), current)

View File

@@ -1,6 +1,7 @@
package v2
import (
"context"
"runtime/debug"
"testing"
@@ -74,7 +75,7 @@ func TestNilState_NoPanic(t *testing.T) {
require.ErrorIs(t, ErrNilInnerState, err)
_, err = st.NextSyncCommittee()
require.ErrorIs(t, ErrNilInnerState, err)
_, _, _, err = st.UnrealizedCheckpointBalances()
_, _, _, err = st.UnrealizedCheckpointBalances(context.Background())
require.ErrorIs(t, ErrNilInnerState, err)
}

View File

@@ -1,6 +1,8 @@
package v3
import (
"context"
"github.com/prysmaticlabs/prysm/beacon-chain/core/time"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
)
@@ -38,7 +40,7 @@ func (b *BeaconState) PreviousEpochParticipation() ([]byte, error) {
// UnrealizedCheckpointBalances returns the total balances: active, target attested in
// current epoch and target attested in previous epoch. This function is used to
// compute the "unrealized justification" that a synced Beacon Block will have.
func (b *BeaconState) UnrealizedCheckpointBalances() (uint64, uint64, uint64, error) {
func (b *BeaconState) UnrealizedCheckpointBalances(_ context.Context) (uint64, uint64, uint64, error) {
if !b.hasInnerState() {
return 0, 0, 0, ErrNilInnerState
}

View File

@@ -1,6 +1,7 @@
package v3
import (
"context"
"testing"
"github.com/prysmaticlabs/prysm/config/params"
@@ -32,7 +33,7 @@ func TestState_UnrealizedCheckpointBalances(t *testing.T) {
// No one voted in the last two epochs
allActive := params.BeaconConfig().MinGenesisActiveValidatorCount * params.BeaconConfig().MaxEffectiveBalance
active, previous, current, err := state.UnrealizedCheckpointBalances()
active, previous, current, err := state.UnrealizedCheckpointBalances(context.Background())
require.NoError(t, err)
require.Equal(t, allActive, active)
require.Equal(t, uint64(0), current)
@@ -45,7 +46,7 @@ func TestState_UnrealizedCheckpointBalances(t *testing.T) {
state, err = InitializeFromProto(base)
require.NoError(t, err)
active, previous, current, err = state.UnrealizedCheckpointBalances()
active, previous, current, err = state.UnrealizedCheckpointBalances(context.Background())
require.NoError(t, err)
require.Equal(t, allActive, active)
require.Equal(t, params.BeaconConfig().MaxEffectiveBalance, current)
@@ -55,7 +56,7 @@ func TestState_UnrealizedCheckpointBalances(t *testing.T) {
validators[0].Slashed = true
state, err = InitializeFromProto(base)
require.NoError(t, err)
active, previous, current, err = state.UnrealizedCheckpointBalances()
active, previous, current, err = state.UnrealizedCheckpointBalances(context.Background())
require.NoError(t, err)
require.Equal(t, allActive-params.BeaconConfig().MaxEffectiveBalance, active)
require.Equal(t, uint64(0), current)

View File

@@ -1,6 +1,7 @@
package v3
import (
"context"
"runtime/debug"
"testing"
@@ -75,7 +76,7 @@ func TestNilState_NoPanic(t *testing.T) {
require.ErrorIs(t, ErrNilInnerState, err)
_, err = st.LatestExecutionPayloadHeader()
require.ErrorIs(t, ErrNilInnerState, err)
_, _, _, err = st.UnrealizedCheckpointBalances()
_, _, _, err = st.UnrealizedCheckpointBalances(context.Background())
require.ErrorIs(t, ErrNilInnerState, err)
}

View File

@@ -61,6 +61,7 @@ type Flags struct {
EnableSlashingProtectionPruning bool
EnableNativeState bool // EnableNativeState defines whether the beacon state will be represented as a pure Go struct or a Go struct that wraps a proto struct.
PullTips bool // Experimental disable of boundary checks
EnableVectorizedHTR bool // EnableVectorizedHTR specifies whether the beacon state will use the optimized sha256 routines.
EnableForkChoiceDoublyLinkedTree bool // EnableForkChoiceDoublyLinkedTree specifies whether fork choice store will use a doubly linked tree.
EnableBatchGossipAggregation bool // EnableBatchGossipAggregation specifies whether to further aggregate our gossip batches before verifying them.
@@ -211,6 +212,10 @@ func ConfigureBeaconChain(ctx *cli.Context) error {
logDisabled(disableNativeState)
cfg.EnableNativeState = false
}
if ctx.Bool(pullTips.Name) {
logEnabled(pullTips)
cfg.PullTips = true
}
if ctx.Bool(enableVecHTR.Name) {
logEnabled(enableVecHTR)
cfg.EnableVectorizedHTR = true

View File

@@ -105,6 +105,12 @@ var (
Name: "disable-native-state",
Usage: "Disables representing the beacon state as a pure Go struct.",
}
pullTips = &cli.BoolFlag{
Name: "experimental-disable-boundary-checks",
Usage: "Experimental disable of boundary checks, useful for debugging, may cause bad votes.",
}
enableVecHTR = &cli.BoolFlag{
Name: "enable-vectorized-htr",
Usage: "Enables new go sha256 library which utilizes optimized routines for merkle trees",
@@ -163,6 +169,7 @@ var BeaconChainFlags = append(deprecatedFlags, []cli.Flag{
enableSlasherFlag,
enableHistoricalSpaceRepresentation,
disableNativeState,
pullTips,
enableVecHTR,
enableForkChoiceDoublyLinkedTree,
enableGossipBatchAggregation,

2
go.mod
View File

@@ -88,6 +88,7 @@ require (
golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064
golang.org/x/exp v0.0.0-20200513190911-00229845015e
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/tools v0.1.11-0.20220523181440-ccb10502d1a5
google.golang.org/genproto v0.0.0-20210426193834-eac7f76ac494
@@ -237,7 +238,6 @@ require (
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
go.uber.org/zap v1.21.0 // indirect
golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect

View File

@@ -9,11 +9,16 @@ import (
)
func TestMinimal_Altair_Forkchoice(t *testing.T) {
resetCfg := features.InitWithReset(&features.Flags{
PullTips: true,
})
defer resetCfg()
forkchoice.Run(t, "minimal", version.Altair)
}
func TestMinimal_Altair_Forkchoice_DoublyLinkTre(t *testing.T) {
resetCfg := features.InitWithReset(&features.Flags{
PullTips: true,
EnableForkChoiceDoublyLinkedTree: true,
})
defer resetCfg()

View File

@@ -9,11 +9,16 @@ import (
)
func TestMinimal_Bellatrix_Forkchoice(t *testing.T) {
resetCfg := features.InitWithReset(&features.Flags{
PullTips: true,
})
defer resetCfg()
forkchoice.Run(t, "minimal", version.Bellatrix)
}
func TestMinimal_Bellatrix_Forkchoice_DoublyLinkTree(t *testing.T) {
resetCfg := features.InitWithReset(&features.Flags{
PullTips: true,
EnableForkChoiceDoublyLinkedTree: true,
})
defer resetCfg()

View File

@@ -9,11 +9,16 @@ import (
)
func TestMinimal_Altair_Forkchoice(t *testing.T) {
resetCfg := features.InitWithReset(&features.Flags{
PullTips: true,
})
defer resetCfg()
forkchoice.Run(t, "minimal", version.Phase0)
}
func TestMinimal_Altair_Forkchoice_DoublyLinkTre(t *testing.T) {
resetCfg := features.InitWithReset(&features.Flags{
PullTips: true,
EnableForkChoiceDoublyLinkedTree: true,
})
defer resetCfg()

View File

@@ -31,12 +31,12 @@ func startChainService(t testing.TB, st state.BeaconState, block interfaces.Sign
r, err := block.Block().HashTreeRoot()
require.NoError(t, err)
require.NoError(t, db.SaveGenesisBlockRoot(ctx, r))
require.NoError(t, db.SaveState(ctx, st, r))
cp := &ethpb.Checkpoint{
Epoch: coreTime.CurrentEpoch(st),
Root: r[:],
}
require.NoError(t, db.SaveState(ctx, st, r))
require.NoError(t, db.SaveJustifiedCheckpoint(ctx, cp))
require.NoError(t, db.SaveFinalizedCheckpoint(ctx, cp))
attPool, err := attestations.NewService(ctx, &attestations.Config{