mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 13:58:09 -05:00
Compare commits
18 Commits
v5.0.2-rc.
...
community_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7614707f9b | ||
|
|
38f208d70d | ||
|
|
65b90abdda | ||
|
|
f3b49d4eaf | ||
|
|
5b1da7353c | ||
|
|
9f17e65860 | ||
|
|
9b2d53b0d1 | ||
|
|
d6f9196707 | ||
|
|
1b0e09369e | ||
|
|
12482eeb40 | ||
|
|
acc307b959 | ||
|
|
c1d75c295a | ||
|
|
fad118cb04 | ||
|
|
cdd1d819df | ||
|
|
97edffaff5 | ||
|
|
6de7df6b9d | ||
|
|
14d7416c16 | ||
|
|
6782df917a |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -41,3 +41,6 @@ jwt.hex
|
||||
|
||||
# manual testing
|
||||
tmp
|
||||
|
||||
# spectest coverage reports
|
||||
report.txt
|
||||
|
||||
2
bazel.sh
2
bazel.sh
@@ -2,7 +2,7 @@
|
||||
|
||||
# This script serves as a wrapper around bazel to limit the scope of environment variables that
|
||||
# may change the action output. Using this script should result in a higher cache hit ratio for
|
||||
# cached actions with a more heremtic build.
|
||||
# cached actions with a more hermetic build.
|
||||
|
||||
env -i \
|
||||
PATH=/usr/bin:/bin \
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
prysmTime "github.com/prysmaticlabs/prysm/v5/time"
|
||||
"github.com/prysmaticlabs/prysm/v5/time/slots"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -133,9 +132,6 @@ func ComputeSubnetFromCommitteeAndSlot(activeValCount uint64, comIdx primitives.
|
||||
//
|
||||
// In the attestation must be within the range of 95 to 102 in the example above.
|
||||
func ValidateAttestationTime(attSlot primitives.Slot, genesisTime time.Time, clockDisparity time.Duration) error {
|
||||
if err := slots.ValidateClock(attSlot, uint64(genesisTime.Unix())); err != nil {
|
||||
return err
|
||||
}
|
||||
attTime, err := slots.ToTime(uint64(genesisTime.Unix()), attSlot)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -182,24 +178,15 @@ func ValidateAttestationTime(attSlot primitives.Slot, genesisTime time.Time, clo
|
||||
}
|
||||
|
||||
// EIP-7045: Starting in Deneb, allow any attestations from the current or previous epoch.
|
||||
|
||||
currentEpoch := slots.ToEpoch(currentSlot)
|
||||
prevEpoch, err := currentEpoch.SafeSub(1)
|
||||
if err != nil {
|
||||
log.WithError(err).Debug("Ignoring underflow for a deneb attestation inclusion check in epoch 0")
|
||||
prevEpoch = 0
|
||||
}
|
||||
attSlotEpoch := slots.ToEpoch(attSlot)
|
||||
if attSlotEpoch != currentEpoch && attSlotEpoch != prevEpoch {
|
||||
if attEpoch+1 < currentEpoch {
|
||||
attError = fmt.Errorf(
|
||||
"attestation epoch %d not within current epoch %d or previous epoch %d",
|
||||
attSlot/params.BeaconConfig().SlotsPerEpoch,
|
||||
"attestation epoch %d not within current epoch %d or previous epoch",
|
||||
attEpoch,
|
||||
currentEpoch,
|
||||
prevEpoch,
|
||||
)
|
||||
return errors.Join(ErrTooLate, attError)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -197,7 +197,7 @@ func Test_ValidateAttestationTime(t *testing.T) {
|
||||
-500 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second,
|
||||
).Add(200 * time.Millisecond),
|
||||
},
|
||||
wantedErr: "attestation epoch 8 not within current epoch 15 or previous epoch 14",
|
||||
wantedErr: "attestation epoch 8 not within current epoch 15 or previous epoch",
|
||||
},
|
||||
{
|
||||
name: "attestation.slot is well beyond current slot",
|
||||
@@ -205,7 +205,7 @@ func Test_ValidateAttestationTime(t *testing.T) {
|
||||
attSlot: 1 << 32,
|
||||
genesisTime: prysmTime.Now().Add(-15 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second),
|
||||
},
|
||||
wantedErr: "which exceeds max allowed value relative to the local clock",
|
||||
wantedErr: "attestation slot 4294967296 not within attestation propagation range of 0 to 15 (current slot)",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
|
||||
@@ -118,7 +118,7 @@ type HeadAccessDatabase interface {
|
||||
// SlasherDatabase interface for persisting data related to detecting slashable offenses on Ethereum.
|
||||
type SlasherDatabase interface {
|
||||
io.Closer
|
||||
SaveLastEpochsWrittenForValidators(
|
||||
SaveLastEpochWrittenForValidators(
|
||||
ctx context.Context, epochByValidator map[primitives.ValidatorIndex]primitives.Epoch,
|
||||
) error
|
||||
SaveAttestationRecordsForValidators(
|
||||
|
||||
@@ -20,6 +20,7 @@ go_library(
|
||||
"migration.go",
|
||||
"migration_archived_index.go",
|
||||
"migration_block_slot_index.go",
|
||||
"migration_finalized_parent.go",
|
||||
"migration_state_validators.go",
|
||||
"schema.go",
|
||||
"state.go",
|
||||
|
||||
@@ -224,7 +224,7 @@ func (s *Store) DeleteBlock(ctx context.Context, root [32]byte) error {
|
||||
return s.db.Update(func(tx *bolt.Tx) error {
|
||||
bkt := tx.Bucket(finalizedBlockRootsIndexBucket)
|
||||
if b := bkt.Get(root[:]); b != nil {
|
||||
return ErrDeleteFinalized
|
||||
return ErrDeleteJustifiedAndFinalized
|
||||
}
|
||||
|
||||
if err := tx.Bucket(blocksBucket).Delete(root[:]); err != nil {
|
||||
|
||||
@@ -289,7 +289,7 @@ func TestStore_DeleteBlock(t *testing.T) {
|
||||
require.Equal(t, b, nil)
|
||||
require.Equal(t, false, db.HasStateSummary(ctx, root2))
|
||||
|
||||
require.ErrorIs(t, db.DeleteBlock(ctx, root), ErrDeleteFinalized)
|
||||
require.ErrorIs(t, db.DeleteBlock(ctx, root), ErrDeleteJustifiedAndFinalized)
|
||||
}
|
||||
|
||||
func TestStore_DeleteJustifiedBlock(t *testing.T) {
|
||||
@@ -309,7 +309,7 @@ func TestStore_DeleteJustifiedBlock(t *testing.T) {
|
||||
require.NoError(t, db.SaveBlock(ctx, blk))
|
||||
require.NoError(t, db.SaveState(ctx, st, root))
|
||||
require.NoError(t, db.SaveJustifiedCheckpoint(ctx, cp))
|
||||
require.ErrorIs(t, db.DeleteBlock(ctx, root), ErrDeleteFinalized)
|
||||
require.ErrorIs(t, db.DeleteBlock(ctx, root), ErrDeleteJustifiedAndFinalized)
|
||||
}
|
||||
|
||||
func TestStore_DeleteFinalizedBlock(t *testing.T) {
|
||||
@@ -329,7 +329,7 @@ func TestStore_DeleteFinalizedBlock(t *testing.T) {
|
||||
require.NoError(t, db.SaveState(ctx, st, root))
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, root))
|
||||
require.NoError(t, db.SaveFinalizedCheckpoint(ctx, cp))
|
||||
require.ErrorIs(t, db.DeleteBlock(ctx, root), ErrDeleteFinalized)
|
||||
require.ErrorIs(t, db.DeleteBlock(ctx, root), ErrDeleteJustifiedAndFinalized)
|
||||
}
|
||||
func TestStore_GenesisBlock(t *testing.T) {
|
||||
db := setupDB(t)
|
||||
|
||||
@@ -2,8 +2,8 @@ package kv
|
||||
|
||||
import "github.com/pkg/errors"
|
||||
|
||||
// ErrDeleteFinalized is raised when we attempt to delete a finalized block/state
|
||||
var ErrDeleteFinalized = errors.New("cannot delete finalized block or state")
|
||||
// ErrDeleteJustifiedAndFinalized is raised when we attempt to delete a finalized block/state
|
||||
var ErrDeleteJustifiedAndFinalized = errors.New("cannot delete finalized block or state")
|
||||
|
||||
// ErrNotFound can be used directly, or as a wrapped DBError, whenever a db method needs to
|
||||
// indicate that a value couldn't be found.
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/db/filters"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
|
||||
@@ -28,76 +29,72 @@ var containerFinalizedButNotCanonical = []byte("recent block needs reindexing to
|
||||
// beacon block chain using the finalized root alone as this would exclude all other blocks in the
|
||||
// finalized epoch from being indexed as "final and canonical".
|
||||
//
|
||||
// The main part of the algorithm traverses parent->child block relationships in the
|
||||
// `blockParentRootIndicesBucket` bucket to find the path between the last finalized checkpoint
|
||||
// and the current finalized checkpoint. It relies on the invariant that there is a unique path
|
||||
// between two finalized checkpoints.
|
||||
// The algorithm for building the index works as follows:
|
||||
// - De-index all finalized beacon block roots from previous_finalized_epoch to
|
||||
// new_finalized_epoch. (I.e. delete these roots from the index, to be re-indexed.)
|
||||
// - Build the canonical finalized chain by walking up the ancestry chain from the finalized block
|
||||
// root until a parent is found in the index, or the parent is genesis or the origin checkpoint.
|
||||
// - Add all block roots in the database where epoch(block.slot) == checkpoint.epoch.
|
||||
//
|
||||
// This method ensures that all blocks from the current finalized epoch are considered "final" while
|
||||
// maintaining only canonical and finalized blocks older than the current finalized epoch.
|
||||
func (s *Store) updateFinalizedBlockRoots(ctx context.Context, tx *bolt.Tx, checkpoint *ethpb.Checkpoint) error {
|
||||
ctx, span := trace.StartSpan(ctx, "BeaconDB.updateFinalizedBlockRoots")
|
||||
defer span.End()
|
||||
|
||||
finalizedBkt := tx.Bucket(finalizedBlockRootsIndexBucket)
|
||||
bkt := tx.Bucket(finalizedBlockRootsIndexBucket)
|
||||
|
||||
root := checkpoint.Root
|
||||
var previousRoot []byte
|
||||
genesisRoot := tx.Bucket(blocksBucket).Get(genesisBlockRootKey)
|
||||
initCheckpointRoot := tx.Bucket(blocksBucket).Get(originCheckpointBlockRootKey)
|
||||
|
||||
// De-index recent finalized block roots, to be re-indexed.
|
||||
previousFinalizedCheckpoint := ðpb.Checkpoint{}
|
||||
if b := finalizedBkt.Get(previousFinalizedCheckpointKey); b != nil {
|
||||
if b := bkt.Get(previousFinalizedCheckpointKey); b != nil {
|
||||
if err := decode(ctx, b, previousFinalizedCheckpoint); err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the case of checkpoint sync.
|
||||
if previousFinalizedCheckpoint.Root == nil && bytes.Equal(checkpoint.Root, tx.Bucket(blocksBucket).Get(originCheckpointBlockRootKey)) {
|
||||
container := ðpb.FinalizedBlockRootContainer{}
|
||||
enc, err := encode(ctx, container)
|
||||
blockRoots, err := s.BlockRoots(ctx, filters.NewFilter().
|
||||
SetStartEpoch(previousFinalizedCheckpoint.Epoch).
|
||||
SetEndEpoch(checkpoint.Epoch+1),
|
||||
)
|
||||
if err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
for _, root := range blockRoots {
|
||||
if err := bkt.Delete(root[:]); err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Walk up the ancestry chain until we reach a block root present in the finalized block roots
|
||||
// index bucket or genesis block root.
|
||||
for {
|
||||
if bytes.Equal(root, genesisRoot) {
|
||||
break
|
||||
}
|
||||
|
||||
signedBlock, err := s.Block(ctx, bytesutil.ToBytes32(root))
|
||||
if err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
if err = finalizedBkt.Put(checkpoint.Root, enc); err != nil {
|
||||
if err := blocks.BeaconBlockIsNil(signedBlock); err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
return updatePrevFinalizedCheckpoint(ctx, span, finalizedBkt, checkpoint)
|
||||
}
|
||||
block := signedBlock.Block()
|
||||
|
||||
var finalized [][]byte
|
||||
if previousFinalizedCheckpoint.Root == nil {
|
||||
genesisRoot := tx.Bucket(blocksBucket).Get(genesisBlockRootKey)
|
||||
_, finalized = pathToFinalizedCheckpoint(ctx, [][]byte{genesisRoot}, checkpoint.Root, tx)
|
||||
} else {
|
||||
if err := updateChildOfPrevFinalizedCheckpoint(
|
||||
ctx,
|
||||
span,
|
||||
finalizedBkt,
|
||||
tx.Bucket(blockParentRootIndicesBucket), previousFinalizedCheckpoint.Root,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
_, finalized = pathToFinalizedCheckpoint(ctx, [][]byte{previousFinalizedCheckpoint.Root}, checkpoint.Root, tx)
|
||||
}
|
||||
|
||||
for i, r := range finalized {
|
||||
var container *ethpb.FinalizedBlockRootContainer
|
||||
switch i {
|
||||
case 0:
|
||||
container = ðpb.FinalizedBlockRootContainer{
|
||||
ParentRoot: previousFinalizedCheckpoint.Root,
|
||||
}
|
||||
if len(finalized) > 1 {
|
||||
container.ChildRoot = finalized[i+1]
|
||||
}
|
||||
case len(finalized) - 1:
|
||||
// We don't know the finalized child of the new finalized checkpoint.
|
||||
// It will be filled out in the next function call.
|
||||
container = ðpb.FinalizedBlockRootContainer{}
|
||||
if len(finalized) > 1 {
|
||||
container.ParentRoot = finalized[i-1]
|
||||
}
|
||||
default:
|
||||
container = ðpb.FinalizedBlockRootContainer{
|
||||
ParentRoot: finalized[i-1],
|
||||
ChildRoot: finalized[i+1],
|
||||
}
|
||||
parentRoot := block.ParentRoot()
|
||||
container := ðpb.FinalizedBlockRootContainer{
|
||||
ParentRoot: parentRoot[:],
|
||||
ChildRoot: previousRoot,
|
||||
}
|
||||
|
||||
enc, err := encode(ctx, container)
|
||||
@@ -105,13 +102,66 @@ func (s *Store) updateFinalizedBlockRoots(ctx context.Context, tx *bolt.Tx, chec
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
if err = finalizedBkt.Put(r, enc); err != nil {
|
||||
if err := bkt.Put(root, enc); err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
|
||||
// breaking here allows the initial checkpoint root to be correctly inserted,
|
||||
// but stops the loop from trying to search for its parent.
|
||||
if bytes.Equal(root, initCheckpointRoot) {
|
||||
break
|
||||
}
|
||||
|
||||
// Found parent, loop exit condition.
|
||||
pr := block.ParentRoot()
|
||||
if parentBytes := bkt.Get(pr[:]); parentBytes != nil {
|
||||
parent := ðpb.FinalizedBlockRootContainer{}
|
||||
if err := decode(ctx, parentBytes, parent); err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
parent.ChildRoot = root
|
||||
enc, err := encode(ctx, parent)
|
||||
if err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
if err := bkt.Put(pr[:], enc); err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
break
|
||||
}
|
||||
previousRoot = root
|
||||
root = pr[:]
|
||||
}
|
||||
|
||||
// Upsert blocks from the current finalized epoch.
|
||||
roots, err := s.BlockRoots(ctx, filters.NewFilter().SetStartEpoch(checkpoint.Epoch).SetEndEpoch(checkpoint.Epoch+1))
|
||||
if err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
for _, root := range roots {
|
||||
root := root[:]
|
||||
if bytes.Equal(root, checkpoint.Root) || bkt.Get(root) != nil {
|
||||
continue
|
||||
}
|
||||
if err := bkt.Put(root, containerFinalizedButNotCanonical); err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return updatePrevFinalizedCheckpoint(ctx, span, finalizedBkt, checkpoint)
|
||||
// Update previous checkpoint
|
||||
enc, err := encode(ctx, checkpoint)
|
||||
if err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
|
||||
return bkt.Put(previousFinalizedCheckpointKey, enc)
|
||||
}
|
||||
|
||||
// BackfillFinalizedIndex updates the finalized index for a contiguous chain of blocks that are the ancestors of the
|
||||
@@ -192,6 +242,8 @@ func (s *Store) BackfillFinalizedIndex(ctx context.Context, blocks []blocks.ROBl
|
||||
|
||||
// IsFinalizedBlock returns true if the block root is present in the finalized block root index.
|
||||
// A beacon block root contained exists in this index if it is considered finalized and canonical.
|
||||
// Note: beacon blocks from the latest finalized epoch return true, whether or not they are
|
||||
// considered canonical in the "head view" of the beacon node.
|
||||
func (s *Store) IsFinalizedBlock(ctx context.Context, blockRoot [32]byte) bool {
|
||||
_, span := trace.StartSpan(ctx, "BeaconDB.IsFinalizedBlock")
|
||||
defer span.End()
|
||||
@@ -244,53 +296,3 @@ func (s *Store) FinalizedChildBlock(ctx context.Context, blockRoot [32]byte) (in
|
||||
tracing.AnnotateError(span, err)
|
||||
return blk, err
|
||||
}
|
||||
|
||||
func pathToFinalizedCheckpoint(ctx context.Context, roots [][]byte, checkpointRoot []byte, tx *bolt.Tx) (bool, [][]byte) {
|
||||
if len(roots) == 0 || (len(roots) == 1 && roots[0] == nil) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
for _, r := range roots {
|
||||
if bytes.Equal(r, checkpointRoot) {
|
||||
return true, [][]byte{r}
|
||||
}
|
||||
children := lookupValuesForIndices(ctx, map[string][]byte{string(blockParentRootIndicesBucket): r}, tx)
|
||||
if len(children) == 0 {
|
||||
children = [][][]byte{nil}
|
||||
}
|
||||
isPath, path := pathToFinalizedCheckpoint(ctx, children[0], checkpointRoot, tx)
|
||||
if isPath {
|
||||
return true, append([][]byte{r}, path...)
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func updatePrevFinalizedCheckpoint(ctx context.Context, span *trace.Span, finalizedBkt *bolt.Bucket, checkpoint *ethpb.Checkpoint) error {
|
||||
enc, err := encode(ctx, checkpoint)
|
||||
if err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
return finalizedBkt.Put(previousFinalizedCheckpointKey, enc)
|
||||
}
|
||||
|
||||
func updateChildOfPrevFinalizedCheckpoint(ctx context.Context, span *trace.Span, finalizedBkt, parentBkt *bolt.Bucket, checkpointRoot []byte) error {
|
||||
container := ðpb.FinalizedBlockRootContainer{}
|
||||
if err := decode(ctx, finalizedBkt.Get(checkpointRoot), container); err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
container.ChildRoot = parentBkt.Get(checkpointRoot)
|
||||
enc, err := encode(ctx, container)
|
||||
if err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
if err = finalizedBkt.Put(checkpointRoot, enc); err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -26,30 +26,38 @@ func TestStore_IsFinalizedBlock(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesisBlockRoot))
|
||||
blks := makeBlocks(t, 0, slotsPerEpoch*2, genesisBlockRoot)
|
||||
|
||||
blks := makeBlocks(t, 0, slotsPerEpoch*3, genesisBlockRoot)
|
||||
require.NoError(t, db.SaveBlocks(ctx, blks))
|
||||
|
||||
root, err := blks[slotsPerEpoch].Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
cp := ðpb.Checkpoint{
|
||||
Epoch: 1,
|
||||
Root: root[:],
|
||||
}
|
||||
|
||||
st, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
// a state is required to save checkpoint
|
||||
require.NoError(t, db.SaveState(ctx, st, root))
|
||||
require.NoError(t, db.SaveFinalizedCheckpoint(ctx, cp))
|
||||
|
||||
for i := uint64(0); i <= slotsPerEpoch; i++ {
|
||||
root, err = blks[i].Block().HashTreeRoot()
|
||||
// All blocks up to slotsPerEpoch*2 should be in the finalized index.
|
||||
for i := uint64(0); i < slotsPerEpoch*2; i++ {
|
||||
root, err := blks[i].Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, db.IsFinalizedBlock(ctx, root), "Block at index %d was not considered finalized", i)
|
||||
assert.Equal(t, true, db.IsFinalizedBlock(ctx, root), "Block at index %d was not considered finalized in the index", i)
|
||||
}
|
||||
for i := slotsPerEpoch + 1; i < uint64(len(blks)); i++ {
|
||||
root, err = blks[i].Block().HashTreeRoot()
|
||||
for i := slotsPerEpoch * 3; i < uint64(len(blks)); i++ {
|
||||
root, err := blks[i].Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, false, db.IsFinalizedBlock(ctx, root), "Block at index %d was considered finalized, but should not have", i)
|
||||
assert.Equal(t, false, db.IsFinalizedBlock(ctx, root), "Block at index %d was considered finalized in the index, but should not have", i)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStore_IsFinalizedGenesisBlock(t *testing.T) {
|
||||
func TestStore_IsFinalizedBlockGenesis(t *testing.T) {
|
||||
db := setupDB(t)
|
||||
ctx := context.Background()
|
||||
|
||||
@@ -61,114 +69,136 @@ func TestStore_IsFinalizedGenesisBlock(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.SaveBlock(ctx, wsb))
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, root))
|
||||
assert.Equal(t, true, db.IsFinalizedBlock(ctx, root))
|
||||
assert.Equal(t, true, db.IsFinalizedBlock(ctx, root), "Finalized genesis block doesn't exist in db")
|
||||
}
|
||||
|
||||
// This test scenario is to test a specific edge case where the finalized block root is not part of
|
||||
// the finalized and canonical chain.
|
||||
//
|
||||
// Example:
|
||||
// 0 1 2 3 4 5 6 slot
|
||||
// a <- b <-- d <- e <- f <- g roots
|
||||
//
|
||||
// ^- c
|
||||
//
|
||||
// Imagine that epochs are 2 slots and that epoch 1, 2, and 3 are finalized. Checkpoint roots would
|
||||
// be c, e, and g. In this scenario, c was a finalized checkpoint root but no block built upon it so
|
||||
// it should not be considered "final and canonical" in the view at slot 6.
|
||||
func TestStore_IsFinalized_ForkEdgeCase(t *testing.T) {
|
||||
slotsPerEpoch := uint64(params.BeaconConfig().SlotsPerEpoch)
|
||||
blocks0 := makeBlocks(t, slotsPerEpoch*0, slotsPerEpoch, genesisBlockRoot)
|
||||
blocks1 := append(
|
||||
makeBlocks(t, slotsPerEpoch*1, 1, bytesutil.ToBytes32(sszRootOrDie(t, blocks0[len(blocks0)-1]))), // No block builds off of the first block in epoch.
|
||||
makeBlocks(t, slotsPerEpoch*1+1, slotsPerEpoch-1, bytesutil.ToBytes32(sszRootOrDie(t, blocks0[len(blocks0)-1])))...,
|
||||
)
|
||||
blocks2 := makeBlocks(t, slotsPerEpoch*2, slotsPerEpoch, bytesutil.ToBytes32(sszRootOrDie(t, blocks1[len(blocks1)-1])))
|
||||
|
||||
db := setupDB(t)
|
||||
ctx := context.Background()
|
||||
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesisBlockRoot))
|
||||
require.NoError(t, db.SaveBlocks(ctx, blocks0))
|
||||
require.NoError(t, db.SaveBlocks(ctx, blocks1))
|
||||
require.NoError(t, db.SaveBlocks(ctx, blocks2))
|
||||
|
||||
// First checkpoint
|
||||
checkpoint1 := ðpb.Checkpoint{
|
||||
Root: sszRootOrDie(t, blocks1[0]),
|
||||
Epoch: 1,
|
||||
}
|
||||
|
||||
st, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
// A state is required to save checkpoint
|
||||
require.NoError(t, db.SaveState(ctx, st, bytesutil.ToBytes32(checkpoint1.Root)))
|
||||
require.NoError(t, db.SaveFinalizedCheckpoint(ctx, checkpoint1))
|
||||
// All blocks in blocks0 and blocks1 should be finalized and canonical.
|
||||
for i, block := range append(blocks0, blocks1...) {
|
||||
root := sszRootOrDie(t, block)
|
||||
assert.Equal(t, true, db.IsFinalizedBlock(ctx, bytesutil.ToBytes32(root)), "%d - Expected block %#x to be finalized", i, root)
|
||||
}
|
||||
|
||||
// Second checkpoint
|
||||
checkpoint2 := ðpb.Checkpoint{
|
||||
Root: sszRootOrDie(t, blocks2[0]),
|
||||
Epoch: 2,
|
||||
}
|
||||
// A state is required to save checkpoint
|
||||
require.NoError(t, db.SaveState(ctx, st, bytesutil.ToBytes32(checkpoint2.Root)))
|
||||
require.NoError(t, db.SaveFinalizedCheckpoint(ctx, checkpoint2))
|
||||
// All blocks in blocks0 and blocks2 should be finalized and canonical.
|
||||
for i, block := range append(blocks0, blocks2...) {
|
||||
root := sszRootOrDie(t, block)
|
||||
assert.Equal(t, true, db.IsFinalizedBlock(ctx, bytesutil.ToBytes32(root)), "%d - Expected block %#x to be finalized", i, root)
|
||||
}
|
||||
// All blocks in blocks1 should be finalized and canonical, except blocks1[0].
|
||||
for i, block := range blocks1 {
|
||||
root := sszRootOrDie(t, block)
|
||||
if db.IsFinalizedBlock(ctx, bytesutil.ToBytes32(root)) == (i == 0) {
|
||||
t.Errorf("Expected db.IsFinalizedBlock(ctx, blocks1[%d]) to be %v", i, i != 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStore_IsFinalizedChildBlock(t *testing.T) {
|
||||
slotsPerEpoch := uint64(params.BeaconConfig().SlotsPerEpoch)
|
||||
ctx := context.Background()
|
||||
db := setupDB(t)
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesisBlockRoot))
|
||||
|
||||
blks := makeBlocks(t, 0, slotsPerEpoch*2, genesisBlockRoot)
|
||||
require.NoError(t, db.SaveBlocks(ctx, blks))
|
||||
root, err := blks[slotsPerEpoch].Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
cp := ðpb.Checkpoint{
|
||||
Epoch: 1,
|
||||
Root: root[:],
|
||||
}
|
||||
require.NoError(t, db.SaveFinalizedCheckpoint(ctx, cp))
|
||||
|
||||
for i := uint64(0); i < slotsPerEpoch; i++ {
|
||||
root, err = blks[i].Block().HashTreeRoot()
|
||||
eval := func(t testing.TB, ctx context.Context, db *Store, blks []interfaces.ReadOnlySignedBeaconBlock) {
|
||||
require.NoError(t, db.SaveBlocks(ctx, blks))
|
||||
root, err := blks[slotsPerEpoch].Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, db.IsFinalizedBlock(ctx, root), "Block at index %d was not considered finalized", i)
|
||||
blk, err := db.FinalizedChildBlock(ctx, root)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, blk == nil, "Child block at index %d was not considered finalized", i)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStore_ChildRootOfPrevFinalizedCheckpointIsUpdated(t *testing.T) {
|
||||
slotsPerEpoch := uint64(params.BeaconConfig().SlotsPerEpoch)
|
||||
ctx := context.Background()
|
||||
db := setupDB(t)
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesisBlockRoot))
|
||||
cp := ðpb.Checkpoint{
|
||||
Epoch: 1,
|
||||
Root: root[:],
|
||||
}
|
||||
|
||||
blks := makeBlocks(t, 0, slotsPerEpoch*3, genesisBlockRoot)
|
||||
require.NoError(t, db.SaveBlocks(ctx, blks))
|
||||
root, err := blks[slotsPerEpoch].Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
cp := ðpb.Checkpoint{
|
||||
Epoch: 1,
|
||||
Root: root[:],
|
||||
}
|
||||
require.NoError(t, db.SaveFinalizedCheckpoint(ctx, cp))
|
||||
root2, err := blks[slotsPerEpoch*2].Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
cp = ðpb.Checkpoint{
|
||||
Epoch: 2,
|
||||
Root: root2[:],
|
||||
}
|
||||
require.NoError(t, db.SaveFinalizedCheckpoint(ctx, cp))
|
||||
|
||||
require.NoError(t, db.db.View(func(tx *bolt.Tx) error {
|
||||
container := ðpb.FinalizedBlockRootContainer{}
|
||||
f := tx.Bucket(finalizedBlockRootsIndexBucket).Get(root[:])
|
||||
require.NoError(t, decode(ctx, f, container))
|
||||
r, err := blks[slotsPerEpoch+1].Block().HashTreeRoot()
|
||||
st, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, r[:], container.ChildRoot)
|
||||
return nil
|
||||
}))
|
||||
}
|
||||
// a state is required to save checkpoint
|
||||
require.NoError(t, db.SaveState(ctx, st, root))
|
||||
require.NoError(t, db.SaveFinalizedCheckpoint(ctx, cp))
|
||||
|
||||
func TestStore_OrphanedBlockIsNotFinalized(t *testing.T) {
|
||||
slotsPerEpoch := uint64(params.BeaconConfig().SlotsPerEpoch)
|
||||
db := setupDB(t)
|
||||
ctx := context.Background()
|
||||
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesisBlockRoot))
|
||||
blk0 := util.NewBeaconBlock()
|
||||
blk0.Block.ParentRoot = genesisBlockRoot[:]
|
||||
blk0Root, err := blk0.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
blk1 := util.NewBeaconBlock()
|
||||
blk1.Block.Slot = 1
|
||||
blk1.Block.ParentRoot = blk0Root[:]
|
||||
blk2 := util.NewBeaconBlock()
|
||||
blk2.Block.Slot = 2
|
||||
// orphan block at index 1
|
||||
blk2.Block.ParentRoot = blk0Root[:]
|
||||
blk2Root, err := blk2.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
sBlk0, err := consensusblocks.NewSignedBeaconBlock(blk0)
|
||||
require.NoError(t, err)
|
||||
sBlk1, err := consensusblocks.NewSignedBeaconBlock(blk1)
|
||||
require.NoError(t, err)
|
||||
sBlk2, err := consensusblocks.NewSignedBeaconBlock(blk2)
|
||||
require.NoError(t, err)
|
||||
blks := append([]interfaces.ReadOnlySignedBeaconBlock{sBlk0, sBlk1, sBlk2}, makeBlocks(t, 3, slotsPerEpoch*2-3, blk2Root)...)
|
||||
require.NoError(t, db.SaveBlocks(ctx, blks))
|
||||
|
||||
root, err := blks[slotsPerEpoch].Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
cp := ðpb.Checkpoint{
|
||||
Epoch: 1,
|
||||
Root: root[:],
|
||||
}
|
||||
require.NoError(t, db.SaveFinalizedCheckpoint(ctx, cp))
|
||||
|
||||
for i := uint64(0); i <= slotsPerEpoch; i++ {
|
||||
root, err = blks[i].Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
if i == 1 {
|
||||
assert.Equal(t, false, db.IsFinalizedBlock(ctx, root), "Block at index 1 was considered finalized, but should not have")
|
||||
} else {
|
||||
assert.Equal(t, true, db.IsFinalizedBlock(ctx, root), "Block at index %d was not considered finalized", i)
|
||||
// All blocks up to slotsPerEpoch should have a finalized child block.
|
||||
for i := uint64(0); i < slotsPerEpoch; i++ {
|
||||
root, err := blks[i].Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, db.IsFinalizedBlock(ctx, root), "Block at index %d was not considered finalized in the index", i)
|
||||
blk, err := db.FinalizedChildBlock(ctx, root)
|
||||
assert.NoError(t, err)
|
||||
if blk == nil {
|
||||
t.Error("Child block doesn't exist for valid finalized block.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setup := func(t testing.TB) *Store {
|
||||
db := setupDB(t)
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesisBlockRoot))
|
||||
|
||||
return db
|
||||
}
|
||||
|
||||
t.Run("phase0", func(t *testing.T) {
|
||||
db := setup(t)
|
||||
|
||||
blks := makeBlocks(t, 0, slotsPerEpoch*3, genesisBlockRoot)
|
||||
eval(t, ctx, db, blks)
|
||||
})
|
||||
|
||||
t.Run("altair", func(t *testing.T) {
|
||||
db := setup(t)
|
||||
|
||||
blks := makeBlocksAltair(t, 0, slotsPerEpoch*3, genesisBlockRoot)
|
||||
eval(t, ctx, db, blks)
|
||||
})
|
||||
}
|
||||
|
||||
func sszRootOrDie(t *testing.T, block interfaces.ReadOnlySignedBeaconBlock) []byte {
|
||||
root, err := block.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
return root[:]
|
||||
}
|
||||
|
||||
func makeBlocks(t *testing.T, i, n uint64, previousRoot [32]byte) []interfaces.ReadOnlySignedBeaconBlock {
|
||||
@@ -189,6 +219,24 @@ func makeBlocks(t *testing.T, i, n uint64, previousRoot [32]byte) []interfaces.R
|
||||
return ifaceBlocks
|
||||
}
|
||||
|
||||
func makeBlocksAltair(t *testing.T, startIdx, num uint64, previousRoot [32]byte) []interfaces.ReadOnlySignedBeaconBlock {
|
||||
blocks := make([]*ethpb.SignedBeaconBlockAltair, num)
|
||||
ifaceBlocks := make([]interfaces.ReadOnlySignedBeaconBlock, num)
|
||||
for j := startIdx; j < num+startIdx; j++ {
|
||||
parentRoot := make([]byte, fieldparams.RootLength)
|
||||
copy(parentRoot, previousRoot[:])
|
||||
blocks[j-startIdx] = util.NewBeaconBlockAltair()
|
||||
blocks[j-startIdx].Block.Slot = primitives.Slot(j + 1)
|
||||
blocks[j-startIdx].Block.ParentRoot = parentRoot
|
||||
var err error
|
||||
previousRoot, err = blocks[j-startIdx].Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
ifaceBlocks[j-startIdx], err = consensusblocks.NewSignedBeaconBlock(blocks[j-startIdx])
|
||||
require.NoError(t, err)
|
||||
}
|
||||
return ifaceBlocks
|
||||
}
|
||||
|
||||
func TestStore_BackfillFinalizedIndexSingle(t *testing.T) {
|
||||
db := setupDB(t)
|
||||
ctx := context.Background()
|
||||
|
||||
@@ -14,6 +14,7 @@ var migrations = []migration{
|
||||
migrateArchivedIndex,
|
||||
migrateBlockSlotIndex,
|
||||
migrateStateValidators,
|
||||
migrateFinalizedParent,
|
||||
}
|
||||
|
||||
// RunMigrations defined in the migrations array.
|
||||
|
||||
87
beacon-chain/db/kv/migration_finalized_parent.go
Normal file
87
beacon-chain/db/kv/migration_finalized_parent.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package kv
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
bolt "go.etcd.io/bbolt"
|
||||
)
|
||||
|
||||
var migrationFinalizedParent = []byte("parent_bug_32fb183")
|
||||
|
||||
func migrateFinalizedParent(ctx context.Context, db *bolt.DB) error {
|
||||
if updateErr := db.Update(func(tx *bolt.Tx) error {
|
||||
mb := tx.Bucket(migrationsBucket)
|
||||
if b := mb.Get(migrationFinalizedParent); bytes.Equal(b, migrationCompleted) {
|
||||
return nil // Migration already completed.
|
||||
}
|
||||
|
||||
bkt := tx.Bucket(finalizedBlockRootsIndexBucket)
|
||||
if bkt == nil {
|
||||
return fmt.Errorf("unable to read %s bucket for migration", finalizedBlockRootsIndexBucket)
|
||||
}
|
||||
bb := tx.Bucket(blocksBucket)
|
||||
if bb == nil {
|
||||
return fmt.Errorf("unable to read %s bucket for migration", blocksBucket)
|
||||
}
|
||||
|
||||
c := bkt.Cursor()
|
||||
var slotsWithoutBug primitives.Slot
|
||||
maxBugSearch := params.BeaconConfig().SlotsPerEpoch * 10
|
||||
for k, v := c.Last(); k != nil; k, v = c.Prev() {
|
||||
// check if context is cancelled in between
|
||||
if ctx.Err() != nil {
|
||||
return ctx.Err()
|
||||
}
|
||||
|
||||
idxEntry := ðpb.FinalizedBlockRootContainer{}
|
||||
if err := decode(ctx, v, idxEntry); err != nil {
|
||||
return errors.Wrapf(err, "unable to decode finalized block root container for root=%#x", k)
|
||||
}
|
||||
// Not one of the corrupt values
|
||||
if !bytes.Equal(idxEntry.ParentRoot, k) {
|
||||
slotsWithoutBug += 1
|
||||
if slotsWithoutBug > maxBugSearch {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
slotsWithoutBug = 0
|
||||
log.WithField("root", fmt.Sprintf("%#x", k)).Debug("found index entry with incorrect parent root")
|
||||
|
||||
// Look up full block to get the correct parent root.
|
||||
encBlk := bb.Get(k)
|
||||
if encBlk == nil {
|
||||
return errors.Wrapf(ErrNotFound, "could not find block for corrupt finalized index entry %#x", k)
|
||||
}
|
||||
blk, err := unmarshalBlock(ctx, encBlk)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to decode block for root=%#x", k)
|
||||
}
|
||||
// Replace parent root in the index with the correct value and write it back.
|
||||
pr := blk.Block().ParentRoot()
|
||||
idxEntry.ParentRoot = pr[:]
|
||||
idxEnc, err := encode(ctx, idxEntry)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to encode finalized index entry for root=%#x", k)
|
||||
}
|
||||
if err := bkt.Put(k, idxEnc); err != nil {
|
||||
return errors.Wrapf(err, "failed to update finalized index entry for root=%#x", k)
|
||||
}
|
||||
log.WithField("root", fmt.Sprintf("%#x", k)).
|
||||
WithField("parentRoot", fmt.Sprintf("%#x", idxEntry.ParentRoot)).
|
||||
Debug("updated corrupt index entry with correct parent")
|
||||
}
|
||||
// Mark migration complete.
|
||||
return mb.Put(migrationFinalizedParent, migrationCompleted)
|
||||
}); updateErr != nil {
|
||||
log.WithError(updateErr).Errorf("could not run finalized parent root index repair migration")
|
||||
return updateErr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -458,7 +458,7 @@ func (s *Store) DeleteState(ctx context.Context, blockRoot [32]byte) error {
|
||||
bkt = tx.Bucket(stateBucket)
|
||||
// Safeguard against deleting genesis, finalized, head state.
|
||||
if bytes.Equal(blockRoot[:], finalized.Root) || bytes.Equal(blockRoot[:], genesisBlockRoot) || bytes.Equal(blockRoot[:], justified.Root) {
|
||||
return ErrDeleteFinalized
|
||||
return ErrDeleteJustifiedAndFinalized
|
||||
}
|
||||
|
||||
// Nothing to delete if state doesn't exist.
|
||||
|
||||
@@ -70,12 +70,12 @@ func (s *Store) LastEpochWrittenForValidators(
|
||||
return attestedEpochs, err
|
||||
}
|
||||
|
||||
// SaveLastEpochsWrittenForValidators updates the latest epoch a slice
|
||||
// of validator indices has attested to.
|
||||
func (s *Store) SaveLastEpochsWrittenForValidators(
|
||||
// SaveLastEpochWrittenForValidators saves the latest epoch
|
||||
// that each validator has attested to in the provided map.
|
||||
func (s *Store) SaveLastEpochWrittenForValidators(
|
||||
ctx context.Context, epochByValIndex map[primitives.ValidatorIndex]primitives.Epoch,
|
||||
) error {
|
||||
ctx, span := trace.StartSpan(ctx, "BeaconDB.SaveLastEpochsWrittenForValidators")
|
||||
ctx, span := trace.StartSpan(ctx, "BeaconDB.SaveLastEpochWrittenForValidators")
|
||||
defer span.End()
|
||||
|
||||
const batchSize = 10000
|
||||
@@ -157,7 +157,7 @@ func (s *Store) CheckAttesterDoubleVotes(
|
||||
attRecordsBkt := tx.Bucket(attestationRecordsBucket)
|
||||
|
||||
encEpoch := encodeTargetEpoch(attToProcess.IndexedAttestation.Data.Target.Epoch)
|
||||
localDoubleVotes := []*slashertypes.AttesterDoubleVote{}
|
||||
localDoubleVotes := make([]*slashertypes.AttesterDoubleVote, 0)
|
||||
|
||||
for _, valIdx := range attToProcess.IndexedAttestation.AttestingIndices {
|
||||
// Check if there is signing root in the database for this combination
|
||||
@@ -166,7 +166,7 @@ func (s *Store) CheckAttesterDoubleVotes(
|
||||
validatorEpochKey := append(encEpoch, encIdx...)
|
||||
attRecordsKey := signingRootsBkt.Get(validatorEpochKey)
|
||||
|
||||
// An attestation record key is comprised of a signing root (32 bytes).
|
||||
// An attestation record key consists of a signing root (32 bytes).
|
||||
if len(attRecordsKey) < attestationRecordKeySize {
|
||||
// If there is no signing root for this combination,
|
||||
// then there is no double vote. We can continue to the next validator.
|
||||
|
||||
@@ -89,7 +89,7 @@ func TestStore_LastEpochWrittenForValidators(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 0, len(attestedEpochs))
|
||||
|
||||
err = beaconDB.SaveLastEpochsWrittenForValidators(ctx, epochsByValidator)
|
||||
err = beaconDB.SaveLastEpochWrittenForValidators(ctx, epochsByValidator)
|
||||
require.NoError(t, err)
|
||||
|
||||
retrievedEpochs, err := beaconDB.LastEpochWrittenForValidators(ctx, indices)
|
||||
|
||||
@@ -3,6 +3,7 @@ package p2p
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -130,7 +131,7 @@ func (s *Service) peerInspector(peerMap map[peer.ID]*pubsub.PeerScoreSnapshot) {
|
||||
}
|
||||
}
|
||||
|
||||
// Creates a list of pubsub options to configure out router with.
|
||||
// pubsubOptions creates a list of options to configure our router with.
|
||||
func (s *Service) pubsubOptions() []pubsub.Option {
|
||||
psOpts := []pubsub.Option{
|
||||
pubsub.WithMessageSignaturePolicy(pubsub.StrictNoSign),
|
||||
@@ -147,9 +148,35 @@ func (s *Service) pubsubOptions() []pubsub.Option {
|
||||
pubsub.WithGossipSubParams(pubsubGossipParam()),
|
||||
pubsub.WithRawTracer(gossipTracer{host: s.host}),
|
||||
}
|
||||
|
||||
if len(s.cfg.StaticPeers) > 0 {
|
||||
directPeersAddrInfos, err := parsePeersEnr(s.cfg.StaticPeers)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not add direct peer option")
|
||||
return psOpts
|
||||
}
|
||||
psOpts = append(psOpts, pubsub.WithDirectPeers(directPeersAddrInfos))
|
||||
}
|
||||
|
||||
return psOpts
|
||||
}
|
||||
|
||||
// parsePeersEnr takes a list of raw ENRs and converts them into a list of AddrInfos.
|
||||
func parsePeersEnr(peers []string) ([]peer.AddrInfo, error) {
|
||||
addrs, err := PeersFromStringAddrs(peers)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Cannot convert peers raw ENRs into multiaddresses: %v", err)
|
||||
}
|
||||
if len(addrs) == 0 {
|
||||
return nil, fmt.Errorf("Converting peers raw ENRs into multiaddresses resulted in an empty list")
|
||||
}
|
||||
directAddrInfos, err := peer.AddrInfosFromP2pAddrs(addrs...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Cannot convert peers multiaddresses into AddrInfos: %v", err)
|
||||
}
|
||||
return directAddrInfos, nil
|
||||
}
|
||||
|
||||
// creates a custom gossipsub parameter set.
|
||||
func pubsubGossipParam() pubsub.GossipSubParams {
|
||||
gParams := pubsub.DefaultGossipSubParams()
|
||||
|
||||
@@ -15,7 +15,9 @@ go_library(
|
||||
"//beacon-chain/core/altair:go_default_library",
|
||||
"//beacon-chain/core/blocks:go_default_library",
|
||||
"//beacon-chain/core/epoch/precompute:go_default_library",
|
||||
"//beacon-chain/core/transition:go_default_library",
|
||||
"//beacon-chain/core/validators:go_default_library",
|
||||
"//beacon-chain/db:go_default_library",
|
||||
"//beacon-chain/rpc/eth/shared:go_default_library",
|
||||
"//beacon-chain/rpc/lookup:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
@@ -35,7 +37,10 @@ go_library(
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["handlers_test.go"],
|
||||
srcs = [
|
||||
"handlers_test.go",
|
||||
"service_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//api/server/structs:go_default_library",
|
||||
@@ -43,6 +48,8 @@ go_test(
|
||||
"//beacon-chain/core/altair:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/signing:go_default_library",
|
||||
"//beacon-chain/core/transition:go_default_library",
|
||||
"//beacon-chain/db/testing:go_default_library",
|
||||
"//beacon-chain/rpc/testutil:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/stategen/mock:go_default_library",
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/altair"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/signing"
|
||||
dbutil "github.com/prysmaticlabs/prysm/v5/beacon-chain/db/testing"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/testutil"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
mockstategen "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/stategen/mock"
|
||||
@@ -192,6 +193,7 @@ func BlockRewardTestSetup(t *testing.T, forkName string) (state.BeaconState, int
|
||||
}
|
||||
|
||||
func TestBlockRewards(t *testing.T) {
|
||||
db := dbutil.SetupDB(t)
|
||||
phase0block, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlock())
|
||||
require.NoError(t, err)
|
||||
t.Run("phase 0", func(t *testing.T) {
|
||||
@@ -227,7 +229,10 @@ func TestBlockRewards(t *testing.T) {
|
||||
}},
|
||||
OptimisticModeFetcher: mockChainService,
|
||||
FinalizationFetcher: mockChainService,
|
||||
BlockRewardFetcher: &BlockRewardService{Replayer: mockstategen.NewReplayerBuilder(mockstategen.WithMockState(st))},
|
||||
BlockRewardFetcher: &BlockRewardService{
|
||||
Replayer: mockstategen.NewReplayerBuilder(mockstategen.WithMockState(st)),
|
||||
DB: db,
|
||||
},
|
||||
}
|
||||
|
||||
url := "http://only.the.slot.number.at.the.end.is.important/2"
|
||||
@@ -260,7 +265,10 @@ func TestBlockRewards(t *testing.T) {
|
||||
}},
|
||||
OptimisticModeFetcher: mockChainService,
|
||||
FinalizationFetcher: mockChainService,
|
||||
BlockRewardFetcher: &BlockRewardService{Replayer: mockstategen.NewReplayerBuilder(mockstategen.WithMockState(st))},
|
||||
BlockRewardFetcher: &BlockRewardService{
|
||||
Replayer: mockstategen.NewReplayerBuilder(mockstategen.WithMockState(st)),
|
||||
DB: db,
|
||||
},
|
||||
}
|
||||
|
||||
url := "http://only.the.slot.number.at.the.end.is.important/2"
|
||||
@@ -293,7 +301,10 @@ func TestBlockRewards(t *testing.T) {
|
||||
}},
|
||||
OptimisticModeFetcher: mockChainService,
|
||||
FinalizationFetcher: mockChainService,
|
||||
BlockRewardFetcher: &BlockRewardService{Replayer: mockstategen.NewReplayerBuilder(mockstategen.WithMockState(st))},
|
||||
BlockRewardFetcher: &BlockRewardService{
|
||||
Replayer: mockstategen.NewReplayerBuilder(mockstategen.WithMockState(st)),
|
||||
DB: db,
|
||||
},
|
||||
}
|
||||
|
||||
url := "http://only.the.slot.number.at.the.end.is.important/2"
|
||||
@@ -326,7 +337,10 @@ func TestBlockRewards(t *testing.T) {
|
||||
}},
|
||||
OptimisticModeFetcher: mockChainService,
|
||||
FinalizationFetcher: mockChainService,
|
||||
BlockRewardFetcher: &BlockRewardService{Replayer: mockstategen.NewReplayerBuilder(mockstategen.WithMockState(st))},
|
||||
BlockRewardFetcher: &BlockRewardService{
|
||||
Replayer: mockstategen.NewReplayerBuilder(mockstategen.WithMockState(st)),
|
||||
DB: db,
|
||||
},
|
||||
}
|
||||
|
||||
url := "http://only.the.slot.number.at.the.end.is.important/2"
|
||||
@@ -715,7 +729,9 @@ func TestSyncCommiteeRewards(t *testing.T) {
|
||||
}},
|
||||
OptimisticModeFetcher: mockChainService,
|
||||
FinalizationFetcher: mockChainService,
|
||||
BlockRewardFetcher: &BlockRewardService{Replayer: mockstategen.NewReplayerBuilder(mockstategen.WithMockState(st))},
|
||||
BlockRewardFetcher: &BlockRewardService{
|
||||
Replayer: mockstategen.NewReplayerBuilder(mockstategen.WithMockState(st)),
|
||||
DB: dbutil.SetupDB(t)},
|
||||
}
|
||||
|
||||
t.Run("ok - filtered vals", func(t *testing.T) {
|
||||
|
||||
@@ -8,7 +8,9 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v5/api/server/structs"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/altair"
|
||||
coreblocks "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/transition"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/validators"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/db"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state/stategen"
|
||||
consensusblocks "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
@@ -26,6 +28,7 @@ type BlockRewardsFetcher interface {
|
||||
// BlockRewardService implements BlockRewardsFetcher and can be declared to access the underlying functions
|
||||
type BlockRewardService struct {
|
||||
Replayer stategen.ReplayerBuilder
|
||||
DB db.HeadAccessDatabase
|
||||
}
|
||||
|
||||
// GetBlockRewardsData returns the BlockRewards object which is used for the BlockRewardsResponse and ProduceBlockV3.
|
||||
@@ -124,6 +127,22 @@ func (rs *BlockRewardService) GetStateForRewards(ctx context.Context, blk interf
|
||||
// We want to run several block processing functions that update the proposer's balance.
|
||||
// This will allow us to calculate proposer rewards for each operation (atts, slashings etc).
|
||||
// To do this, we replay the state up to the block's slot, but before processing the block.
|
||||
|
||||
// Try getting the state from the next slot cache first.
|
||||
_, prevSlotRoots, err := rs.DB.BlockRootsBySlot(ctx, slots.PrevSlot(blk.Slot()))
|
||||
if err != nil {
|
||||
return nil, &httputil.DefaultJsonError{
|
||||
Message: "Could not get roots for previous slot: " + err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
}
|
||||
}
|
||||
for _, r := range prevSlotRoots {
|
||||
s := transition.NextSlotState(r[:], blk.Slot())
|
||||
if s != nil {
|
||||
return s, nil
|
||||
}
|
||||
}
|
||||
|
||||
st, err := rs.Replayer.ReplayerForSlot(slots.PrevSlot(blk.Slot())).ReplayToSlot(ctx, blk.Slot())
|
||||
if err != nil {
|
||||
return nil, &httputil.DefaultJsonError{
|
||||
|
||||
46
beacon-chain/rpc/eth/rewards/service_test.go
Normal file
46
beacon-chain/rpc/eth/rewards/service_test.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package rewards
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/transition"
|
||||
dbutil "github.com/prysmaticlabs/prysm/v5/beacon-chain/db/testing"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
)
|
||||
|
||||
func TestGetStateForRewards_NextSlotCacheHit(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := dbutil.SetupDB(t)
|
||||
|
||||
st, err := util.NewBeaconStateDeneb()
|
||||
require.NoError(t, err)
|
||||
b := util.HydrateSignedBeaconBlockDeneb(util.NewBeaconBlockDeneb())
|
||||
parent, err := blocks.NewSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.SaveBlock(ctx, parent))
|
||||
|
||||
r, err := parent.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, transition.UpdateNextSlotCache(ctx, r[:], st))
|
||||
|
||||
s := &BlockRewardService{
|
||||
Replayer: nil, // setting to nil because replayer must not be invoked
|
||||
DB: db,
|
||||
}
|
||||
b = util.HydrateSignedBeaconBlockDeneb(util.NewBeaconBlockDeneb())
|
||||
sbb, err := blocks.NewSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
sbb.SetSlot(parent.Block().Slot() + 1)
|
||||
result, err := s.GetStateForRewards(ctx, sbb.Block())
|
||||
require.NoError(t, err)
|
||||
_, lcs := transition.LastCachedState()
|
||||
expected, err := lcs.HashTreeRoot(ctx)
|
||||
require.NoError(t, err)
|
||||
actual, err := result.HashTreeRoot(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, expected, actual)
|
||||
}
|
||||
@@ -4,10 +4,10 @@ go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"aggregator.go",
|
||||
"duties.go",
|
||||
"attester.go",
|
||||
"blocks.go",
|
||||
"construct_generic_block.go",
|
||||
"duties.go",
|
||||
"exit.go",
|
||||
"log.go",
|
||||
"proposer.go",
|
||||
@@ -179,10 +179,10 @@ go_test(
|
||||
timeout = "moderate",
|
||||
srcs = [
|
||||
"aggregator_test.go",
|
||||
"duties_test.go",
|
||||
"attester_test.go",
|
||||
"blocks_test.go",
|
||||
"construct_generic_block_test.go",
|
||||
"duties_test.go",
|
||||
"exit_test.go",
|
||||
"proposer_altair_test.go",
|
||||
"proposer_attestations_test.go",
|
||||
@@ -201,6 +201,7 @@ go_test(
|
||||
"status_mainnet_test.go",
|
||||
"status_test.go",
|
||||
"sync_committee_test.go",
|
||||
"unblinder_test.go",
|
||||
"validator_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
|
||||
@@ -27,11 +27,20 @@ import (
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
// builderGetPayloadMissCount tracks the number of misses when validator tries to get a payload from builder
|
||||
var builderGetPayloadMissCount = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "builder_get_payload_miss_count",
|
||||
Help: "The number of get payload misses for validator requests to builder",
|
||||
})
|
||||
var (
|
||||
builderValueGweiGauge = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "builder_value_gwei",
|
||||
Help: "Builder payload value in gwei",
|
||||
})
|
||||
localValueGweiGauge = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "local_value_gwei",
|
||||
Help: "Local payload value in gwei",
|
||||
})
|
||||
builderGetPayloadMissCount = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "builder_get_payload_miss_count",
|
||||
Help: "The number of get payload misses for validator requests to builder",
|
||||
})
|
||||
)
|
||||
|
||||
// emptyTransactionsRoot represents the returned value of ssz.TransactionsRoot([][]byte{}) and
|
||||
// can be used as a constant to avoid recomputing this value in every call.
|
||||
@@ -92,6 +101,8 @@ func setExecutionData(ctx context.Context, blk interfaces.SignedBeaconBlock, loc
|
||||
"builderBoostFactor": builderBoostFactor,
|
||||
}).Warn("Proposer: both local boost and builder boost are using non default values")
|
||||
}
|
||||
builderValueGweiGauge.Set(float64(builderValueGwei))
|
||||
localValueGweiGauge.Set(float64(localValueGwei))
|
||||
|
||||
// If we can't get the builder value, just use local block.
|
||||
if higherValueBuilder && withdrawalsMatched { // Builder value is higher and withdrawals match.
|
||||
|
||||
@@ -13,18 +13,25 @@ import (
|
||||
)
|
||||
|
||||
func unblindBlobsSidecars(block interfaces.SignedBeaconBlock, bundle *enginev1.BlobsBundle) ([]*ethpb.BlobSidecar, error) {
|
||||
if block.Version() < version.Deneb || bundle == nil {
|
||||
if block.Version() < version.Deneb {
|
||||
return nil, nil
|
||||
}
|
||||
header, err := block.Header()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
body := block.Block().Body()
|
||||
blockCommitments, err := body.BlobKzgCommitments()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(blockCommitments) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
// Do not allow builders to provide no blob bundles for blocks which carry commitments.
|
||||
if bundle == nil {
|
||||
return nil, errors.New("no valid bundle provided")
|
||||
}
|
||||
header, err := block.Header()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Ensure there are equal counts of blobs/commitments/proofs.
|
||||
if len(bundle.KzgCommitments) != len(bundle.Blobs) {
|
||||
|
||||
34
beacon-chain/rpc/prysm/v1alpha1/validator/unblinder_test.go
Normal file
34
beacon-chain/rpc/prysm/v1alpha1/validator/unblinder_test.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package validator
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
consensusblocks "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/assert"
|
||||
)
|
||||
|
||||
func TestUnblinder_UnblindBlobSidecars_InvalidBundle(t *testing.T) {
|
||||
wBlock, err := consensusblocks.NewSignedBeaconBlock(ðpb.SignedBeaconBlockDeneb{
|
||||
Block: ðpb.BeaconBlockDeneb{
|
||||
Body: ðpb.BeaconBlockBodyDeneb{},
|
||||
},
|
||||
Signature: nil,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
_, err = unblindBlobsSidecars(wBlock, nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
wBlock, err = consensusblocks.NewSignedBeaconBlock(ðpb.SignedBeaconBlockDeneb{
|
||||
Block: ðpb.BeaconBlockDeneb{
|
||||
Body: ðpb.BeaconBlockBodyDeneb{
|
||||
BlobKzgCommitments: [][]byte{[]byte("a"), []byte("b")},
|
||||
},
|
||||
},
|
||||
Signature: nil,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
_, err = unblindBlobsSidecars(wBlock, nil)
|
||||
assert.ErrorContains(t, "no valid bundle provided", err)
|
||||
|
||||
}
|
||||
@@ -215,7 +215,7 @@ func NewService(ctx context.Context, cfg *Config) *Service {
|
||||
GenesisTimeFetcher: s.cfg.GenesisTimeFetcher,
|
||||
BlobStorage: s.cfg.BlobStorage,
|
||||
}
|
||||
rewardFetcher := &rewards.BlockRewardService{Replayer: ch}
|
||||
rewardFetcher := &rewards.BlockRewardService{Replayer: ch, DB: s.cfg.BeaconDB}
|
||||
coreService := &core.Service{
|
||||
HeadFetcher: s.cfg.HeadFetcher,
|
||||
GenesisTimeFetcher: s.cfg.GenesisTimeFetcher,
|
||||
|
||||
@@ -19,6 +19,7 @@ go_library(
|
||||
importpath = "github.com/prysmaticlabs/prysm/v5/beacon-chain/slasher",
|
||||
visibility = [
|
||||
"//beacon-chain:__subpackages__",
|
||||
"//cmd/prysmctl:__subpackages__",
|
||||
"//testing/slasher/simulator:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
@@ -27,6 +28,7 @@ go_library(
|
||||
"//beacon-chain/core/blocks:go_default_library",
|
||||
"//beacon-chain/core/feed/state:go_default_library",
|
||||
"//beacon-chain/db:go_default_library",
|
||||
"//beacon-chain/db/slasherkv:go_default_library",
|
||||
"//beacon-chain/operations/slashings:go_default_library",
|
||||
"//beacon-chain/slasher/types:go_default_library",
|
||||
"//beacon-chain/startup:go_default_library",
|
||||
@@ -45,6 +47,7 @@ go_library(
|
||||
"@com_github_prysmaticlabs_fastssz//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@io_opencensus_go//trace:go_default_library",
|
||||
"@org_golang_x_exp//maps:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"go.opencensus.io/trace"
|
||||
"golang.org/x/exp/maps"
|
||||
)
|
||||
|
||||
// Takes in a list of indexed attestation wrappers and returns any
|
||||
@@ -131,7 +132,7 @@ func (s *Service) checkSurroundVotes(
|
||||
}
|
||||
|
||||
// Update the latest updated epoch for all validators involved to the current chunk.
|
||||
indexes := s.params.validatorIndexesInChunk(validatorChunkIndex)
|
||||
indexes := s.params.ValidatorIndexesInChunk(validatorChunkIndex)
|
||||
for _, index := range indexes {
|
||||
s.latestEpochUpdatedForValidator[index] = currentEpoch
|
||||
}
|
||||
@@ -272,44 +273,20 @@ func (s *Service) updatedChunkByChunkIndex(
|
||||
|
||||
// minFirstEpochToUpdate is set to the smallest first epoch to update for all validators in the chunk
|
||||
// corresponding to the `validatorChunkIndex`.
|
||||
var minFirstEpochToUpdate *primitives.Epoch
|
||||
var (
|
||||
minFirstEpochToUpdate *primitives.Epoch
|
||||
neededChunkIndexesMap map[uint64]bool
|
||||
|
||||
neededChunkIndexesMap := map[uint64]bool{}
|
||||
err error
|
||||
)
|
||||
validatorIndexes := s.params.ValidatorIndexesInChunk(validatorChunkIndex)
|
||||
|
||||
validatorIndexes := s.params.validatorIndexesInChunk(validatorChunkIndex)
|
||||
for _, validatorIndex := range validatorIndexes {
|
||||
// Retrieve the first epoch to write for the validator index.
|
||||
isAnEpochToUpdate, firstEpochToUpdate, err := s.firstEpochToUpdate(validatorIndex, currentEpoch)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not get first epoch to write for validator index %d with current epoch %d", validatorIndex, currentEpoch)
|
||||
}
|
||||
|
||||
if !isAnEpochToUpdate {
|
||||
// If there is no epoch to write, skip.
|
||||
continue
|
||||
}
|
||||
|
||||
// If, for this validator index, the chunk corresponding to the first epoch to write
|
||||
// (and all following epochs until the current epoch) are already flagged as needed,
|
||||
// skip.
|
||||
if minFirstEpochToUpdate != nil && *minFirstEpochToUpdate <= firstEpochToUpdate {
|
||||
continue
|
||||
}
|
||||
|
||||
minFirstEpochToUpdate = &firstEpochToUpdate
|
||||
|
||||
// Add new needed chunk indexes to the map.
|
||||
for i := firstEpochToUpdate; i <= currentEpoch; i++ {
|
||||
chunkIndex := s.params.chunkIndex(i)
|
||||
neededChunkIndexesMap[chunkIndex] = true
|
||||
}
|
||||
if neededChunkIndexesMap, err = s.findNeededChunkIndexes(validatorIndexes, currentEpoch, minFirstEpochToUpdate); err != nil {
|
||||
return nil, errors.Wrap(err, "could not find the needed chunk indexed")
|
||||
}
|
||||
|
||||
// Get the list of needed chunk indexes.
|
||||
neededChunkIndexes := make([]uint64, 0, len(neededChunkIndexesMap))
|
||||
for chunkIndex := range neededChunkIndexesMap {
|
||||
neededChunkIndexes = append(neededChunkIndexes, chunkIndex)
|
||||
}
|
||||
// Transform the map of needed chunk indexes to a slice.
|
||||
neededChunkIndexes := maps.Keys(neededChunkIndexesMap)
|
||||
|
||||
// Retrieve needed chunks from the database.
|
||||
chunkByChunkIndex, err := s.loadChunksFromDisk(ctx, validatorChunkIndex, chunkKind, neededChunkIndexes)
|
||||
@@ -332,7 +309,7 @@ func (s *Service) updatedChunkByChunkIndex(
|
||||
epochToUpdate := firstEpochToUpdate
|
||||
|
||||
for epochToUpdate <= currentEpoch {
|
||||
// Get the chunk index for the ecpoh to write.
|
||||
// Get the chunk index for the epoch to write.
|
||||
chunkIndex := s.params.chunkIndex(epochToUpdate)
|
||||
|
||||
// Get the chunk corresponding to the chunk index from the `chunkByChunkIndex` map.
|
||||
@@ -363,6 +340,45 @@ func (s *Service) updatedChunkByChunkIndex(
|
||||
return chunkByChunkIndex, nil
|
||||
}
|
||||
|
||||
// findNeededChunkIndexes returns a map of chunk indexes
|
||||
// it loops over the validator indexes and finds the first epoch to update for each validator index.
|
||||
func (s *Service) findNeededChunkIndexes(
|
||||
validatorIndexes []primitives.ValidatorIndex,
|
||||
currentEpoch primitives.Epoch,
|
||||
minFirstEpochToUpdate *primitives.Epoch,
|
||||
) (map[uint64]bool, error) {
|
||||
neededChunkIndexesMap := map[uint64]bool{}
|
||||
|
||||
for _, validatorIndex := range validatorIndexes {
|
||||
// Retrieve the first epoch to write for the validator index.
|
||||
isAnEpochToUpdate, firstEpochToUpdate, err := s.firstEpochToUpdate(validatorIndex, currentEpoch)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not get first epoch to write for validator index %d with current epoch %d", validatorIndex, currentEpoch)
|
||||
}
|
||||
|
||||
if !isAnEpochToUpdate {
|
||||
// If there is no epoch to write, skip.
|
||||
continue
|
||||
}
|
||||
|
||||
// If, for this validator index, the chunk corresponding to the first epoch to write
|
||||
// (and all following epochs until the current epoch) are already flagged as needed,
|
||||
// skip.
|
||||
if minFirstEpochToUpdate != nil && *minFirstEpochToUpdate <= firstEpochToUpdate {
|
||||
continue
|
||||
}
|
||||
|
||||
minFirstEpochToUpdate = &firstEpochToUpdate
|
||||
|
||||
// Add new needed chunk indexes to the map.
|
||||
for i := firstEpochToUpdate; i <= currentEpoch; i++ {
|
||||
chunkIndex := s.params.chunkIndex(i)
|
||||
neededChunkIndexesMap[chunkIndex] = true
|
||||
}
|
||||
}
|
||||
return neededChunkIndexesMap, nil
|
||||
}
|
||||
|
||||
// firstEpochToUpdate, given a validator index and the current epoch, returns a boolean indicating
|
||||
// if there is an epoch to write. If it is the case, it returns the first epoch to write.
|
||||
func (s *Service) firstEpochToUpdate(validatorIndex primitives.ValidatorIndex, currentEpoch primitives.Epoch) (bool, primitives.Epoch, error) {
|
||||
|
||||
@@ -2,8 +2,11 @@ package slasher
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/db/slasherkv"
|
||||
slashertypes "github.com/prysmaticlabs/prysm/v5/beacon-chain/slasher/types"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
@@ -159,3 +162,93 @@ func isDoubleProposal(incomingSigningRoot, existingSigningRoot [32]byte) bool {
|
||||
}
|
||||
return incomingSigningRoot != existingSigningRoot
|
||||
}
|
||||
|
||||
type GetChunkFromDatabaseFilters struct {
|
||||
ChunkKind slashertypes.ChunkKind
|
||||
ValidatorIndex primitives.ValidatorIndex
|
||||
SourceEpoch primitives.Epoch
|
||||
IsDisplayAllValidatorsInChunk bool
|
||||
IsDisplayAllEpochsInChunk bool
|
||||
}
|
||||
|
||||
// GetChunkFromDatabase Utility function aiming at retrieving a chunk from the
|
||||
// database.
|
||||
func GetChunkFromDatabase(
|
||||
ctx context.Context,
|
||||
dbPath string,
|
||||
filters GetChunkFromDatabaseFilters,
|
||||
params *Parameters,
|
||||
) (lastEpochForValidatorIndex primitives.Epoch, chunkIndex, validatorChunkIndex uint64, chunk Chunker, err error) {
|
||||
// init store
|
||||
d, err := slasherkv.NewKVStore(ctx, dbPath)
|
||||
if err != nil {
|
||||
return lastEpochForValidatorIndex, chunkIndex, validatorChunkIndex, chunk, fmt.Errorf("could not open database at path %s: %w", dbPath, err)
|
||||
}
|
||||
defer closeDB(d)
|
||||
|
||||
// init service
|
||||
s := Service{
|
||||
params: params,
|
||||
serviceCfg: &ServiceConfig{
|
||||
Database: d,
|
||||
},
|
||||
}
|
||||
|
||||
// variables
|
||||
validatorIndex := filters.ValidatorIndex
|
||||
sourceEpoch := filters.SourceEpoch
|
||||
chunkKind := filters.ChunkKind
|
||||
validatorChunkIndex = s.params.validatorChunkIndex(validatorIndex)
|
||||
chunkIndex = s.params.chunkIndex(sourceEpoch)
|
||||
|
||||
// before getting the chunk, we need to verify if the requested epoch is in database
|
||||
lastEpochForValidator, err := s.serviceCfg.Database.LastEpochWrittenForValidators(ctx, []primitives.ValidatorIndex{validatorIndex})
|
||||
if err != nil {
|
||||
return lastEpochForValidatorIndex,
|
||||
chunkIndex,
|
||||
validatorChunkIndex,
|
||||
chunk,
|
||||
fmt.Errorf("could not get last epoch written for validator %d: %w", validatorIndex, err)
|
||||
}
|
||||
|
||||
if len(lastEpochForValidator) == 0 {
|
||||
return lastEpochForValidatorIndex,
|
||||
chunkIndex,
|
||||
validatorChunkIndex,
|
||||
chunk,
|
||||
fmt.Errorf("could not get information at epoch %d for validator %d: there's no record found in slasher database",
|
||||
sourceEpoch, validatorIndex,
|
||||
)
|
||||
}
|
||||
lastEpochForValidatorIndex = lastEpochForValidator[0].Epoch
|
||||
|
||||
// if the epoch requested is within the range, we can proceed to get the chunk, otherwise return error
|
||||
atBestSmallestEpoch := lastEpochForValidatorIndex.Sub(uint64(params.historyLength))
|
||||
if sourceEpoch < atBestSmallestEpoch || sourceEpoch > lastEpochForValidatorIndex {
|
||||
return lastEpochForValidatorIndex,
|
||||
chunkIndex,
|
||||
validatorChunkIndex,
|
||||
chunk,
|
||||
fmt.Errorf("requested epoch %d is outside the slasher history length %d, data can be provided within the epoch range [%d:%d] for validator %d",
|
||||
sourceEpoch, params.historyLength, atBestSmallestEpoch, lastEpochForValidatorIndex, validatorIndex,
|
||||
)
|
||||
}
|
||||
|
||||
// fetch chunk from DB
|
||||
chunk, err = s.getChunkFromDatabase(ctx, chunkKind, validatorChunkIndex, chunkIndex)
|
||||
if err != nil {
|
||||
return lastEpochForValidatorIndex,
|
||||
chunkIndex,
|
||||
validatorChunkIndex,
|
||||
chunk,
|
||||
fmt.Errorf("could not get chunk at index %d: %w", chunkIndex, err)
|
||||
}
|
||||
|
||||
return lastEpochForValidatorIndex, chunkIndex, validatorChunkIndex, chunk, nil
|
||||
}
|
||||
|
||||
func closeDB(d *slasherkv.Store) {
|
||||
if err := d.Close(); err != nil {
|
||||
log.WithError(err).Error("could not close database")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,21 @@ type Parameters struct {
|
||||
historyLength primitives.Epoch // H - defines how many epochs we keep of min or max spans.
|
||||
}
|
||||
|
||||
// ChunkSize returns the chunk size.
|
||||
func (p *Parameters) ChunkSize() uint64 {
|
||||
return p.chunkSize
|
||||
}
|
||||
|
||||
// ValidatorChunkSize returns the validator chunk size.
|
||||
func (p *Parameters) ValidatorChunkSize() uint64 {
|
||||
return p.validatorChunkSize
|
||||
}
|
||||
|
||||
// HistoryLength returns the history length.
|
||||
func (p *Parameters) HistoryLength() primitives.Epoch {
|
||||
return p.historyLength
|
||||
}
|
||||
|
||||
// DefaultParams defines default values for slasher's important parameters, defined
|
||||
// based on optimization analysis for best and worst case scenarios for
|
||||
// slasher's performance.
|
||||
@@ -32,7 +47,15 @@ func DefaultParams() *Parameters {
|
||||
}
|
||||
}
|
||||
|
||||
// Validator min and max spans are split into chunks of length C = chunkSize.
|
||||
func NewParams(chunkSize, validatorChunkSize uint64, historyLength primitives.Epoch) *Parameters {
|
||||
return &Parameters{
|
||||
chunkSize: chunkSize,
|
||||
validatorChunkSize: validatorChunkSize,
|
||||
historyLength: historyLength,
|
||||
}
|
||||
}
|
||||
|
||||
// ChunkIndex Validator min and max spans are split into chunks of length C = chunkSize.
|
||||
// That is, if we are keeping N epochs worth of attesting history, finding what
|
||||
// chunk a certain epoch, e, falls into can be computed as (e % N) / C. For example,
|
||||
// if we are keeping 6 epochs worth of data, and we have chunks of size 2, then epoch
|
||||
@@ -139,9 +162,9 @@ func (p *Parameters) flatSliceID(validatorChunkIndex, chunkIndex uint64) []byte
|
||||
return ssz.MarshalUint64(make([]byte, 0), uint64(width.Mul(validatorChunkIndex).Add(chunkIndex)))
|
||||
}
|
||||
|
||||
// Given a validator chunk index, we determine all of the validator
|
||||
// ValidatorIndexesInChunk Given a validator chunk index, we determine all the validators
|
||||
// indices that will belong in that chunk.
|
||||
func (p *Parameters) validatorIndexesInChunk(validatorChunkIndex uint64) []primitives.ValidatorIndex {
|
||||
func (p *Parameters) ValidatorIndexesInChunk(validatorChunkIndex uint64) []primitives.ValidatorIndex {
|
||||
validatorIndices := make([]primitives.ValidatorIndex, 0)
|
||||
low := validatorChunkIndex * p.validatorChunkSize
|
||||
high := (validatorChunkIndex + 1) * p.validatorChunkSize
|
||||
|
||||
@@ -468,7 +468,7 @@ func TestParams_validatorIndicesInChunk(t *testing.T) {
|
||||
c := &Parameters{
|
||||
validatorChunkSize: tt.fields.validatorChunkSize,
|
||||
}
|
||||
if got := c.validatorIndexesInChunk(tt.validatorChunkIdx); !reflect.DeepEqual(got, tt.want) {
|
||||
if got := c.ValidatorIndexesInChunk(tt.validatorChunkIdx); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("validatorIndicesInChunk() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -161,7 +161,7 @@ func (s *Service) Stop() error {
|
||||
ctx, innerCancel := context.WithTimeout(context.Background(), shutdownTimeout)
|
||||
defer innerCancel()
|
||||
log.Info("Flushing last epoch written for each validator to disk, please wait")
|
||||
if err := s.serviceCfg.Database.SaveLastEpochsWrittenForValidators(
|
||||
if err := s.serviceCfg.Database.SaveLastEpochWrittenForValidators(
|
||||
ctx, s.latestEpochUpdatedForValidator,
|
||||
); err != nil {
|
||||
log.Error(err)
|
||||
|
||||
@@ -4,7 +4,10 @@ go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["types.go"],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v5/beacon-chain/slasher/types",
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
visibility = [
|
||||
"//beacon-chain:__subpackages__",
|
||||
"//cmd/prysmctl:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
|
||||
@@ -14,6 +14,18 @@ const (
|
||||
MaxSpan
|
||||
)
|
||||
|
||||
// String returns the string representation of the chunk kind.
|
||||
func (c ChunkKind) String() string {
|
||||
switch c {
|
||||
case MinSpan:
|
||||
return "minspan"
|
||||
case MaxSpan:
|
||||
return "maxspan"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
// IndexedAttestationWrapper contains an indexed attestation with its
|
||||
// data root to reduce duplicated computation.
|
||||
type IndexedAttestationWrapper struct {
|
||||
|
||||
@@ -189,7 +189,7 @@ func TestLoadBlocks_FirstBranch(t *testing.T) {
|
||||
roots, savedBlocks, err := tree1(t, beaconDB, bytesutil.PadTo([]byte{'A'}, 32))
|
||||
require.NoError(t, err)
|
||||
|
||||
filteredBlocks, err := s.loadBlocks(ctx, 0, 9, roots[len(roots)-1])
|
||||
filteredBlocks, err := s.loadBlocks(ctx, 0, 8, roots[len(roots)-1])
|
||||
require.NoError(t, err)
|
||||
|
||||
wanted := []*ethpb.SignedBeaconBlock{
|
||||
@@ -220,7 +220,7 @@ func TestLoadBlocks_SecondBranch(t *testing.T) {
|
||||
roots, savedBlocks, err := tree1(t, beaconDB, bytesutil.PadTo([]byte{'A'}, 32))
|
||||
require.NoError(t, err)
|
||||
|
||||
filteredBlocks, err := s.loadBlocks(ctx, 0, 6, roots[5])
|
||||
filteredBlocks, err := s.loadBlocks(ctx, 0, 5, roots[5])
|
||||
require.NoError(t, err)
|
||||
|
||||
wanted := []*ethpb.SignedBeaconBlock{
|
||||
@@ -249,7 +249,7 @@ func TestLoadBlocks_ThirdBranch(t *testing.T) {
|
||||
roots, savedBlocks, err := tree1(t, beaconDB, bytesutil.PadTo([]byte{'A'}, 32))
|
||||
require.NoError(t, err)
|
||||
|
||||
filteredBlocks, err := s.loadBlocks(ctx, 0, 8, roots[7])
|
||||
filteredBlocks, err := s.loadBlocks(ctx, 0, 7, roots[7])
|
||||
require.NoError(t, err)
|
||||
|
||||
wanted := []*ethpb.SignedBeaconBlock{
|
||||
@@ -280,7 +280,7 @@ func TestLoadBlocks_SameSlots(t *testing.T) {
|
||||
roots, savedBlocks, err := tree2(t, beaconDB, bytesutil.PadTo([]byte{'A'}, 32))
|
||||
require.NoError(t, err)
|
||||
|
||||
filteredBlocks, err := s.loadBlocks(ctx, 0, 4, roots[6])
|
||||
filteredBlocks, err := s.loadBlocks(ctx, 0, 3, roots[6])
|
||||
require.NoError(t, err)
|
||||
|
||||
wanted := []*ethpb.SignedBeaconBlock{
|
||||
@@ -309,7 +309,7 @@ func TestLoadBlocks_SameEndSlots(t *testing.T) {
|
||||
roots, savedBlocks, err := tree3(t, beaconDB, bytesutil.PadTo([]byte{'A'}, 32))
|
||||
require.NoError(t, err)
|
||||
|
||||
filteredBlocks, err := s.loadBlocks(ctx, 0, 3, roots[2])
|
||||
filteredBlocks, err := s.loadBlocks(ctx, 0, 2, roots[2])
|
||||
require.NoError(t, err)
|
||||
|
||||
wanted := []*ethpb.SignedBeaconBlock{
|
||||
@@ -337,7 +337,7 @@ func TestLoadBlocks_SameEndSlotsWith2blocks(t *testing.T) {
|
||||
roots, savedBlocks, err := tree4(t, beaconDB, bytesutil.PadTo([]byte{'A'}, 32))
|
||||
require.NoError(t, err)
|
||||
|
||||
filteredBlocks, err := s.loadBlocks(ctx, 0, 3, roots[1])
|
||||
filteredBlocks, err := s.loadBlocks(ctx, 0, 2, roots[1])
|
||||
require.NoError(t, err)
|
||||
|
||||
wanted := []*ethpb.SignedBeaconBlock{
|
||||
@@ -363,7 +363,7 @@ func TestLoadBlocks_BadStart(t *testing.T) {
|
||||
|
||||
roots, _, err := tree1(t, beaconDB, bytesutil.PadTo([]byte{'A'}, 32))
|
||||
require.NoError(t, err)
|
||||
_, err = s.loadBlocks(ctx, 0, 6, roots[8])
|
||||
_, err = s.loadBlocks(ctx, 0, 5, roots[8])
|
||||
assert.ErrorContains(t, "end block roots don't match", err)
|
||||
}
|
||||
|
||||
@@ -374,63 +374,63 @@ func TestLoadBlocks_BadStart(t *testing.T) {
|
||||
// \- B7
|
||||
func tree1(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte, []*ethpb.SignedBeaconBlock, error) {
|
||||
b0 := util.NewBeaconBlock()
|
||||
b0.Block.Slot = 1
|
||||
b0.Block.Slot = 0
|
||||
b0.Block.ParentRoot = genesisRoot
|
||||
r0, err := b0.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
b1 := util.NewBeaconBlock()
|
||||
b1.Block.Slot = 2
|
||||
b1.Block.Slot = 1
|
||||
b1.Block.ParentRoot = r0[:]
|
||||
r1, err := b1.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
b2 := util.NewBeaconBlock()
|
||||
b2.Block.Slot = 3
|
||||
b2.Block.Slot = 2
|
||||
b2.Block.ParentRoot = r1[:]
|
||||
r2, err := b2.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
b3 := util.NewBeaconBlock()
|
||||
b3.Block.Slot = 4
|
||||
b3.Block.Slot = 3
|
||||
b3.Block.ParentRoot = r1[:]
|
||||
r3, err := b3.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
b4 := util.NewBeaconBlock()
|
||||
b4.Block.Slot = 5
|
||||
b4.Block.Slot = 4
|
||||
b4.Block.ParentRoot = r2[:]
|
||||
r4, err := b4.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
b5 := util.NewBeaconBlock()
|
||||
b5.Block.Slot = 6
|
||||
b5.Block.Slot = 5
|
||||
b5.Block.ParentRoot = r3[:]
|
||||
r5, err := b5.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
b6 := util.NewBeaconBlock()
|
||||
b6.Block.Slot = 7
|
||||
b6.Block.Slot = 6
|
||||
b6.Block.ParentRoot = r4[:]
|
||||
r6, err := b6.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
b7 := util.NewBeaconBlock()
|
||||
b7.Block.Slot = 8
|
||||
b7.Block.Slot = 7
|
||||
b7.Block.ParentRoot = r6[:]
|
||||
r7, err := b7.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
b8 := util.NewBeaconBlock()
|
||||
b8.Block.Slot = 9
|
||||
b8.Block.Slot = 8
|
||||
b8.Block.ParentRoot = r6[:]
|
||||
r8, err := b8.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
@@ -466,21 +466,21 @@ func tree1(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte,
|
||||
// \- B2 -- B3
|
||||
func tree2(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte, []*ethpb.SignedBeaconBlock, error) {
|
||||
b0 := util.NewBeaconBlock()
|
||||
b0.Block.Slot = 1
|
||||
b0.Block.Slot = 0
|
||||
b0.Block.ParentRoot = genesisRoot
|
||||
r0, err := b0.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
b1 := util.NewBeaconBlock()
|
||||
b1.Block.Slot = 2
|
||||
b1.Block.Slot = 1
|
||||
b1.Block.ParentRoot = r0[:]
|
||||
r1, err := b1.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
b21 := util.NewBeaconBlock()
|
||||
b21.Block.Slot = 3
|
||||
b21.Block.Slot = 2
|
||||
b21.Block.ParentRoot = r1[:]
|
||||
b21.Block.StateRoot = bytesutil.PadTo([]byte{'A'}, 32)
|
||||
r21, err := b21.Block.HashTreeRoot()
|
||||
@@ -488,7 +488,7 @@ func tree2(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte,
|
||||
return nil, nil, err
|
||||
}
|
||||
b22 := util.NewBeaconBlock()
|
||||
b22.Block.Slot = 3
|
||||
b22.Block.Slot = 2
|
||||
b22.Block.ParentRoot = r1[:]
|
||||
b22.Block.StateRoot = bytesutil.PadTo([]byte{'B'}, 32)
|
||||
r22, err := b22.Block.HashTreeRoot()
|
||||
@@ -496,7 +496,7 @@ func tree2(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte,
|
||||
return nil, nil, err
|
||||
}
|
||||
b23 := util.NewBeaconBlock()
|
||||
b23.Block.Slot = 3
|
||||
b23.Block.Slot = 2
|
||||
b23.Block.ParentRoot = r1[:]
|
||||
b23.Block.StateRoot = bytesutil.PadTo([]byte{'C'}, 32)
|
||||
r23, err := b23.Block.HashTreeRoot()
|
||||
@@ -504,7 +504,7 @@ func tree2(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte,
|
||||
return nil, nil, err
|
||||
}
|
||||
b24 := util.NewBeaconBlock()
|
||||
b24.Block.Slot = 3
|
||||
b24.Block.Slot = 2
|
||||
b24.Block.ParentRoot = r1[:]
|
||||
b24.Block.StateRoot = bytesutil.PadTo([]byte{'D'}, 32)
|
||||
r24, err := b24.Block.HashTreeRoot()
|
||||
@@ -512,7 +512,7 @@ func tree2(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte,
|
||||
return nil, nil, err
|
||||
}
|
||||
b3 := util.NewBeaconBlock()
|
||||
b3.Block.Slot = 4
|
||||
b3.Block.Slot = 3
|
||||
b3.Block.ParentRoot = r24[:]
|
||||
r3, err := b3.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
@@ -549,21 +549,21 @@ func tree2(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte,
|
||||
// \- B2
|
||||
func tree3(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte, []*ethpb.SignedBeaconBlock, error) {
|
||||
b0 := util.NewBeaconBlock()
|
||||
b0.Block.Slot = 1
|
||||
b0.Block.Slot = 0
|
||||
b0.Block.ParentRoot = genesisRoot
|
||||
r0, err := b0.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
b1 := util.NewBeaconBlock()
|
||||
b1.Block.Slot = 2
|
||||
b1.Block.Slot = 1
|
||||
b1.Block.ParentRoot = r0[:]
|
||||
r1, err := b1.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
b21 := util.NewBeaconBlock()
|
||||
b21.Block.Slot = 3
|
||||
b21.Block.Slot = 2
|
||||
b21.Block.ParentRoot = r1[:]
|
||||
b21.Block.StateRoot = bytesutil.PadTo([]byte{'A'}, 32)
|
||||
r21, err := b21.Block.HashTreeRoot()
|
||||
@@ -571,7 +571,7 @@ func tree3(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte,
|
||||
return nil, nil, err
|
||||
}
|
||||
b22 := util.NewBeaconBlock()
|
||||
b22.Block.Slot = 3
|
||||
b22.Block.Slot = 2
|
||||
b22.Block.ParentRoot = r1[:]
|
||||
b22.Block.StateRoot = bytesutil.PadTo([]byte{'B'}, 32)
|
||||
r22, err := b22.Block.HashTreeRoot()
|
||||
@@ -579,7 +579,7 @@ func tree3(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte,
|
||||
return nil, nil, err
|
||||
}
|
||||
b23 := util.NewBeaconBlock()
|
||||
b23.Block.Slot = 3
|
||||
b23.Block.Slot = 2
|
||||
b23.Block.ParentRoot = r1[:]
|
||||
b23.Block.StateRoot = bytesutil.PadTo([]byte{'C'}, 32)
|
||||
r23, err := b23.Block.HashTreeRoot()
|
||||
@@ -587,7 +587,7 @@ func tree3(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte,
|
||||
return nil, nil, err
|
||||
}
|
||||
b24 := util.NewBeaconBlock()
|
||||
b24.Block.Slot = 3
|
||||
b24.Block.Slot = 2
|
||||
b24.Block.ParentRoot = r1[:]
|
||||
b24.Block.StateRoot = bytesutil.PadTo([]byte{'D'}, 32)
|
||||
r24, err := b24.Block.HashTreeRoot()
|
||||
@@ -626,14 +626,14 @@ func tree3(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte,
|
||||
// \- B2
|
||||
func tree4(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte, []*ethpb.SignedBeaconBlock, error) {
|
||||
b0 := util.NewBeaconBlock()
|
||||
b0.Block.Slot = 1
|
||||
b0.Block.Slot = 0
|
||||
b0.Block.ParentRoot = genesisRoot
|
||||
r0, err := b0.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
b21 := util.NewBeaconBlock()
|
||||
b21.Block.Slot = 3
|
||||
b21.Block.Slot = 2
|
||||
b21.Block.ParentRoot = r0[:]
|
||||
b21.Block.StateRoot = bytesutil.PadTo([]byte{'A'}, 32)
|
||||
r21, err := b21.Block.HashTreeRoot()
|
||||
@@ -641,7 +641,7 @@ func tree4(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte,
|
||||
return nil, nil, err
|
||||
}
|
||||
b22 := util.NewBeaconBlock()
|
||||
b22.Block.Slot = 3
|
||||
b22.Block.Slot = 2
|
||||
b22.Block.ParentRoot = r0[:]
|
||||
b22.Block.StateRoot = bytesutil.PadTo([]byte{'B'}, 32)
|
||||
r22, err := b22.Block.HashTreeRoot()
|
||||
@@ -649,7 +649,7 @@ func tree4(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte,
|
||||
return nil, nil, err
|
||||
}
|
||||
b23 := util.NewBeaconBlock()
|
||||
b23.Block.Slot = 3
|
||||
b23.Block.Slot = 2
|
||||
b23.Block.ParentRoot = r0[:]
|
||||
b23.Block.StateRoot = bytesutil.PadTo([]byte{'C'}, 32)
|
||||
r23, err := b23.Block.HashTreeRoot()
|
||||
@@ -657,7 +657,7 @@ func tree4(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte,
|
||||
return nil, nil, err
|
||||
}
|
||||
b24 := util.NewBeaconBlock()
|
||||
b24.Block.Slot = 3
|
||||
b24.Block.Slot = 2
|
||||
b24.Block.ParentRoot = r0[:]
|
||||
b24.Block.StateRoot = bytesutil.PadTo([]byte{'D'}, 32)
|
||||
r24, err := b24.Block.HashTreeRoot()
|
||||
@@ -697,17 +697,17 @@ func TestLoadFinalizedBlocks(t *testing.T) {
|
||||
gRoot, err := gBlock.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
util.SaveBlock(t, ctx, beaconDB, gBlock)
|
||||
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, gRoot))
|
||||
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, [32]byte{}))
|
||||
roots, _, err := tree1(t, beaconDB, gRoot[:])
|
||||
require.NoError(t, err)
|
||||
|
||||
filteredBlocks, err := s.loadFinalizedBlocks(ctx, 0, 9)
|
||||
filteredBlocks, err := s.loadFinalizedBlocks(ctx, 0, 8)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(filteredBlocks))
|
||||
require.Equal(t, 0, len(filteredBlocks))
|
||||
require.NoError(t, beaconDB.SaveStateSummary(ctx, ðpb.StateSummary{Root: roots[8][:]}))
|
||||
|
||||
require.NoError(t, s.beaconDB.SaveFinalizedCheckpoint(ctx, ðpb.Checkpoint{Root: roots[8][:]}))
|
||||
filteredBlocks, err = s.loadFinalizedBlocks(ctx, 0, 9)
|
||||
filteredBlocks, err = s.loadFinalizedBlocks(ctx, 0, 8)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 7, len(filteredBlocks))
|
||||
require.Equal(t, 10, len(filteredBlocks))
|
||||
}
|
||||
|
||||
@@ -12,14 +12,12 @@ go_library(
|
||||
"log.go",
|
||||
"round_robin.go",
|
||||
"service.go",
|
||||
"verification.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v5/beacon-chain/sync/initial-sync",
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
deps = [
|
||||
"//async/abool:go_default_library",
|
||||
"//beacon-chain/blockchain:go_default_library",
|
||||
"//beacon-chain/blockchain/kzg:go_default_library",
|
||||
"//beacon-chain/core/feed/block:go_default_library",
|
||||
"//beacon-chain/core/feed/state:go_default_library",
|
||||
"//beacon-chain/core/transition:go_default_library",
|
||||
@@ -41,7 +39,6 @@ go_library(
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//container/leaky-bucket:go_default_library",
|
||||
"//crypto/rand:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//math:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//runtime:go_default_library",
|
||||
|
||||
@@ -312,7 +312,7 @@ func (f *blocksFetcher) handleRequest(ctx context.Context, start primitives.Slot
|
||||
|
||||
response.bwb, response.pid, response.err = f.fetchBlocksFromPeer(ctx, start, count, peers)
|
||||
if response.err == nil {
|
||||
bwb, err := f.fetchBlobsFromPeer(ctx, response.bwb, response.pid)
|
||||
bwb, err := f.fetchBlobsFromPeer(ctx, response.bwb, response.pid, peers)
|
||||
if err != nil {
|
||||
response.err = err
|
||||
}
|
||||
@@ -336,6 +336,11 @@ func (f *blocksFetcher) fetchBlocksFromPeer(
|
||||
Count: count,
|
||||
Step: 1,
|
||||
}
|
||||
bestPeers := f.hasSufficientBandwidth(peers, req.Count)
|
||||
// We append the best peers to the front so that higher capacity
|
||||
// peers are dialed first.
|
||||
peers = append(bestPeers, peers...)
|
||||
peers = dedupPeers(peers)
|
||||
for i := 0; i < len(peers); i++ {
|
||||
p := peers[i]
|
||||
blocks, err := f.requestBlocks(ctx, req, p)
|
||||
@@ -472,7 +477,7 @@ func missingCommitError(root [32]byte, slot primitives.Slot, missing [][]byte) e
|
||||
}
|
||||
|
||||
// fetchBlobsFromPeer fetches blocks from a single randomly selected peer.
|
||||
func (f *blocksFetcher) fetchBlobsFromPeer(ctx context.Context, bwb []blocks2.BlockWithROBlobs, pid peer.ID) ([]blocks2.BlockWithROBlobs, error) {
|
||||
func (f *blocksFetcher) fetchBlobsFromPeer(ctx context.Context, bwb []blocks2.BlockWithROBlobs, pid peer.ID, peers []peer.ID) ([]blocks2.BlockWithROBlobs, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "initialsync.fetchBlobsFromPeer")
|
||||
defer span.End()
|
||||
if slots.ToEpoch(f.clock.CurrentSlot()) < params.BeaconConfig().DenebForkEpoch {
|
||||
@@ -487,13 +492,30 @@ func (f *blocksFetcher) fetchBlobsFromPeer(ctx context.Context, bwb []blocks2.Bl
|
||||
if req == nil {
|
||||
return bwb, nil
|
||||
}
|
||||
// Request blobs from the same peer that gave us the blob batch.
|
||||
blobs, err := f.requestBlobs(ctx, req, pid)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not request blobs by range")
|
||||
peers = f.filterPeers(ctx, peers, peersPercentagePerRequest)
|
||||
// We dial the initial peer first to ensure that we get the desired set of blobs.
|
||||
wantedPeers := append([]peer.ID{pid}, peers...)
|
||||
bestPeers := f.hasSufficientBandwidth(wantedPeers, req.Count)
|
||||
// We append the best peers to the front so that higher capacity
|
||||
// peers are dialed first. If all of them fail, we fallback to the
|
||||
// initial peer we wanted to request blobs from.
|
||||
peers = append(bestPeers, pid)
|
||||
for i := 0; i < len(peers); i++ {
|
||||
p := peers[i]
|
||||
blobs, err := f.requestBlobs(ctx, req, p)
|
||||
if err != nil {
|
||||
log.WithField("peer", p).WithError(err).Debug("Could not request blobs by range from peer")
|
||||
continue
|
||||
}
|
||||
f.p2p.Peers().Scorers().BlockProviderScorer().Touch(p)
|
||||
robs, err := verifyAndPopulateBlobs(bwb, blobs, blobWindowStart)
|
||||
if err != nil {
|
||||
log.WithField("peer", p).WithError(err).Debug("Invalid BeaconBlobsByRange response")
|
||||
continue
|
||||
}
|
||||
return robs, err
|
||||
}
|
||||
f.p2p.Peers().Scorers().BlockProviderScorer().Touch(pid)
|
||||
return verifyAndPopulateBlobs(bwb, blobs, blobWindowStart)
|
||||
return nil, errNoPeersAvailable
|
||||
}
|
||||
|
||||
// requestBlocks is a wrapper for handling BeaconBlocksByRangeRequest requests/streams.
|
||||
@@ -606,6 +628,18 @@ func (f *blocksFetcher) waitForBandwidth(pid peer.ID, count uint64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *blocksFetcher) hasSufficientBandwidth(peers []peer.ID, count uint64) []peer.ID {
|
||||
filteredPeers := []peer.ID{}
|
||||
for _, p := range peers {
|
||||
if uint64(f.rateLimiter.Remaining(p.String())) < count {
|
||||
continue
|
||||
}
|
||||
copiedP := p
|
||||
filteredPeers = append(filteredPeers, copiedP)
|
||||
}
|
||||
return filteredPeers
|
||||
}
|
||||
|
||||
// Determine how long it will take for us to have the required number of blocks allowed by our rate limiter.
|
||||
// We do this by calculating the duration till the rate limiter can request these blocks without exceeding
|
||||
// the provided bandwidth limits per peer.
|
||||
@@ -626,3 +660,18 @@ func timeToWait(wanted, rem, capacity int64, timeTillEmpty time.Duration) time.D
|
||||
expectedTime := int64(timeTillEmpty) * blocksNeeded / currentNumBlks
|
||||
return time.Duration(expectedTime)
|
||||
}
|
||||
|
||||
// deduplicates the provided peer list.
|
||||
func dedupPeers(peers []peer.ID) []peer.ID {
|
||||
newPeerList := make([]peer.ID, 0, len(peers))
|
||||
peerExists := make(map[peer.ID]bool)
|
||||
|
||||
for i := range peers {
|
||||
if peerExists[peers[i]] {
|
||||
continue
|
||||
}
|
||||
newPeerList = append(newPeerList, peers[i])
|
||||
peerExists[peers[i]] = true
|
||||
}
|
||||
return newPeerList
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
|
||||
libp2pcore "github.com/libp2p/go-libp2p/core"
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
mock "github.com/prysmaticlabs/prysm/v5/beacon-chain/blockchain/testing"
|
||||
dbtest "github.com/prysmaticlabs/prysm/v5/beacon-chain/db/testing"
|
||||
p2pm "github.com/prysmaticlabs/prysm/v5/beacon-chain/p2p"
|
||||
@@ -1166,3 +1167,22 @@ func TestBatchLimit(t *testing.T) {
|
||||
|
||||
assert.Equal(t, params.BeaconConfig().MaxRequestBlocksDeneb, uint64(maxBatchLimit()))
|
||||
}
|
||||
|
||||
func TestBlockFetcher_HasSufficientBandwidth(t *testing.T) {
|
||||
bf := newBlocksFetcher(context.Background(), &blocksFetcherConfig{})
|
||||
currCap := bf.rateLimiter.Capacity()
|
||||
wantedAmt := currCap - 100
|
||||
bf.rateLimiter.Add(peer.ID("a").String(), wantedAmt)
|
||||
bf.rateLimiter.Add(peer.ID("c").String(), wantedAmt)
|
||||
bf.rateLimiter.Add(peer.ID("f").String(), wantedAmt)
|
||||
bf.rateLimiter.Add(peer.ID("d").String(), wantedAmt)
|
||||
|
||||
receivedPeers := bf.hasSufficientBandwidth([]peer.ID{"a", "b", "c", "d", "e", "f"}, 110)
|
||||
for _, p := range receivedPeers {
|
||||
switch p {
|
||||
case "a", "c", "f", "d":
|
||||
t.Errorf("peer has exceeded capacity: %s", p)
|
||||
}
|
||||
}
|
||||
assert.Equal(t, 2, len(receivedPeers))
|
||||
}
|
||||
|
||||
@@ -280,7 +280,7 @@ func (f *blocksFetcher) findForkWithPeer(ctx context.Context, pid peer.ID, slot
|
||||
}
|
||||
// We need to fetch the blobs for the given alt-chain if any exist, so that we can try to verify and import
|
||||
// the blocks.
|
||||
bwb, err := f.fetchBlobsFromPeer(ctx, altBlocks, pid)
|
||||
bwb, err := f.fetchBlobsFromPeer(ctx, altBlocks, pid, []peer.ID{pid})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to retrieve blobs for blocks found in findForkWithPeer")
|
||||
}
|
||||
@@ -302,7 +302,7 @@ func (f *blocksFetcher) findAncestor(ctx context.Context, pid peer.ID, b interfa
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "received invalid blocks in findAncestor")
|
||||
}
|
||||
bwb, err = f.fetchBlobsFromPeer(ctx, bwb, pid)
|
||||
bwb, err = f.fetchBlobsFromPeer(ctx, bwb, pid, []peer.ID{pid})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to retrieve blobs for blocks found in findAncestor")
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/transition"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/das"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/sync"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/verification"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
@@ -167,7 +168,7 @@ func (s *Service) processFetchedDataRegSync(
|
||||
if len(bwb) == 0 {
|
||||
return
|
||||
}
|
||||
bv := newBlobBatchVerifier(s.newBlobVerifier)
|
||||
bv := verification.NewBlobBatchVerifier(s.newBlobVerifier, verification.InitsyncSidecarRequirements)
|
||||
avs := das.NewLazilyPersistentStore(s.cfg.BlobStorage, bv)
|
||||
batchFields := logrus.Fields{
|
||||
"firstSlot": data.bwb[0].Block.Block().Slot(),
|
||||
@@ -326,7 +327,7 @@ func (s *Service) processBatchedBlocks(ctx context.Context, genesis time.Time,
|
||||
errParentDoesNotExist, first.Block().ParentRoot(), first.Block().Slot())
|
||||
}
|
||||
|
||||
bv := newBlobBatchVerifier(s.newBlobVerifier)
|
||||
bv := verification.NewBlobBatchVerifier(s.newBlobVerifier, verification.InitsyncSidecarRequirements)
|
||||
avs := das.NewLazilyPersistentStore(s.cfg.BlobStorage, bv)
|
||||
s.logBatchSyncStatus(genesis, first, len(bwb))
|
||||
for _, bb := range bwb {
|
||||
|
||||
@@ -340,7 +340,7 @@ func (s *Service) fetchOriginBlobs(pids []peer.ID) error {
|
||||
if len(sidecars) != len(req) {
|
||||
continue
|
||||
}
|
||||
bv := newBlobBatchVerifier(s.newBlobVerifier)
|
||||
bv := verification.NewBlobBatchVerifier(s.newBlobVerifier, verification.InitsyncSidecarRequirements)
|
||||
avs := das.NewLazilyPersistentStore(s.cfg.BlobStorage, bv)
|
||||
current := s.clock.CurrentSlot()
|
||||
if err := avs.Persist(current, sidecars...); err != nil {
|
||||
@@ -362,3 +362,9 @@ func shufflePeers(pids []peer.ID) {
|
||||
pids[i], pids[j] = pids[j], pids[i]
|
||||
})
|
||||
}
|
||||
|
||||
func newBlobVerifierFromInitializer(ini *verification.Initializer) verification.NewBlobVerifier {
|
||||
return func(b blocks.ROBlob, reqs []verification.Requirement) verification.BlobVerifier {
|
||||
return ini.NewBlobVerifier(b, reqs)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,6 +150,10 @@ var (
|
||||
Help: "Time to verify gossiped blob sidecars",
|
||||
},
|
||||
)
|
||||
pendingAttCount = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "gossip_pending_attestations_total",
|
||||
Help: "increased when receiving a new pending attestation",
|
||||
})
|
||||
|
||||
// Sync committee verification performance.
|
||||
syncMessagesForUnknownBlocks = promauto.NewCounter(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package sync
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"sync"
|
||||
@@ -157,7 +158,8 @@ func (s *Service) processAttestations(ctx context.Context, attestations []*ethpb
|
||||
|
||||
// This defines how pending attestations is saved in the map. The key is the
|
||||
// root of the missing block. The value is the list of pending attestations
|
||||
// that voted for that block root.
|
||||
// that voted for that block root. The caller of this function is responsible
|
||||
// for not sending repeated attestations to the pending queue.
|
||||
func (s *Service) savePendingAtt(att *ethpb.SignedAggregateAttestationAndProof) {
|
||||
root := bytesutil.ToBytes32(att.Message.Aggregate.Data.BeaconBlockRoot)
|
||||
|
||||
@@ -175,20 +177,37 @@ func (s *Service) savePendingAtt(att *ethpb.SignedAggregateAttestationAndProof)
|
||||
|
||||
_, ok := s.blkRootToPendingAtts[root]
|
||||
if !ok {
|
||||
pendingAttCount.Inc()
|
||||
s.blkRootToPendingAtts[root] = []*ethpb.SignedAggregateAttestationAndProof{att}
|
||||
return
|
||||
}
|
||||
|
||||
// Skip if the attestation from the same aggregator already exists in the pending queue.
|
||||
// Skip if the attestation from the same aggregator already exists in
|
||||
// the pending queue.
|
||||
for _, a := range s.blkRootToPendingAtts[root] {
|
||||
if a.Message.AggregatorIndex == att.Message.AggregatorIndex {
|
||||
if attsAreEqual(att, a) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
pendingAttCount.Inc()
|
||||
s.blkRootToPendingAtts[root] = append(s.blkRootToPendingAtts[root], att)
|
||||
}
|
||||
|
||||
func attsAreEqual(a, b *ethpb.SignedAggregateAttestationAndProof) bool {
|
||||
if a.Signature != nil {
|
||||
return b.Signature != nil && a.Message.AggregatorIndex == b.Message.AggregatorIndex
|
||||
}
|
||||
if b.Signature != nil {
|
||||
return false
|
||||
}
|
||||
if a.Message.Aggregate.Data.Slot != b.Message.Aggregate.Data.Slot {
|
||||
return false
|
||||
}
|
||||
if a.Message.Aggregate.Data.CommitteeIndex != b.Message.Aggregate.Data.CommitteeIndex {
|
||||
return false
|
||||
}
|
||||
return bytes.Equal(a.Message.Aggregate.AggregationBits, b.Message.Aggregate.AggregationBits)
|
||||
}
|
||||
|
||||
// This validates the pending attestations in the queue are still valid.
|
||||
// If not valid, a node will remove it in the queue in place. The validity
|
||||
// check specifies the pending attestation could not fall one epoch behind
|
||||
|
||||
@@ -399,7 +399,7 @@ func TestValidatePendingAtts_CanPruneOldAtts(t *testing.T) {
|
||||
assert.Equal(t, 0, len(s.blkRootToPendingAtts), "Did not delete block keys")
|
||||
}
|
||||
|
||||
func TestValidatePendingAtts_NoDuplicatingAggregatorIndex(t *testing.T) {
|
||||
func TestValidatePendingAtts_NoDuplicatingAtts(t *testing.T) {
|
||||
s := &Service{
|
||||
blkRootToPendingAtts: make(map[[32]byte][]*ethpb.SignedAggregateAttestationAndProof),
|
||||
}
|
||||
@@ -420,7 +420,7 @@ func TestValidatePendingAtts_NoDuplicatingAggregatorIndex(t *testing.T) {
|
||||
Message: ðpb.AggregateAttestationAndProof{
|
||||
AggregatorIndex: 2,
|
||||
Aggregate: ðpb.Attestation{
|
||||
Data: ðpb.AttestationData{Slot: 3, BeaconBlockRoot: r2[:]}}}})
|
||||
Data: ðpb.AttestationData{Slot: 2, BeaconBlockRoot: r2[:]}}}})
|
||||
|
||||
assert.Equal(t, 1, len(s.blkRootToPendingAtts[r1]), "Did not save pending atts")
|
||||
assert.Equal(t, 1, len(s.blkRootToPendingAtts[r2]), "Did not save pending atts")
|
||||
|
||||
@@ -151,14 +151,14 @@ func (s *Service) sendAndSaveBlobSidecars(ctx context.Context, request types.Blo
|
||||
if len(sidecars) != len(request) {
|
||||
return fmt.Errorf("received %d blob sidecars, expected %d for RPC", len(sidecars), len(request))
|
||||
}
|
||||
bv := verification.NewBlobBatchVerifier(s.newBlobVerifier, verification.PendingQueueSidecarRequirements)
|
||||
for _, sidecar := range sidecars {
|
||||
if err := verify.BlobAlignsWithBlock(sidecar, RoBlock); err != nil {
|
||||
return err
|
||||
}
|
||||
log.WithFields(blobFields(sidecar)).Debug("Received blob sidecar RPC")
|
||||
}
|
||||
|
||||
vscs, err := verification.BlobSidecarSliceNoop(sidecars)
|
||||
vscs, err := bv.VerifiedROBlobs(ctx, RoBlock, sidecars)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ func (s *Service) goodbyeRPCHandler(_ context.Context, msg interface{}, stream l
|
||||
return fmt.Errorf("wrong message type for goodbye, got %T, wanted *uint64", msg)
|
||||
}
|
||||
if err := s.rateLimiter.validateRequest(stream, 1); err != nil {
|
||||
log.WithError(err).Warn("Goodbye message from rate-limited peer.")
|
||||
log.WithError(err).Debug("Goodbye message from rate-limited peer.")
|
||||
} else {
|
||||
s.rateLimiter.add(stream, 1)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"batch.go",
|
||||
"blob.go",
|
||||
"cache.go",
|
||||
"error.go",
|
||||
@@ -45,6 +46,7 @@ go_library(
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"batch_test.go",
|
||||
"blob_test.go",
|
||||
"cache_test.go",
|
||||
"initializer_test.go",
|
||||
@@ -69,5 +71,6 @@ go_test(
|
||||
"//testing/util:go_default_library",
|
||||
"//time/slots:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_stretchr_testify//require:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package initialsync
|
||||
package verification
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/blockchain/kzg"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/das"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/verification"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
|
||||
)
|
||||
@@ -20,21 +18,17 @@ var (
|
||||
ErrBatchBlockRootMismatch = errors.New("Sidecar block header root does not match signed block")
|
||||
)
|
||||
|
||||
func newBlobVerifierFromInitializer(ini *verification.Initializer) verification.NewBlobVerifier {
|
||||
return func(b blocks.ROBlob, reqs []verification.Requirement) verification.BlobVerifier {
|
||||
return ini.NewBlobVerifier(b, reqs)
|
||||
}
|
||||
}
|
||||
|
||||
func newBlobBatchVerifier(newVerifier verification.NewBlobVerifier) *BlobBatchVerifier {
|
||||
// NewBlobBatchVerifier initializes a blob batch verifier. It requires the caller to correctly specify
|
||||
// verification Requirements and to also pass in a NewBlobVerifier, which is a callback function that
|
||||
// returns a new BlobVerifier for handling a single blob in the batch.
|
||||
func NewBlobBatchVerifier(newVerifier NewBlobVerifier, reqs []Requirement) *BlobBatchVerifier {
|
||||
return &BlobBatchVerifier{
|
||||
verifyKzg: kzg.Verify,
|
||||
newVerifier: newVerifier,
|
||||
reqs: reqs,
|
||||
}
|
||||
}
|
||||
|
||||
type kzgVerifier func(b ...blocks.ROBlob) error
|
||||
|
||||
// BlobBatchVerifier solves problems that come from verifying batches of blobs from RPC.
|
||||
// First: we only update forkchoice after the entire batch has completed, so the n+1 elements in the batch
|
||||
// won't be in forkchoice yet.
|
||||
@@ -42,18 +36,17 @@ type kzgVerifier func(b ...blocks.ROBlob) error
|
||||
// method to BlobVerifier to verify the kzg commitments of all blob sidecars for a block together, then using the cached
|
||||
// result of the batch verification when verifying the individual blobs.
|
||||
type BlobBatchVerifier struct {
|
||||
verifyKzg kzgVerifier
|
||||
newVerifier verification.NewBlobVerifier
|
||||
verifyKzg roblobCommitmentVerifier
|
||||
newVerifier NewBlobVerifier
|
||||
reqs []Requirement
|
||||
}
|
||||
|
||||
var _ das.BlobBatchVerifier = &BlobBatchVerifier{}
|
||||
|
||||
// VerifiedROBlobs satisfies the das.BlobBatchVerifier interface, used by das.AvailabilityStore.
|
||||
func (batch *BlobBatchVerifier) VerifiedROBlobs(ctx context.Context, blk blocks.ROBlock, scs []blocks.ROBlob) ([]blocks.VerifiedROBlob, error) {
|
||||
if len(scs) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
// We assume the proposer was validated wrt the block in batch block processing before performing the DA check.
|
||||
|
||||
// We assume the proposer is validated wrt the block in batch block processing before performing the DA check.
|
||||
// So at this stage we just need to make sure the value being signed and signature bytes match the block.
|
||||
for i := range scs {
|
||||
if blk.Signature() != bytesutil.ToBytes96(scs[i].SignedBlockHeader.Signature) {
|
||||
@@ -71,7 +64,7 @@ func (batch *BlobBatchVerifier) VerifiedROBlobs(ctx context.Context, blk blocks.
|
||||
}
|
||||
vs := make([]blocks.VerifiedROBlob, len(scs))
|
||||
for i := range scs {
|
||||
vb, err := batch.verifyOneBlob(ctx, scs[i])
|
||||
vb, err := batch.verifyOneBlob(scs[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -80,13 +73,13 @@ func (batch *BlobBatchVerifier) VerifiedROBlobs(ctx context.Context, blk blocks.
|
||||
return vs, nil
|
||||
}
|
||||
|
||||
func (batch *BlobBatchVerifier) verifyOneBlob(ctx context.Context, sc blocks.ROBlob) (blocks.VerifiedROBlob, error) {
|
||||
func (batch *BlobBatchVerifier) verifyOneBlob(sc blocks.ROBlob) (blocks.VerifiedROBlob, error) {
|
||||
vb := blocks.VerifiedROBlob{}
|
||||
bv := batch.newVerifier(sc, verification.InitsyncSidecarRequirements)
|
||||
bv := batch.newVerifier(sc, batch.reqs)
|
||||
// We can satisfy the following 2 requirements immediately because VerifiedROBlobs always verifies commitments
|
||||
// and block signature for all blobs in the batch before calling verifyOneBlob.
|
||||
bv.SatisfyRequirement(verification.RequireSidecarKzgProofVerified)
|
||||
bv.SatisfyRequirement(verification.RequireValidProposerSignature)
|
||||
bv.SatisfyRequirement(RequireSidecarKzgProofVerified)
|
||||
bv.SatisfyRequirement(RequireValidProposerSignature)
|
||||
|
||||
if err := bv.BlobIndexInBounds(); err != nil {
|
||||
return vb, err
|
||||
189
beacon-chain/verification/batch_test.go
Normal file
189
beacon-chain/verification/batch_test.go
Normal file
@@ -0,0 +1,189 @@
|
||||
package verification
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestBatchVerifier(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
mockCV := func(err error) roblobCommitmentVerifier {
|
||||
return func(...blocks.ROBlob) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
var invCmtErr = errors.New("mock invalid commitment")
|
||||
type vbcbt func() (blocks.VerifiedROBlob, error)
|
||||
vbcb := func(bl blocks.ROBlob, err error) vbcbt {
|
||||
return func() (blocks.VerifiedROBlob, error) {
|
||||
return blocks.VerifiedROBlob{ROBlob: bl}, err
|
||||
}
|
||||
}
|
||||
cases := []struct {
|
||||
name string
|
||||
nv func() NewBlobVerifier
|
||||
cv roblobCommitmentVerifier
|
||||
bandb func(t *testing.T, n int) (blocks.ROBlock, []blocks.ROBlob)
|
||||
err error
|
||||
nblobs int
|
||||
reqs []Requirement
|
||||
}{
|
||||
{
|
||||
name: "no blobs",
|
||||
bandb: func(t *testing.T, nb int) (blocks.ROBlock, []blocks.ROBlob) {
|
||||
return util.GenerateTestDenebBlockWithSidecar(t, [32]byte{}, 0, nb)
|
||||
},
|
||||
nv: func() NewBlobVerifier {
|
||||
return func(bl blocks.ROBlob, reqs []Requirement) BlobVerifier {
|
||||
return &MockBlobVerifier{cbVerifiedROBlob: vbcb(bl, nil)}
|
||||
}
|
||||
},
|
||||
nblobs: 0,
|
||||
},
|
||||
{
|
||||
name: "happy path",
|
||||
nv: func() NewBlobVerifier {
|
||||
return func(bl blocks.ROBlob, reqs []Requirement) BlobVerifier {
|
||||
return &MockBlobVerifier{cbVerifiedROBlob: vbcb(bl, nil)}
|
||||
}
|
||||
},
|
||||
bandb: func(t *testing.T, nb int) (blocks.ROBlock, []blocks.ROBlob) {
|
||||
return util.GenerateTestDenebBlockWithSidecar(t, [32]byte{}, 0, nb)
|
||||
},
|
||||
nblobs: 3,
|
||||
},
|
||||
{
|
||||
name: "partial batch",
|
||||
nv: func() NewBlobVerifier {
|
||||
return func(bl blocks.ROBlob, reqs []Requirement) BlobVerifier {
|
||||
return &MockBlobVerifier{cbVerifiedROBlob: vbcb(bl, nil)}
|
||||
}
|
||||
},
|
||||
bandb: func(t *testing.T, nb int) (blocks.ROBlock, []blocks.ROBlob) {
|
||||
// Add extra blobs to the block that we won't return
|
||||
blk, blbs := util.GenerateTestDenebBlockWithSidecar(t, [32]byte{}, 0, nb+3)
|
||||
return blk, blbs[0:3]
|
||||
},
|
||||
nblobs: 3,
|
||||
},
|
||||
{
|
||||
name: "invalid commitment",
|
||||
nv: func() NewBlobVerifier {
|
||||
return func(bl blocks.ROBlob, reqs []Requirement) BlobVerifier {
|
||||
return &MockBlobVerifier{cbVerifiedROBlob: func() (blocks.VerifiedROBlob, error) {
|
||||
t.Fatal("Batch verifier should stop before this point")
|
||||
return blocks.VerifiedROBlob{}, nil
|
||||
}}
|
||||
}
|
||||
},
|
||||
cv: mockCV(invCmtErr),
|
||||
bandb: func(t *testing.T, nb int) (blocks.ROBlock, []blocks.ROBlob) {
|
||||
return util.GenerateTestDenebBlockWithSidecar(t, [32]byte{}, 0, nb)
|
||||
},
|
||||
err: invCmtErr,
|
||||
nblobs: 1,
|
||||
},
|
||||
{
|
||||
name: "signature mismatch",
|
||||
nv: func() NewBlobVerifier {
|
||||
return func(bl blocks.ROBlob, reqs []Requirement) BlobVerifier {
|
||||
return &MockBlobVerifier{cbVerifiedROBlob: func() (blocks.VerifiedROBlob, error) {
|
||||
t.Fatal("Batch verifier should stop before this point")
|
||||
return blocks.VerifiedROBlob{}, nil
|
||||
}}
|
||||
}
|
||||
},
|
||||
bandb: func(t *testing.T, nb int) (blocks.ROBlock, []blocks.ROBlob) {
|
||||
blk, blbs := util.GenerateTestDenebBlockWithSidecar(t, [32]byte{}, 0, nb)
|
||||
blbs[0].SignedBlockHeader.Signature = []byte("wrong")
|
||||
return blk, blbs
|
||||
},
|
||||
err: ErrBatchSignatureMismatch,
|
||||
nblobs: 2,
|
||||
},
|
||||
{
|
||||
name: "root mismatch",
|
||||
nv: func() NewBlobVerifier {
|
||||
return func(bl blocks.ROBlob, reqs []Requirement) BlobVerifier {
|
||||
return &MockBlobVerifier{cbVerifiedROBlob: func() (blocks.VerifiedROBlob, error) {
|
||||
t.Fatal("Batch verifier should stop before this point")
|
||||
return blocks.VerifiedROBlob{}, nil
|
||||
}}
|
||||
}
|
||||
},
|
||||
bandb: func(t *testing.T, nb int) (blocks.ROBlock, []blocks.ROBlob) {
|
||||
blk, blbs := util.GenerateTestDenebBlockWithSidecar(t, [32]byte{}, 0, nb)
|
||||
wr, err := blocks.NewROBlobWithRoot(blbs[0].BlobSidecar, bytesutil.ToBytes32([]byte("wrong")))
|
||||
require.NoError(t, err)
|
||||
blbs[0] = wr
|
||||
return blk, blbs
|
||||
},
|
||||
err: ErrBatchBlockRootMismatch,
|
||||
nblobs: 1,
|
||||
},
|
||||
{
|
||||
name: "idx oob",
|
||||
nv: func() NewBlobVerifier {
|
||||
return func(bl blocks.ROBlob, reqs []Requirement) BlobVerifier {
|
||||
return &MockBlobVerifier{
|
||||
ErrBlobIndexInBounds: ErrBlobIndexInvalid,
|
||||
cbVerifiedROBlob: func() (blocks.VerifiedROBlob, error) {
|
||||
t.Fatal("Batch verifier should stop before this point")
|
||||
return blocks.VerifiedROBlob{}, nil
|
||||
}}
|
||||
}
|
||||
},
|
||||
bandb: func(t *testing.T, nb int) (blocks.ROBlock, []blocks.ROBlob) {
|
||||
return util.GenerateTestDenebBlockWithSidecar(t, [32]byte{}, 0, nb)
|
||||
},
|
||||
nblobs: 1,
|
||||
err: ErrBlobIndexInvalid,
|
||||
},
|
||||
{
|
||||
name: "inclusion proof invalid",
|
||||
nv: func() NewBlobVerifier {
|
||||
return func(bl blocks.ROBlob, reqs []Requirement) BlobVerifier {
|
||||
return &MockBlobVerifier{
|
||||
ErrSidecarInclusionProven: ErrSidecarInclusionProofInvalid,
|
||||
cbVerifiedROBlob: func() (blocks.VerifiedROBlob, error) {
|
||||
t.Fatal("Batch verifier should stop before this point")
|
||||
return blocks.VerifiedROBlob{}, nil
|
||||
}}
|
||||
}
|
||||
},
|
||||
bandb: func(t *testing.T, nb int) (blocks.ROBlock, []blocks.ROBlob) {
|
||||
return util.GenerateTestDenebBlockWithSidecar(t, [32]byte{}, 0, nb)
|
||||
},
|
||||
nblobs: 1,
|
||||
err: ErrSidecarInclusionProofInvalid,
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
blk, blbs := c.bandb(t, c.nblobs)
|
||||
reqs := c.reqs
|
||||
if reqs == nil {
|
||||
reqs = InitsyncSidecarRequirements
|
||||
}
|
||||
bbv := NewBlobBatchVerifier(c.nv(), reqs)
|
||||
if c.cv == nil {
|
||||
bbv.verifyKzg = mockCV(nil)
|
||||
} else {
|
||||
bbv.verifyKzg = c.cv
|
||||
}
|
||||
vb, err := bbv.VerifiedROBlobs(ctx, blk, blbs)
|
||||
if c.err != nil {
|
||||
require.ErrorIs(t, err, c.err)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, c.nblobs, len(vb))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -70,6 +70,9 @@ var InitsyncSidecarRequirements = requirementList(GossipSidecarRequirements).exc
|
||||
// BackfillSidecarRequirements is the same as InitsyncSidecarRequirements.
|
||||
var BackfillSidecarRequirements = requirementList(InitsyncSidecarRequirements).excluding()
|
||||
|
||||
// PendingQueueSidecarRequirements is the same as InitsyncSidecarRequirements, used by the pending blocks queue.
|
||||
var PendingQueueSidecarRequirements = requirementList(InitsyncSidecarRequirements).excluding()
|
||||
|
||||
var (
|
||||
ErrBlobInvalid = errors.New("blob failed verification")
|
||||
// ErrBlobIndexInvalid means RequireBlobIndexInBounds failed.
|
||||
@@ -160,6 +163,7 @@ func (bv *ROBlobVerifier) NotFromFutureSlot() (err error) {
|
||||
earliestStart := bv.clock.SlotStart(bv.blob.Slot()).Add(-1 * params.BeaconConfig().MaximumGossipClockDisparityDuration())
|
||||
// If the system time is still before earliestStart, we consider the blob from a future slot and return an error.
|
||||
if bv.clock.Now().Before(earliestStart) {
|
||||
log.WithFields(logging.BlobFields(bv.blob)).Debug("sidecar slot is too far in the future")
|
||||
return ErrFromFutureSlot
|
||||
}
|
||||
return nil
|
||||
@@ -176,6 +180,7 @@ func (bv *ROBlobVerifier) SlotAboveFinalized() (err error) {
|
||||
return errors.Wrapf(ErrSlotNotAfterFinalized, "error computing epoch start slot for finalized checkpoint (%d) %s", fcp.Epoch, err.Error())
|
||||
}
|
||||
if bv.blob.Slot() <= fSlot {
|
||||
log.WithFields(logging.BlobFields(bv.blob)).Debug("sidecar slot is not after finalized checkpoint")
|
||||
return ErrSlotNotAfterFinalized
|
||||
}
|
||||
return nil
|
||||
@@ -225,6 +230,7 @@ func (bv *ROBlobVerifier) SidecarParentSeen(parentSeen func([32]byte) bool) (err
|
||||
if bv.fc.HasNode(bv.blob.ParentRoot()) {
|
||||
return nil
|
||||
}
|
||||
log.WithFields(logging.BlobFields(bv.blob)).Debug("parent root has not been seen")
|
||||
return ErrSidecarParentNotSeen
|
||||
}
|
||||
|
||||
@@ -233,6 +239,7 @@ func (bv *ROBlobVerifier) SidecarParentSeen(parentSeen func([32]byte) bool) (err
|
||||
func (bv *ROBlobVerifier) SidecarParentValid(badParent func([32]byte) bool) (err error) {
|
||||
defer bv.recordResult(RequireSidecarParentValid, &err)
|
||||
if badParent != nil && badParent(bv.blob.ParentRoot()) {
|
||||
log.WithFields(logging.BlobFields(bv.blob)).Debug("parent root is invalid")
|
||||
return ErrSidecarParentInvalid
|
||||
}
|
||||
return nil
|
||||
@@ -258,6 +265,7 @@ func (bv *ROBlobVerifier) SidecarParentSlotLower() (err error) {
|
||||
func (bv *ROBlobVerifier) SidecarDescendsFromFinalized() (err error) {
|
||||
defer bv.recordResult(RequireSidecarDescendsFromFinalized, &err)
|
||||
if !bv.fc.HasNode(bv.blob.ParentRoot()) {
|
||||
log.WithFields(logging.BlobFields(bv.blob)).Debug("parent root not in forkchoice")
|
||||
return ErrSidecarNotFinalizedDescendent
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -39,7 +39,7 @@ func TestResultList(t *testing.T) {
|
||||
func TestExportedBlobSanityCheck(t *testing.T) {
|
||||
// make sure all requirement lists contain the bare minimum checks
|
||||
sanity := []Requirement{RequireValidProposerSignature, RequireSidecarKzgProofVerified, RequireBlobIndexInBounds, RequireSidecarInclusionProven}
|
||||
reqs := [][]Requirement{GossipSidecarRequirements, SpectestSidecarRequirements, InitsyncSidecarRequirements, BackfillSidecarRequirements}
|
||||
reqs := [][]Requirement{GossipSidecarRequirements, SpectestSidecarRequirements, InitsyncSidecarRequirements, BackfillSidecarRequirements, PendingQueueSidecarRequirements}
|
||||
for i := range reqs {
|
||||
r := reqs[i]
|
||||
reqMap := make(map[Requirement]struct{})
|
||||
|
||||
@@ -6,13 +6,18 @@ go_library(
|
||||
"buckets.go",
|
||||
"cmd.go",
|
||||
"query.go",
|
||||
"span.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v5/cmd/prysmctl/db",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//beacon-chain/db/kv:go_default_library",
|
||||
"//beacon-chain/slasher:go_default_library",
|
||||
"//beacon-chain/slasher/types:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||
"@com_github_jedib0t_go_pretty_v6//table:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@com_github_urfave_cli_v2//:go_default_library",
|
||||
|
||||
@@ -9,6 +9,7 @@ var Commands = []*cli.Command{
|
||||
Subcommands: []*cli.Command{
|
||||
queryCmd,
|
||||
bucketsCmd,
|
||||
spanCmd,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
304
cmd/prysmctl/db/span.go
Normal file
304
cmd/prysmctl/db/span.go
Normal file
@@ -0,0 +1,304 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/slasher"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/slasher/types"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
const DefaultChunkKind = types.MinSpan
|
||||
|
||||
var (
|
||||
f = struct {
|
||||
Path string
|
||||
ValidatorIndex uint64
|
||||
Epoch uint64
|
||||
ChunkKind string
|
||||
ChunkSize uint64
|
||||
ValidatorChunkSize uint64
|
||||
HistoryLength uint64
|
||||
IsDisplayAllValidatorsInChunk bool
|
||||
IsDisplayAllEpochsInChunk bool
|
||||
}{}
|
||||
|
||||
slasherDefaultParams = slasher.DefaultParams()
|
||||
)
|
||||
|
||||
var spanCmd = &cli.Command{
|
||||
Name: "slasher-span-display",
|
||||
Usage: "visualise values in db span bucket",
|
||||
Action: func(c *cli.Context) error {
|
||||
if err := spanAction(c); err != nil {
|
||||
return errors.Wrapf(err, "visualise values in db span bucket failed")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "db-path-directory",
|
||||
Usage: "path to directory containing slasher.db",
|
||||
Destination: &f.Path,
|
||||
Required: true,
|
||||
},
|
||||
&cli.Uint64Flag{
|
||||
Name: "validator-index",
|
||||
Usage: "filter by validator index",
|
||||
Destination: &f.ValidatorIndex,
|
||||
Required: true,
|
||||
},
|
||||
&cli.Uint64Flag{
|
||||
Name: "epoch",
|
||||
Usage: "filter by epoch",
|
||||
Destination: &f.Epoch,
|
||||
Required: true,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "chunk-kind",
|
||||
Usage: "chunk kind to query (maxspan|minspan)",
|
||||
Destination: &f.ChunkKind,
|
||||
Value: DefaultChunkKind.String(),
|
||||
DefaultText: DefaultChunkKind.String(),
|
||||
},
|
||||
&cli.Uint64Flag{
|
||||
Name: "chunk-size",
|
||||
Usage: "chunk size to query",
|
||||
Destination: &f.ChunkSize,
|
||||
DefaultText: fmt.Sprintf("%d", slasherDefaultParams.ChunkSize()),
|
||||
},
|
||||
&cli.Uint64Flag{
|
||||
Name: "validator-chunk-size",
|
||||
Usage: "validator chunk size to query",
|
||||
Destination: &f.ValidatorChunkSize,
|
||||
DefaultText: fmt.Sprintf("%d", slasherDefaultParams.ValidatorChunkSize()),
|
||||
},
|
||||
&cli.Uint64Flag{
|
||||
Name: "history-length",
|
||||
Usage: "history length to query",
|
||||
Destination: &f.HistoryLength,
|
||||
DefaultText: fmt.Sprintf("%d", slasherDefaultParams.HistoryLength()),
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "display-all-validators-in-chunk",
|
||||
Usage: "display all validators in chunk",
|
||||
Destination: &f.IsDisplayAllValidatorsInChunk,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "display-all-epochs-in-chunk",
|
||||
Usage: "display all epochs in chunk",
|
||||
Destination: &f.IsDisplayAllEpochsInChunk,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func spanAction(cliCtx *cli.Context) error {
|
||||
var (
|
||||
chunk slasher.Chunker
|
||||
validatorChunkIdx uint64
|
||||
lastEpochForValidatorIndex primitives.Epoch
|
||||
|
||||
err error
|
||||
)
|
||||
|
||||
// context
|
||||
ctx := cliCtx.Context
|
||||
|
||||
// variables
|
||||
chunkKind := getChunkKind()
|
||||
params := getSlasherParams()
|
||||
i := primitives.ValidatorIndex(f.ValidatorIndex)
|
||||
epoch := primitives.Epoch(f.Epoch)
|
||||
|
||||
// display configuration
|
||||
fmt.Printf("############################# SLASHER PARAMS ###############################\n")
|
||||
fmt.Printf("# Chunk Size: %d\n", params.ChunkSize())
|
||||
fmt.Printf("# Validator Chunk Size: %d\n", params.ValidatorChunkSize())
|
||||
fmt.Printf("# History Length: %d\n", params.HistoryLength())
|
||||
fmt.Printf("# DB: %s\n", f.Path)
|
||||
fmt.Printf("# Chunk Kind: %s\n", chunkKind)
|
||||
fmt.Printf("# Validator: %d\n", i)
|
||||
fmt.Printf("# Epoch: %d\n", epoch)
|
||||
fmt.Printf("############################################################################\n")
|
||||
|
||||
// fetch chunk in database
|
||||
if lastEpochForValidatorIndex, _, validatorChunkIdx, chunk, err = slasher.GetChunkFromDatabase(
|
||||
ctx,
|
||||
f.Path,
|
||||
slasher.GetChunkFromDatabaseFilters{
|
||||
ChunkKind: chunkKind,
|
||||
ValidatorIndex: i,
|
||||
SourceEpoch: epoch,
|
||||
IsDisplayAllValidatorsInChunk: f.IsDisplayAllValidatorsInChunk,
|
||||
IsDisplayAllEpochsInChunk: f.IsDisplayAllEpochsInChunk,
|
||||
},
|
||||
params,
|
||||
); err != nil {
|
||||
return errors.Wrapf(err, "could not get chunk from database")
|
||||
}
|
||||
|
||||
// fetch information related to chunk
|
||||
fmt.Printf("\n################################ CHUNK #####################################\n")
|
||||
firstValidator := params.ValidatorIndexesInChunk(validatorChunkIdx)[0]
|
||||
firstEpoch := epoch - (epoch.Mod(params.ChunkSize()))
|
||||
fmt.Printf("# First validator in chunk: %d\n", firstValidator)
|
||||
fmt.Printf("# First epoch in chunk: %d\n\n", firstEpoch)
|
||||
fmt.Printf("# Last epoch found in database for validator(%d): %d\n", i, lastEpochForValidatorIndex)
|
||||
fmt.Printf("############################################################################\n\n")
|
||||
|
||||
// init table
|
||||
tw := table.NewWriter()
|
||||
|
||||
minLowerBound := lastEpochForValidatorIndex.Sub(uint64(params.HistoryLength()))
|
||||
if f.IsDisplayAllValidatorsInChunk {
|
||||
if f.IsDisplayAllEpochsInChunk {
|
||||
// display all validators and epochs in chunk
|
||||
|
||||
// headers
|
||||
addEpochsHeader(tw, params.ChunkSize(), firstEpoch)
|
||||
|
||||
// rows
|
||||
b := chunk.Chunk()
|
||||
c := uint64(0)
|
||||
for z := uint64(0); z < uint64(len(b)); z += params.ChunkSize() {
|
||||
end := z + params.ChunkSize()
|
||||
if end > uint64(len(b)) {
|
||||
end = uint64(len(b))
|
||||
}
|
||||
subChunk := b[z:end]
|
||||
|
||||
row := make(table.Row, params.ChunkSize()+1)
|
||||
title := firstValidator + primitives.ValidatorIndex(c)
|
||||
row[0] = title
|
||||
for y, span := range subChunk {
|
||||
row[y+1] = getSpanOrNonApplicable(firstEpoch, y, minLowerBound, lastEpochForValidatorIndex, span)
|
||||
}
|
||||
tw.AppendRow(row)
|
||||
|
||||
c++
|
||||
}
|
||||
} else {
|
||||
// display all validators but only the requested epoch in chunk
|
||||
indexEpochInChunk := epoch - firstEpoch
|
||||
|
||||
// headers
|
||||
addEpochsHeader(tw, 1, firstEpoch)
|
||||
|
||||
// rows
|
||||
b := chunk.Chunk()
|
||||
c := uint64(0)
|
||||
for z := uint64(0); z < uint64(len(b)); z += params.ChunkSize() {
|
||||
end := z + params.ChunkSize()
|
||||
if end > uint64(len(b)) {
|
||||
end = uint64(len(b))
|
||||
}
|
||||
subChunk := b[z:end]
|
||||
|
||||
row := make(table.Row, 2)
|
||||
title := firstValidator + primitives.ValidatorIndex(c)
|
||||
row[0] = title
|
||||
row[1] = subChunk[indexEpochInChunk]
|
||||
tw.AppendRow(row)
|
||||
|
||||
c++
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if f.IsDisplayAllEpochsInChunk {
|
||||
// display only the requested validator with all epochs in chunk
|
||||
|
||||
// headers
|
||||
addEpochsHeader(tw, params.ChunkSize(), firstEpoch)
|
||||
|
||||
// rows
|
||||
b := chunk.Chunk()
|
||||
validatorFirstEpochIdx := uint64(i.Mod(params.ValidatorChunkSize())) * params.ChunkSize()
|
||||
subChunk := b[validatorFirstEpochIdx : validatorFirstEpochIdx+params.ChunkSize()]
|
||||
row := make(table.Row, params.ChunkSize()+1)
|
||||
title := i
|
||||
row[0] = title
|
||||
for y, span := range subChunk {
|
||||
row[y+1] = getSpanOrNonApplicable(firstEpoch, y, minLowerBound, lastEpochForValidatorIndex, span)
|
||||
}
|
||||
tw.AppendRow(row)
|
||||
} else {
|
||||
// display only the requested validator and epoch in chunk
|
||||
|
||||
// headers
|
||||
addEpochsHeader(tw, 1, epoch)
|
||||
|
||||
// rows
|
||||
b := chunk.Chunk()
|
||||
validatorFirstEpochIdx := uint64(i.Mod(params.ValidatorChunkSize())) * params.ChunkSize()
|
||||
subChunk := b[validatorFirstEpochIdx : validatorFirstEpochIdx+params.ChunkSize()]
|
||||
row := make(table.Row, 2)
|
||||
title := i
|
||||
row[0] = title
|
||||
indexEpochInChunk := epoch - firstEpoch
|
||||
row[1] = subChunk[indexEpochInChunk]
|
||||
tw.AppendRow(row)
|
||||
}
|
||||
}
|
||||
|
||||
// display table
|
||||
displayTable(tw)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// getSpanOrNonApplicable checks if there's some epoch that are not correct in chunk due to the round robin
|
||||
// nature of 2D chunking when an epoch gets overwritten by an epoch eg. (params.historyLength + next_epoch) > params.historyLength
|
||||
// if we are out of the range, we display a n/a value otherwise the span value
|
||||
func getSpanOrNonApplicable(firstEpoch primitives.Epoch, y int, minLowerBound primitives.Epoch, lastEpochForValidatorIndex primitives.Epoch, span uint16) string {
|
||||
if firstEpoch.Add(uint64(y)) < minLowerBound || firstEpoch.Add(uint64(y)) > lastEpochForValidatorIndex {
|
||||
return "-"
|
||||
}
|
||||
return fmt.Sprintf("%d", span)
|
||||
}
|
||||
|
||||
func displayTable(tw table.Writer) {
|
||||
tw.AppendSeparator()
|
||||
fmt.Println(tw.Render())
|
||||
}
|
||||
|
||||
func addEpochsHeader(tw table.Writer, nbEpoch uint64, firstEpoch primitives.Epoch) {
|
||||
header := table.Row{"Validator / Epoch"}
|
||||
for y := 0; uint64(y) < nbEpoch; y++ {
|
||||
header = append(header, firstEpoch+primitives.Epoch(y))
|
||||
}
|
||||
tw.AppendHeader(header)
|
||||
}
|
||||
|
||||
func getChunkKind() types.ChunkKind {
|
||||
chunkKind := types.MinSpan
|
||||
if f.ChunkKind == "maxspan" {
|
||||
chunkKind = types.MaxSpan
|
||||
}
|
||||
return chunkKind
|
||||
}
|
||||
|
||||
func getSlasherParams() *slasher.Parameters {
|
||||
var (
|
||||
chunkSize, validatorChunkSize uint64
|
||||
historyLength primitives.Epoch
|
||||
)
|
||||
if f.ChunkSize != 0 && f.ChunkSize != slasherDefaultParams.ChunkSize() {
|
||||
chunkSize = f.ChunkSize
|
||||
} else {
|
||||
chunkSize = slasherDefaultParams.ChunkSize()
|
||||
}
|
||||
if f.ValidatorChunkSize != 0 && f.ValidatorChunkSize != slasherDefaultParams.ValidatorChunkSize() {
|
||||
validatorChunkSize = f.ValidatorChunkSize
|
||||
} else {
|
||||
validatorChunkSize = slasherDefaultParams.ValidatorChunkSize()
|
||||
}
|
||||
if f.HistoryLength != 0 && f.HistoryLength != uint64(slasherDefaultParams.HistoryLength()) {
|
||||
historyLength = primitives.Epoch(f.HistoryLength)
|
||||
} else {
|
||||
historyLength = slasherDefaultParams.HistoryLength()
|
||||
}
|
||||
return slasher.NewParams(chunkSize, validatorChunkSize, historyLength)
|
||||
}
|
||||
@@ -95,6 +95,28 @@ var (
|
||||
Name: "attest-timely",
|
||||
Usage: "Fixes validator can attest timely after current block processes. See #8185 for more details.",
|
||||
}
|
||||
optimisticExecution = &cli.BoolFlag{
|
||||
Name: "optimistic-execution",
|
||||
Usage: "Allows the beacon to run without a connection to an EL. Useful for nodes without large storage.",
|
||||
}
|
||||
blobsAreAvailable = &cli.BoolFlag{
|
||||
Name: "blobs-are-available",
|
||||
Usage: "Disables blob gossip, requests, and checks for blob data availability. Useful for nodes without large internet bandwidth.",
|
||||
}
|
||||
allowDeepReorg = &cli.BoolFlag{
|
||||
Name: "allow-deep-reorg",
|
||||
Usage: "Allow for honest reorgs of arbitrary depth as long as the orphaned chain has less than PROPOSER_SCORE_BOOST.",
|
||||
}
|
||||
withholdAttestations = &cli.BoolFlag{
|
||||
Name: "withhold_consecutive_attestations",
|
||||
Usage: "Withhold attestations for consecutive blocks. Useful in conjunction with --allow-deep-reorg.",
|
||||
Hidden: true,
|
||||
}
|
||||
followMajority = &cli.BoolFlag{
|
||||
Name: "follow-majority",
|
||||
Usage: "Disable state transition validation and instead follow the attester majority. Useful for systems with low resources.",
|
||||
Hidden: true,
|
||||
}
|
||||
enableSlasherFlag = &cli.BoolFlag{
|
||||
Name: "slasher",
|
||||
Usage: "Enables a slasher in the beacon node for detecting slashable offenses.",
|
||||
|
||||
63
go.mod
63
go.mod
@@ -28,7 +28,7 @@ require (
|
||||
github.com/golang/protobuf v1.5.3
|
||||
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb
|
||||
github.com/google/gofuzz v1.2.0
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/google/uuid v1.4.0
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/gostaticanalysis/comment v1.4.2
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.2.2
|
||||
@@ -39,11 +39,12 @@ require (
|
||||
github.com/holiman/uint256 v1.2.4
|
||||
github.com/ianlancetaylor/cgosymbolizer v0.0.0-20200424224625-be1b05b0b279
|
||||
github.com/ipfs/go-log/v2 v2.5.1
|
||||
github.com/jedib0t/go-pretty/v6 v6.5.4
|
||||
github.com/joonix/log v0.0.0-20200409080653-9c1d2ceb5f1d
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213
|
||||
github.com/kr/pretty v0.3.1
|
||||
github.com/libp2p/go-libp2p v0.32.1
|
||||
github.com/libp2p/go-libp2p v0.33.1
|
||||
github.com/libp2p/go-libp2p-mplex v0.9.0
|
||||
github.com/libp2p/go-libp2p-pubsub v0.10.0
|
||||
github.com/libp2p/go-mplex v0.7.0
|
||||
@@ -53,15 +54,15 @@ require (
|
||||
github.com/minio/highwayhash v1.0.2
|
||||
github.com/minio/sha256-simd v1.0.1
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
|
||||
github.com/multiformats/go-multiaddr v0.12.1
|
||||
github.com/multiformats/go-multiaddr v0.12.2
|
||||
github.com/onsi/ginkgo v1.16.5
|
||||
github.com/onsi/gomega v1.27.10
|
||||
github.com/onsi/gomega v1.30.0
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
github.com/paulbellamy/ratecounter v0.2.0
|
||||
github.com/pborman/uuid v1.2.1
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.17.0
|
||||
github.com/prometheus/client_model v0.5.0
|
||||
github.com/prometheus/client_golang v1.18.0
|
||||
github.com/prometheus/client_model v0.6.0
|
||||
github.com/prometheus/prom2json v1.3.0
|
||||
github.com/prysmaticlabs/fastssz v0.0.0-20221107182844-78142813af44
|
||||
github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7
|
||||
@@ -85,15 +86,15 @@ require (
|
||||
go.etcd.io/bbolt v1.3.6
|
||||
go.opencensus.io v0.24.0
|
||||
go.uber.org/automaxprocs v1.5.2
|
||||
go.uber.org/mock v0.3.0
|
||||
golang.org/x/crypto v0.17.0
|
||||
golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611
|
||||
golang.org/x/mod v0.14.0
|
||||
golang.org/x/sync v0.5.0
|
||||
golang.org/x/tools v0.16.0
|
||||
go.uber.org/mock v0.4.0
|
||||
golang.org/x/crypto v0.19.0
|
||||
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a
|
||||
golang.org/x/mod v0.15.0
|
||||
golang.org/x/sync v0.6.0
|
||||
golang.org/x/tools v0.18.0
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1
|
||||
google.golang.org/grpc v1.56.3
|
||||
google.golang.org/protobuf v1.31.0
|
||||
google.golang.org/protobuf v1.32.0
|
||||
gopkg.in/d4l3k/messagediff.v1 v1.2.1
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
@@ -134,7 +135,7 @@ require (
|
||||
github.com/elastic/gosigar v0.14.2 // indirect
|
||||
github.com/ethereum/c-kzg-4844 v0.4.0 // indirect
|
||||
github.com/ferranbt/fastssz v0.0.0-20210120143747-11b9eff30ea9 // indirect
|
||||
github.com/flynn/noise v1.0.0 // indirect
|
||||
github.com/flynn/noise v1.1.0 // indirect
|
||||
github.com/francoispqt/gojay v1.2.13 // indirect
|
||||
github.com/getsentry/sentry-go v0.25.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
@@ -145,9 +146,9 @@ require (
|
||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||
github.com/gofrs/flock v0.8.1 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/gopacket v1.1.19 // indirect
|
||||
github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b // indirect
|
||||
github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect
|
||||
github.com/gorilla/websocket v1.5.1 // indirect
|
||||
github.com/graph-gophers/graphql-go v1.3.0 // indirect
|
||||
github.com/hashicorp/go-bexpr v0.1.10 // indirect
|
||||
@@ -164,8 +165,8 @@ require (
|
||||
github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
|
||||
github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a // indirect
|
||||
github.com/karalabe/usb v0.0.3-0.20230711191512-61db3e06439c // indirect
|
||||
github.com/klauspost/compress v1.17.4 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
|
||||
github.com/klauspost/compress v1.17.6 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||
github.com/koron/go-ssdp v0.0.4 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/leodido/go-urn v1.2.3 // indirect
|
||||
@@ -183,8 +184,7 @@ require (
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
|
||||
github.com/miekg/dns v1.1.56 // indirect
|
||||
github.com/miekg/dns v1.1.58 // indirect
|
||||
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect
|
||||
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
||||
@@ -205,16 +205,15 @@ require (
|
||||
github.com/multiformats/go-varint v0.0.7 // indirect
|
||||
github.com/nxadm/tail v1.4.8 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.13.0 // indirect
|
||||
github.com/opencontainers/runtime-spec v1.1.0 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.15.0 // indirect
|
||||
github.com/opencontainers/runtime-spec v1.2.0 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/common v0.45.0 // indirect
|
||||
github.com/prometheus/common v0.47.0 // indirect
|
||||
github.com/prometheus/procfs v0.12.0 // indirect
|
||||
github.com/quic-go/qpack v0.4.0 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.3.4 // indirect
|
||||
github.com/quic-go/quic-go v0.39.4 // indirect
|
||||
github.com/quic-go/quic-go v0.42.0 // indirect
|
||||
github.com/quic-go/webtransport-go v0.6.0 // indirect
|
||||
github.com/raulk/go-watchdog v1.3.0 // indirect
|
||||
github.com/rivo/uniseg v0.4.4 // indirect
|
||||
@@ -233,13 +232,13 @@ require (
|
||||
go.uber.org/dig v1.17.1 // indirect
|
||||
go.uber.org/fx v1.20.1 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.26.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/exp/typeparams v0.0.0-20231108232855-2478ac86f678 // indirect
|
||||
golang.org/x/net v0.19.0 // indirect
|
||||
golang.org/x/oauth2 v0.12.0 // indirect
|
||||
golang.org/x/term v0.15.0 // indirect
|
||||
golang.org/x/net v0.21.0 // indirect
|
||||
golang.org/x/oauth2 v0.16.0 // indirect
|
||||
golang.org/x/term v0.17.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||
@@ -253,12 +252,12 @@ require (
|
||||
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
|
||||
github.com/fatih/color v1.13.0 // indirect
|
||||
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect
|
||||
github.com/go-logr/logr v1.2.4 // indirect
|
||||
github.com/go-logr/logr v1.3.0 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/go-playground/validator/v10 v10.13.0
|
||||
github.com/peterh/liner v1.2.0 // indirect
|
||||
github.com/prysmaticlabs/gohashtree v0.0.4-beta
|
||||
golang.org/x/sys v0.15.0 // indirect
|
||||
golang.org/x/sys v0.17.0 // indirect
|
||||
google.golang.org/api v0.44.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
k8s.io/klog/v2 v2.80.0 // indirect
|
||||
|
||||
130
go.sum
130
go.sum
@@ -275,8 +275,8 @@ github.com/ferranbt/fastssz v0.0.0-20210120143747-11b9eff30ea9/go.mod h1:DyEu2iu
|
||||
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c=
|
||||
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ=
|
||||
github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag=
|
||||
github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg=
|
||||
github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag=
|
||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
||||
github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=
|
||||
@@ -317,8 +317,8 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG
|
||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
|
||||
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
|
||||
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||
@@ -428,8 +428,8 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
@@ -454,16 +454,16 @@ github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLe
|
||||
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg=
|
||||
github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b h1:RMpPgZTSApbPf7xaVel+QkoGPRLFLrwFO89uDUHEGf0=
|
||||
github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||
github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 h1:E/LAvt58di64hlYjx7AsNS6C/ysHWYo+2qPCZKTQhRo=
|
||||
github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
|
||||
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
|
||||
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
@@ -569,6 +569,8 @@ github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+
|
||||
github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk=
|
||||
github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk=
|
||||
github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
|
||||
github.com/jedib0t/go-pretty/v6 v6.5.4 h1:gOGo0613MoqUcf0xCj+h/V3sHDaZasfv152G6/5l91s=
|
||||
github.com/jedib0t/go-pretty/v6 v6.5.4/go.mod h1:5LQIxa52oJ/DlDSLv0HEkWOFMDGoWkJb9ss5KqPpJBg=
|
||||
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
|
||||
github.com/jhump/protoreflect v1.8.1/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
@@ -595,11 +597,11 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
|
||||
github.com/klauspost/compress v1.9.8/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.10.1/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
|
||||
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
||||
github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI=
|
||||
github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
||||
github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
||||
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/klauspost/reedsolomon v1.9.3/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
@@ -633,8 +635,8 @@ github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6
|
||||
github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg=
|
||||
github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM=
|
||||
github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro=
|
||||
github.com/libp2p/go-libp2p v0.32.1 h1:wy1J4kZIZxOaej6NveTWCZmHiJ/kY7GoAqXgqNCnPps=
|
||||
github.com/libp2p/go-libp2p v0.32.1/go.mod h1:hXXC3kXPlBZ1eu8Q2hptGrMB4mZ3048JUoS4EKaHW5c=
|
||||
github.com/libp2p/go-libp2p v0.33.1 h1:tvJl9b9M6nSLBtZSXSguq+/lRhRj2oLRkyhBmQNMFLA=
|
||||
github.com/libp2p/go-libp2p v0.33.1/go.mod h1:zOUTMjG4I7TXwMndNyOBn/CNtVBLlvBlnxfi+8xzx+E=
|
||||
github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94=
|
||||
github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8=
|
||||
github.com/libp2p/go-libp2p-mplex v0.9.0 h1:R58pDRAmuBXkYugbSSXR9wrTX3+1pFM1xP2bLuodIq8=
|
||||
@@ -699,15 +701,13 @@ github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
|
||||
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
||||
github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE=
|
||||
github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY=
|
||||
github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4=
|
||||
github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY=
|
||||
github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8=
|
||||
github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms=
|
||||
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc=
|
||||
@@ -758,8 +758,8 @@ github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9
|
||||
github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4=
|
||||
github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo=
|
||||
github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4=
|
||||
github.com/multiformats/go-multiaddr v0.12.1 h1:vm+BA/WZA8QZDp1pF1FWhi5CT3g1tbi5GJmqpb6wnlk=
|
||||
github.com/multiformats/go-multiaddr v0.12.1/go.mod h1:7mPkiBMmLeFipt+nNSq9pHZUeJSt8lHBgH6yhj0YQzE=
|
||||
github.com/multiformats/go-multiaddr v0.12.2 h1:9G9sTY/wCYajKa9lyfWPmpZAwe6oV+Wb1zcmMS1HG24=
|
||||
github.com/multiformats/go-multiaddr v0.12.2/go.mod h1:GKyaTYjZRdcUhyOetrxTk9z0cW+jA/YrnqTOvKgi44M=
|
||||
github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A=
|
||||
github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk=
|
||||
github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E=
|
||||
@@ -808,21 +808,21 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108
|
||||
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4=
|
||||
github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o=
|
||||
github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY=
|
||||
github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM=
|
||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
|
||||
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
|
||||
github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
|
||||
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||
github.com/openconfig/gnmi v0.0.0-20190823184014-89b2bf29312c/go.mod h1:t+O9It+LKzfOAhKTT5O0ehDix+MTqbtT0T9t+7zzOvc=
|
||||
github.com/openconfig/reference v0.0.0-20190727015836-8dfd928c9696/go.mod h1:ym2A+zigScwkSEb/cVQB0/ZMpU3rqiH6X7WRRsxgOGw=
|
||||
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg=
|
||||
github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk=
|
||||
github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
|
||||
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
|
||||
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
@@ -885,16 +885,16 @@ github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeD
|
||||
github.com/prometheus/client_golang v1.4.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
|
||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
github.com/prometheus/client_golang v1.9.0/go.mod h1:FqZLKOZnGdFAhOK4nqGHa7D66IdsO+O441Eve7ptJDU=
|
||||
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
|
||||
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
|
||||
github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=
|
||||
github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
|
||||
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
|
||||
github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos=
|
||||
github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8=
|
||||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
@@ -904,8 +904,8 @@ github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt2
|
||||
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
|
||||
github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM=
|
||||
github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
|
||||
github.com/prometheus/common v0.47.0 h1:p5Cz0FNHo7SnWOmWmoRozVcjEp0bIVU8cV7OShpjL1k=
|
||||
github.com/prometheus/common v0.47.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
|
||||
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
@@ -935,10 +935,8 @@ github.com/prysmaticlabs/protoc-gen-go-cast v0.0.0-20230228205207-28762a7b9294 h
|
||||
github.com/prysmaticlabs/protoc-gen-go-cast v0.0.0-20230228205207-28762a7b9294/go.mod h1:ZVEbRdnMkGhp/pu35zq4SXxtvUwWK0J1MATtekZpH2Y=
|
||||
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
|
||||
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
|
||||
github.com/quic-go/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg=
|
||||
github.com/quic-go/qtls-go1-20 v0.3.4/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
|
||||
github.com/quic-go/quic-go v0.39.4 h1:PelfiuG7wXEffUT2yceiqz5V6Pc0TA5ruOd1LcmFc1s=
|
||||
github.com/quic-go/quic-go v0.39.4/go.mod h1:T09QsDQWjLiQ74ZmacDfqZmhY/NLnw5BC40MANNNZ1Q=
|
||||
github.com/quic-go/quic-go v0.42.0 h1:uSfdap0eveIl8KXnipv9K7nlwZ5IqLlYOpJ58u5utpM=
|
||||
github.com/quic-go/quic-go v0.42.0/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M=
|
||||
github.com/quic-go/webtransport-go v0.6.0 h1:CvNsKqc4W2HljHJnoT+rMmbRJybShZ0YPFDD3NxaZLY=
|
||||
github.com/quic-go/webtransport-go v0.6.0/go.mod h1:9KjU4AEBqEQidGHNDkZrb8CAa1abRaosM2yGOyiikEc=
|
||||
github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk=
|
||||
@@ -1146,10 +1144,10 @@ go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE=
|
||||
go.uber.org/fx v1.20.1 h1:zVwVQGS8zYvhh9Xxcu4w1M6ESyeMzebzj2NbSayZ4Mk=
|
||||
go.uber.org/fx v1.20.1/go.mod h1:iSYNbHf2y55acNCwCXKx7LbWb5WG1Bnue5RDXz1OREg=
|
||||
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
|
||||
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
|
||||
go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo=
|
||||
go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
|
||||
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||
@@ -1161,8 +1159,8 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
|
||||
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
|
||||
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
|
||||
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
|
||||
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
@@ -1187,8 +1185,8 @@ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -1200,8 +1198,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
|
||||
golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611 h1:qCEDpW1G+vcj3Y7Fy52pEM1AWm3abj8WimGYejI3SC4=
|
||||
golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
|
||||
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a h1:HinSgX1tJRX3KsL//Gxynpw5CTOAIPhgL4W8PNiIpVE=
|
||||
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
|
||||
golang.org/x/exp/typeparams v0.0.0-20231108232855-2478ac86f678 h1:1P7xPZEwZMoBoz0Yze5Nx2/4pxj6nw9ZqHWXqP0iRgQ=
|
||||
golang.org/x/exp/typeparams v0.0.0-20231108232855-2478ac86f678/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
@@ -1230,8 +1228,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
|
||||
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
|
||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -1284,8 +1282,8 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
||||
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/oauth2 v0.0.0-20170912212905-13449ad91cb2/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
@@ -1302,8 +1300,8 @@ golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ
|
||||
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4=
|
||||
golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4=
|
||||
golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ=
|
||||
golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o=
|
||||
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
|
||||
golang.org/x/sync v0.0.0-20170517211232-f52d1811a629/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -1318,8 +1316,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
|
||||
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -1412,13 +1410,13 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
|
||||
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
|
||||
golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -1439,8 +1437,8 @@ golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxb
|
||||
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
@@ -1508,8 +1506,8 @@ golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0t
|
||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM=
|
||||
golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
|
||||
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
|
||||
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -1651,8 +1649,8 @@ google.golang.org/protobuf v1.25.1-0.20200805231151-a709e31e5d12/go.mod h1:9JNX7
|
||||
google.golang.org/protobuf v1.25.1-0.20201208041424-160c7477e0e8/go.mod h1:hFxJC2f0epmp1elRCiEGJTKAWbwxZ2nvqZdHl3FQXCY=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
|
||||
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/bsm/ratelimit.v1 v1.0.0-20160220154919-db14e161995a/go.mod h1:KF9sEfUPAXdG8Oev9e99iLGnl2uJMjc5B+4y3O7x610=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
78
hack/spectest-report.sh
Executable file
78
hack/spectest-report.sh
Executable file
@@ -0,0 +1,78 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -xe
|
||||
|
||||
# Constants
|
||||
PROJECT_ROOT=$(pwd)
|
||||
PRYSM_DIR="${PROJECT_ROOT%/hack}/testing/spectest"
|
||||
EXCLUSION_LIST="$PRYSM_DIR/exclusions.txt"
|
||||
BAZEL_DIR="/tmp/spectest_report"
|
||||
SPEC_REPO="git@github.com:ethereum/consensus-spec-tests.git"
|
||||
SPEC_DIR="/tmp/consensus-spec"
|
||||
|
||||
# Create directory if it doesn't already exist
|
||||
mkdir -p "$BAZEL_DIR"
|
||||
|
||||
# Add any passed flags to BAZEL_FLAGS
|
||||
BAZEL_FLAGS=""
|
||||
for flag in "$@"
|
||||
do
|
||||
BAZEL_FLAGS="$BAZEL_FLAGS $flag"
|
||||
done
|
||||
|
||||
# Run spectests
|
||||
bazel test //testing/spectest/... --test_env=SPEC_TEST_REPORT_OUTPUT_DIR="$BAZEL_DIR" $BAZEL_FLAGS
|
||||
|
||||
# Ensure the SPEC_DIR exists and is a git repository
|
||||
if [ -d "$SPEC_DIR/.git" ]; then
|
||||
echo "Repository already exists. Pulling latest changes."
|
||||
(cd "$SPEC_DIR" && git pull) || exit 1
|
||||
else
|
||||
echo "Cloning the GitHub repository."
|
||||
git clone "$SPEC_REPO" "$SPEC_DIR" || exit 1
|
||||
fi
|
||||
|
||||
# Finding all *_tests.txt files in BAZEL_DIR and concatenating them into tests.txt
|
||||
find "$BAZEL_DIR" -type f -name '*_tests.txt' -exec cat {} + > "$PRYSM_DIR/tests.txt"
|
||||
|
||||
# Generating spec.txt
|
||||
(cd "$SPEC_DIR" && find tests -maxdepth 4 -mindepth 4 -type d > "$PRYSM_DIR/spec.txt") || exit 1
|
||||
|
||||
# Comparing spec.txt with tests.txt and generating report.txt
|
||||
while IFS= read -r line; do
|
||||
if grep -Fxq "$line" "$EXCLUSION_LIST"; then
|
||||
# If it's excluded and we have a test for it flag as an error
|
||||
if grep -q "$line" "$PRYSM_DIR/tests.txt"; then
|
||||
echo "Error: Excluded item found in tests.txt: $line"
|
||||
exit 1 # Exit with an error status
|
||||
else
|
||||
echo "Skipping excluded item: $line"
|
||||
fi
|
||||
continue
|
||||
fi
|
||||
if grep -q "$line" "$PRYSM_DIR/tests.txt"; then
|
||||
echo "found $line"
|
||||
else
|
||||
echo "missing $line"
|
||||
fi
|
||||
done < "$PRYSM_DIR/spec.txt" > "$PRYSM_DIR/report.txt"
|
||||
|
||||
# Formatting report.txt
|
||||
{
|
||||
echo "Prysm Spectest Report"
|
||||
echo ""
|
||||
echo "Tests Missing"
|
||||
grep '^missing' "$PRYSM_DIR/report.txt"
|
||||
echo ""
|
||||
echo "Tests Found"
|
||||
grep '^found' "$PRYSM_DIR/report.txt"
|
||||
} > "$PRYSM_DIR/report_temp.txt" && mv "$PRYSM_DIR/report_temp.txt" "$PRYSM_DIR/report.txt"
|
||||
|
||||
# Check for the word "missing" in the report and exit with an error if present
|
||||
if grep -q '^missing' "$PRYSM_DIR/report.txt"; then
|
||||
echo "Error: 'missing' tests found in report: $PRYSM_DIR/report.txt"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Clean up
|
||||
rm -f "$PRYSM_DIR/tests.txt" "$PRYSM_DIR/spec.txt"
|
||||
296
testing/spectest/exclusions.txt
Normal file
296
testing/spectest/exclusions.txt
Normal file
@@ -0,0 +1,296 @@
|
||||
# LightClient
|
||||
tests/mainnet/altair/light_client/single_merkle_proof
|
||||
tests/mainnet/bellatrix/light_client/single_merkle_proof
|
||||
tests/mainnet/capella/light_client/single_merkle_proof
|
||||
tests/mainnet/deneb/light_client/single_merkle_proof
|
||||
tests/minimal/altair/light_client/single_merkle_proof
|
||||
tests/minimal/altair/light_client/sync
|
||||
tests/minimal/altair/light_client/update_ranking
|
||||
tests/minimal/bellatrix/light_client/single_merkle_proof
|
||||
tests/minimal/bellatrix/light_client/sync
|
||||
tests/minimal/bellatrix/light_client/update_ranking
|
||||
tests/minimal/capella/light_client/single_merkle_proof
|
||||
tests/minimal/capella/light_client/sync
|
||||
tests/minimal/capella/light_client/update_ranking
|
||||
tests/minimal/deneb/light_client/single_merkle_proof
|
||||
tests/minimal/deneb/light_client/sync
|
||||
tests/minimal/deneb/light_client/update_ranking
|
||||
|
||||
# SSZ Generic
|
||||
tests/general/phase0/ssz_generic/basic_vector
|
||||
tests/general/phase0/ssz_generic/bitlist
|
||||
tests/general/phase0/ssz_generic/bitvector
|
||||
tests/general/phase0/ssz_generic/boolean
|
||||
tests/general/phase0/ssz_generic/containers
|
||||
tests/general/phase0/ssz_generic/uints
|
||||
|
||||
# EIP6110
|
||||
tests/mainnet/eip6110/epoch_processing/effective_balance_updates
|
||||
tests/mainnet/eip6110/epoch_processing/eth1_data_reset
|
||||
tests/mainnet/eip6110/epoch_processing/historical_summaries_update
|
||||
tests/mainnet/eip6110/epoch_processing/inactivity_updates
|
||||
tests/mainnet/eip6110/epoch_processing/justification_and_finalization
|
||||
tests/mainnet/eip6110/epoch_processing/participation_flag_updates
|
||||
tests/mainnet/eip6110/epoch_processing/randao_mixes_reset
|
||||
tests/mainnet/eip6110/epoch_processing/registry_updates
|
||||
tests/mainnet/eip6110/epoch_processing/rewards_and_penalties
|
||||
tests/mainnet/eip6110/epoch_processing/slashings
|
||||
tests/mainnet/eip6110/epoch_processing/slashings_reset
|
||||
tests/mainnet/eip6110/finality/finality
|
||||
tests/mainnet/eip6110/fork_choice/ex_ante
|
||||
tests/mainnet/eip6110/fork_choice/get_head
|
||||
tests/mainnet/eip6110/fork_choice/get_proposer_head
|
||||
tests/mainnet/eip6110/fork_choice/on_block
|
||||
tests/mainnet/eip6110/fork_choice/should_override_forkchoice_update
|
||||
tests/mainnet/eip6110/operations/attestation
|
||||
tests/mainnet/eip6110/operations/attester_slashing
|
||||
tests/mainnet/eip6110/operations/block_header
|
||||
tests/mainnet/eip6110/operations/bls_to_execution_change
|
||||
tests/mainnet/eip6110/operations/deposit
|
||||
tests/mainnet/eip6110/operations/deposit_receipt
|
||||
tests/mainnet/eip6110/operations/execution_payload
|
||||
tests/mainnet/eip6110/operations/proposer_slashing
|
||||
tests/mainnet/eip6110/operations/sync_aggregate
|
||||
tests/mainnet/eip6110/operations/voluntary_exit
|
||||
tests/mainnet/eip6110/operations/withdrawals
|
||||
tests/mainnet/eip6110/rewards/basic
|
||||
tests/mainnet/eip6110/rewards/leak
|
||||
tests/mainnet/eip6110/rewards/random
|
||||
tests/mainnet/eip6110/sanity/blocks
|
||||
tests/mainnet/eip6110/sanity/slots
|
||||
tests/mainnet/eip6110/ssz_static/AggregateAndProof
|
||||
tests/mainnet/eip6110/ssz_static/Attestation
|
||||
tests/mainnet/eip6110/ssz_static/AttestationData
|
||||
tests/mainnet/eip6110/ssz_static/AttesterSlashing
|
||||
tests/mainnet/eip6110/ssz_static/BLSToExecutionChange
|
||||
tests/mainnet/eip6110/ssz_static/BeaconBlock
|
||||
tests/mainnet/eip6110/ssz_static/BeaconBlockBody
|
||||
tests/mainnet/eip6110/ssz_static/BeaconBlockHeader
|
||||
tests/mainnet/eip6110/ssz_static/BeaconState
|
||||
tests/mainnet/eip6110/ssz_static/BlobIdentifier
|
||||
tests/mainnet/eip6110/ssz_static/BlobSidecar
|
||||
tests/mainnet/eip6110/ssz_static/Checkpoint
|
||||
tests/mainnet/eip6110/ssz_static/ContributionAndProof
|
||||
tests/mainnet/eip6110/ssz_static/Deposit
|
||||
tests/mainnet/eip6110/ssz_static/DepositData
|
||||
tests/mainnet/eip6110/ssz_static/DepositMessage
|
||||
tests/mainnet/eip6110/ssz_static/DepositReceipt
|
||||
tests/mainnet/eip6110/ssz_static/Eth1Block
|
||||
tests/mainnet/eip6110/ssz_static/Eth1Data
|
||||
tests/mainnet/eip6110/ssz_static/ExecutionPayload
|
||||
tests/mainnet/eip6110/ssz_static/ExecutionPayloadHeader
|
||||
tests/mainnet/eip6110/ssz_static/Fork
|
||||
tests/mainnet/eip6110/ssz_static/ForkData
|
||||
tests/mainnet/eip6110/ssz_static/HistoricalBatch
|
||||
tests/mainnet/eip6110/ssz_static/HistoricalSummary
|
||||
tests/mainnet/eip6110/ssz_static/IndexedAttestation
|
||||
tests/mainnet/eip6110/ssz_static/LightClientBootstrap
|
||||
tests/mainnet/eip6110/ssz_static/LightClientFinalityUpdate
|
||||
tests/mainnet/eip6110/ssz_static/LightClientHeader
|
||||
tests/mainnet/eip6110/ssz_static/LightClientOptimisticUpdate
|
||||
tests/mainnet/eip6110/ssz_static/LightClientUpdate
|
||||
tests/mainnet/eip6110/ssz_static/PendingAttestation
|
||||
tests/mainnet/eip6110/ssz_static/PowBlock
|
||||
tests/mainnet/eip6110/ssz_static/ProposerSlashing
|
||||
tests/mainnet/eip6110/ssz_static/SignedAggregateAndProof
|
||||
tests/mainnet/eip6110/ssz_static/SignedBLSToExecutionChange
|
||||
tests/mainnet/eip6110/ssz_static/SignedBeaconBlock
|
||||
tests/mainnet/eip6110/ssz_static/SignedBeaconBlockHeader
|
||||
tests/mainnet/eip6110/ssz_static/SignedContributionAndProof
|
||||
tests/mainnet/eip6110/ssz_static/SignedVoluntaryExit
|
||||
tests/mainnet/eip6110/ssz_static/SigningData
|
||||
tests/mainnet/eip6110/ssz_static/SyncAggregate
|
||||
tests/mainnet/eip6110/ssz_static/SyncAggregatorSelectionData
|
||||
tests/mainnet/eip6110/ssz_static/SyncCommittee
|
||||
tests/mainnet/eip6110/ssz_static/SyncCommitteeContribution
|
||||
tests/mainnet/eip6110/ssz_static/SyncCommitteeMessage
|
||||
tests/mainnet/eip6110/ssz_static/Validator
|
||||
tests/mainnet/eip6110/ssz_static/VoluntaryExit
|
||||
tests/mainnet/eip6110/ssz_static/Withdrawal
|
||||
tests/mainnet/eip6110/sync/optimistic
|
||||
tests/mainnet/eip6110/transition/core
|
||||
tests/minimal/eip6110/epoch_processing/effective_balance_updates
|
||||
tests/minimal/eip6110/epoch_processing/eth1_data_reset
|
||||
tests/minimal/eip6110/epoch_processing/historical_summaries_update
|
||||
tests/minimal/eip6110/epoch_processing/inactivity_updates
|
||||
tests/minimal/eip6110/epoch_processing/justification_and_finalization
|
||||
tests/minimal/eip6110/epoch_processing/participation_flag_updates
|
||||
tests/minimal/eip6110/epoch_processing/randao_mixes_reset
|
||||
tests/minimal/eip6110/epoch_processing/registry_updates
|
||||
tests/minimal/eip6110/epoch_processing/rewards_and_penalties
|
||||
tests/minimal/eip6110/epoch_processing/slashings
|
||||
tests/minimal/eip6110/epoch_processing/slashings_reset
|
||||
tests/minimal/eip6110/epoch_processing/sync_committee_updates
|
||||
tests/minimal/eip6110/finality/finality
|
||||
tests/minimal/eip6110/fork_choice/ex_ante
|
||||
tests/minimal/eip6110/fork_choice/get_head
|
||||
tests/minimal/eip6110/fork_choice/get_proposer_head
|
||||
tests/minimal/eip6110/fork_choice/on_block
|
||||
tests/minimal/eip6110/fork_choice/reorg
|
||||
tests/minimal/eip6110/fork_choice/should_override_forkchoice_update
|
||||
tests/minimal/eip6110/fork_choice/withholding
|
||||
tests/minimal/eip6110/genesis/initialization
|
||||
tests/minimal/eip6110/genesis/validity
|
||||
tests/minimal/eip6110/operations/attestation
|
||||
tests/minimal/eip6110/operations/attester_slashing
|
||||
tests/minimal/eip6110/operations/block_header
|
||||
tests/minimal/eip6110/operations/bls_to_execution_change
|
||||
tests/minimal/eip6110/operations/deposit
|
||||
tests/minimal/eip6110/operations/deposit_receipt
|
||||
tests/minimal/eip6110/operations/execution_payload
|
||||
tests/minimal/eip6110/operations/proposer_slashing
|
||||
tests/minimal/eip6110/operations/sync_aggregate
|
||||
tests/minimal/eip6110/operations/voluntary_exit
|
||||
tests/minimal/eip6110/operations/withdrawals
|
||||
tests/minimal/eip6110/rewards/basic
|
||||
tests/minimal/eip6110/rewards/leak
|
||||
tests/minimal/eip6110/rewards/random
|
||||
tests/minimal/eip6110/sanity/blocks
|
||||
tests/minimal/eip6110/sanity/slots
|
||||
tests/minimal/eip6110/ssz_static/AggregateAndProof
|
||||
tests/minimal/eip6110/ssz_static/Attestation
|
||||
tests/minimal/eip6110/ssz_static/AttestationData
|
||||
tests/minimal/eip6110/ssz_static/AttesterSlashing
|
||||
tests/minimal/eip6110/ssz_static/BLSToExecutionChange
|
||||
tests/minimal/eip6110/ssz_static/BeaconBlock
|
||||
tests/minimal/eip6110/ssz_static/BeaconBlockBody
|
||||
tests/minimal/eip6110/ssz_static/BeaconBlockHeader
|
||||
tests/minimal/eip6110/ssz_static/BeaconState
|
||||
tests/minimal/eip6110/ssz_static/BlobIdentifier
|
||||
tests/minimal/eip6110/ssz_static/BlobSidecar
|
||||
tests/minimal/eip6110/ssz_static/Checkpoint
|
||||
tests/minimal/eip6110/ssz_static/ContributionAndProof
|
||||
tests/minimal/eip6110/ssz_static/Deposit
|
||||
tests/minimal/eip6110/ssz_static/DepositData
|
||||
tests/minimal/eip6110/ssz_static/DepositMessage
|
||||
tests/minimal/eip6110/ssz_static/DepositReceipt
|
||||
tests/minimal/eip6110/ssz_static/Eth1Block
|
||||
tests/minimal/eip6110/ssz_static/Eth1Data
|
||||
tests/minimal/eip6110/ssz_static/ExecutionPayload
|
||||
tests/minimal/eip6110/ssz_static/ExecutionPayloadHeader
|
||||
tests/minimal/eip6110/ssz_static/Fork
|
||||
tests/minimal/eip6110/ssz_static/ForkData
|
||||
tests/minimal/eip6110/ssz_static/HistoricalBatch
|
||||
tests/minimal/eip6110/ssz_static/HistoricalSummary
|
||||
tests/minimal/eip6110/ssz_static/IndexedAttestation
|
||||
tests/minimal/eip6110/ssz_static/LightClientBootstrap
|
||||
tests/minimal/eip6110/ssz_static/LightClientFinalityUpdate
|
||||
tests/minimal/eip6110/ssz_static/LightClientHeader
|
||||
tests/minimal/eip6110/ssz_static/LightClientOptimisticUpdate
|
||||
tests/minimal/eip6110/ssz_static/LightClientUpdate
|
||||
tests/minimal/eip6110/ssz_static/PendingAttestation
|
||||
tests/minimal/eip6110/ssz_static/PowBlock
|
||||
tests/minimal/eip6110/ssz_static/ProposerSlashing
|
||||
tests/minimal/eip6110/ssz_static/SignedAggregateAndProof
|
||||
tests/minimal/eip6110/ssz_static/SignedBLSToExecutionChange
|
||||
tests/minimal/eip6110/ssz_static/SignedBeaconBlock
|
||||
tests/minimal/eip6110/ssz_static/SignedBeaconBlockHeader
|
||||
tests/minimal/eip6110/ssz_static/SignedContributionAndProof
|
||||
tests/minimal/eip6110/ssz_static/SignedVoluntaryExit
|
||||
tests/minimal/eip6110/ssz_static/SigningData
|
||||
tests/minimal/eip6110/ssz_static/SyncAggregate
|
||||
tests/minimal/eip6110/ssz_static/SyncAggregatorSelectionData
|
||||
tests/minimal/eip6110/ssz_static/SyncCommittee
|
||||
tests/minimal/eip6110/ssz_static/SyncCommitteeContribution
|
||||
tests/minimal/eip6110/ssz_static/SyncCommitteeMessage
|
||||
tests/minimal/eip6110/ssz_static/Validator
|
||||
tests/minimal/eip6110/ssz_static/VoluntaryExit
|
||||
tests/minimal/eip6110/ssz_static/Withdrawal
|
||||
tests/minimal/eip6110/sync/optimistic
|
||||
tests/minimal/eip6110/transition/core
|
||||
|
||||
# Whisk
|
||||
tests/mainnet/whisk/ssz_static/AggregateAndProof
|
||||
tests/mainnet/whisk/ssz_static/Attestation
|
||||
tests/mainnet/whisk/ssz_static/AttestationData
|
||||
tests/mainnet/whisk/ssz_static/AttesterSlashing
|
||||
tests/mainnet/whisk/ssz_static/BLSToExecutionChange
|
||||
tests/mainnet/whisk/ssz_static/BeaconBlock
|
||||
tests/mainnet/whisk/ssz_static/BeaconBlockBody
|
||||
tests/mainnet/whisk/ssz_static/BeaconBlockHeader
|
||||
tests/mainnet/whisk/ssz_static/BeaconState
|
||||
tests/mainnet/whisk/ssz_static/Checkpoint
|
||||
tests/mainnet/whisk/ssz_static/ContributionAndProof
|
||||
tests/mainnet/whisk/ssz_static/Deposit
|
||||
tests/mainnet/whisk/ssz_static/DepositData
|
||||
tests/mainnet/whisk/ssz_static/DepositMessage
|
||||
tests/mainnet/whisk/ssz_static/Eth1Block
|
||||
tests/mainnet/whisk/ssz_static/Eth1Data
|
||||
tests/mainnet/whisk/ssz_static/ExecutionPayload
|
||||
tests/mainnet/whisk/ssz_static/ExecutionPayloadHeader
|
||||
tests/mainnet/whisk/ssz_static/Fork
|
||||
tests/mainnet/whisk/ssz_static/ForkData
|
||||
tests/mainnet/whisk/ssz_static/HistoricalBatch
|
||||
tests/mainnet/whisk/ssz_static/HistoricalSummary
|
||||
tests/mainnet/whisk/ssz_static/IndexedAttestation
|
||||
tests/mainnet/whisk/ssz_static/LightClientBootstrap
|
||||
tests/mainnet/whisk/ssz_static/LightClientFinalityUpdate
|
||||
tests/mainnet/whisk/ssz_static/LightClientHeader
|
||||
tests/mainnet/whisk/ssz_static/LightClientOptimisticUpdate
|
||||
tests/mainnet/whisk/ssz_static/LightClientUpdate
|
||||
tests/mainnet/whisk/ssz_static/PendingAttestation
|
||||
tests/mainnet/whisk/ssz_static/PowBlock
|
||||
tests/mainnet/whisk/ssz_static/ProposerSlashing
|
||||
tests/mainnet/whisk/ssz_static/SignedAggregateAndProof
|
||||
tests/mainnet/whisk/ssz_static/SignedBLSToExecutionChange
|
||||
tests/mainnet/whisk/ssz_static/SignedBeaconBlock
|
||||
tests/mainnet/whisk/ssz_static/SignedBeaconBlockHeader
|
||||
tests/mainnet/whisk/ssz_static/SignedContributionAndProof
|
||||
tests/mainnet/whisk/ssz_static/SignedVoluntaryExit
|
||||
tests/mainnet/whisk/ssz_static/SigningData
|
||||
tests/mainnet/whisk/ssz_static/SyncAggregate
|
||||
tests/mainnet/whisk/ssz_static/SyncAggregatorSelectionData
|
||||
tests/mainnet/whisk/ssz_static/SyncCommittee
|
||||
tests/mainnet/whisk/ssz_static/SyncCommitteeContribution
|
||||
tests/mainnet/whisk/ssz_static/SyncCommitteeMessage
|
||||
tests/mainnet/whisk/ssz_static/Validator
|
||||
tests/mainnet/whisk/ssz_static/VoluntaryExit
|
||||
tests/mainnet/whisk/ssz_static/WhiskTracker
|
||||
tests/mainnet/whisk/ssz_static/Withdrawal
|
||||
tests/minimal/whisk/ssz_static/AggregateAndProof
|
||||
tests/minimal/whisk/ssz_static/Attestation
|
||||
tests/minimal/whisk/ssz_static/AttestationData
|
||||
tests/minimal/whisk/ssz_static/AttesterSlashing
|
||||
tests/minimal/whisk/ssz_static/BLSToExecutionChange
|
||||
tests/minimal/whisk/ssz_static/BeaconBlock
|
||||
tests/minimal/whisk/ssz_static/BeaconBlockBody
|
||||
tests/minimal/whisk/ssz_static/BeaconBlockHeader
|
||||
tests/minimal/whisk/ssz_static/BeaconState
|
||||
tests/minimal/whisk/ssz_static/Checkpoint
|
||||
tests/minimal/whisk/ssz_static/ContributionAndProof
|
||||
tests/minimal/whisk/ssz_static/Deposit
|
||||
tests/minimal/whisk/ssz_static/DepositData
|
||||
tests/minimal/whisk/ssz_static/DepositMessage
|
||||
tests/minimal/whisk/ssz_static/Eth1Block
|
||||
tests/minimal/whisk/ssz_static/Eth1Data
|
||||
tests/minimal/whisk/ssz_static/ExecutionPayload
|
||||
tests/minimal/whisk/ssz_static/ExecutionPayloadHeader
|
||||
tests/minimal/whisk/ssz_static/Fork
|
||||
tests/minimal/whisk/ssz_static/ForkData
|
||||
tests/minimal/whisk/ssz_static/HistoricalBatch
|
||||
tests/minimal/whisk/ssz_static/HistoricalSummary
|
||||
tests/minimal/whisk/ssz_static/IndexedAttestation
|
||||
tests/minimal/whisk/ssz_static/LightClientBootstrap
|
||||
tests/minimal/whisk/ssz_static/LightClientFinalityUpdate
|
||||
tests/minimal/whisk/ssz_static/LightClientHeader
|
||||
tests/minimal/whisk/ssz_static/LightClientOptimisticUpdate
|
||||
tests/minimal/whisk/ssz_static/LightClientUpdate
|
||||
tests/minimal/whisk/ssz_static/PendingAttestation
|
||||
tests/minimal/whisk/ssz_static/PowBlock
|
||||
tests/minimal/whisk/ssz_static/ProposerSlashing
|
||||
tests/minimal/whisk/ssz_static/SignedAggregateAndProof
|
||||
tests/minimal/whisk/ssz_static/SignedBLSToExecutionChange
|
||||
tests/minimal/whisk/ssz_static/SignedBeaconBlock
|
||||
tests/minimal/whisk/ssz_static/SignedBeaconBlockHeader
|
||||
tests/minimal/whisk/ssz_static/SignedContributionAndProof
|
||||
tests/minimal/whisk/ssz_static/SignedVoluntaryExit
|
||||
tests/minimal/whisk/ssz_static/SigningData
|
||||
tests/minimal/whisk/ssz_static/SyncAggregate
|
||||
tests/minimal/whisk/ssz_static/SyncAggregatorSelectionData
|
||||
tests/minimal/whisk/ssz_static/SyncCommittee
|
||||
tests/minimal/whisk/ssz_static/SyncCommitteeContribution
|
||||
tests/minimal/whisk/ssz_static/SyncCommitteeMessage
|
||||
tests/minimal/whisk/ssz_static/Validator
|
||||
tests/minimal/whisk/ssz_static/VoluntaryExit
|
||||
tests/minimal/whisk/ssz_static/WhiskTracker
|
||||
tests/minimal/whisk/ssz_static/Withdrawal
|
||||
@@ -11,6 +11,7 @@ go_library(
|
||||
visibility = ["//testing/spectest:__subpackages__"],
|
||||
deps = [
|
||||
"//config/params:go_default_library",
|
||||
"//io/file:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
"@com_github_ghodss_yaml//:go_default_library",
|
||||
"@com_github_json_iterator_go//:go_default_library",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
@@ -8,6 +9,7 @@ import (
|
||||
"github.com/bazelbuild/rules_go/go/tools/bazel"
|
||||
"github.com/ghodss/yaml"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/prysmaticlabs/prysm/v5/io/file"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
)
|
||||
|
||||
@@ -42,6 +44,20 @@ func TestFolders(t testing.TB, config, forkOrPhase, folderPath string) ([]os.Dir
|
||||
if len(testFolders) == 0 {
|
||||
t.Fatalf("No test folders found at %s", testsFolderPath)
|
||||
}
|
||||
|
||||
err = saveSpecTest(testsFolderPath)
|
||||
require.NoError(t, err)
|
||||
return testFolders, testsFolderPath
|
||||
}
|
||||
|
||||
func saveSpecTest(testFolder string) error {
|
||||
baseDir := os.Getenv("SPEC_TEST_REPORT_OUTPUT_DIR")
|
||||
if baseDir == "" {
|
||||
return nil // Do nothing if spec test report not requested.
|
||||
}
|
||||
fullPath := path.Join(baseDir, fmt.Sprintf("%x_tests.txt", testFolder))
|
||||
err := file.WriteFile(fullPath, []byte(testFolder))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ func NewNodeClientWithFallback(jsonRestHandler JsonRestHandler, fallbackClient i
|
||||
b := &beaconApiNodeClient{
|
||||
jsonRestHandler: jsonRestHandler,
|
||||
fallbackClient: fallbackClient,
|
||||
genesisProvider: beaconApiGenesisProvider{jsonRestHandler: jsonRestHandler},
|
||||
genesisProvider: &beaconApiGenesisProvider{jsonRestHandler: jsonRestHandler},
|
||||
}
|
||||
b.healthTracker = beacon.NewNodeHealthTracker(b)
|
||||
return b
|
||||
|
||||
@@ -29,7 +29,7 @@ type beaconApiValidatorClient struct {
|
||||
|
||||
func NewBeaconApiValidatorClient(jsonRestHandler JsonRestHandler, opts ...ValidatorClientOpt) iface.ValidatorClient {
|
||||
c := &beaconApiValidatorClient{
|
||||
genesisProvider: beaconApiGenesisProvider{jsonRestHandler: jsonRestHandler},
|
||||
genesisProvider: &beaconApiGenesisProvider{jsonRestHandler: jsonRestHandler},
|
||||
dutiesProvider: beaconApiDutiesProvider{jsonRestHandler: jsonRestHandler},
|
||||
stateValidatorsProvider: beaconApiStateValidatorsProvider{jsonRestHandler: jsonRestHandler},
|
||||
jsonRestHandler: jsonRestHandler,
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
@@ -19,6 +20,8 @@ type GenesisProvider interface {
|
||||
|
||||
type beaconApiGenesisProvider struct {
|
||||
jsonRestHandler JsonRestHandler
|
||||
genesis *structs.Genesis
|
||||
once sync.Once
|
||||
}
|
||||
|
||||
func (c beaconApiValidatorClient) waitForChainStart(ctx context.Context) (*ethpb.ChainStartResponse, error) {
|
||||
@@ -64,15 +67,23 @@ func (c beaconApiValidatorClient) waitForChainStart(ctx context.Context) (*ethpb
|
||||
}
|
||||
|
||||
// GetGenesis gets the genesis information from the beacon node via the /eth/v1/beacon/genesis endpoint
|
||||
func (c beaconApiGenesisProvider) GetGenesis(ctx context.Context) (*structs.Genesis, error) {
|
||||
func (c *beaconApiGenesisProvider) GetGenesis(ctx context.Context) (*structs.Genesis, error) {
|
||||
genesisJson := &structs.GetGenesisResponse{}
|
||||
if err := c.jsonRestHandler.Get(ctx, "/eth/v1/beacon/genesis", genesisJson); err != nil {
|
||||
return nil, err
|
||||
var doErr error
|
||||
c.once.Do(func() {
|
||||
if err := c.jsonRestHandler.Get(ctx, "/eth/v1/beacon/genesis", genesisJson); err != nil {
|
||||
doErr = err
|
||||
return
|
||||
}
|
||||
if genesisJson.Data == nil {
|
||||
doErr = errors.New("genesis data is nil")
|
||||
return
|
||||
}
|
||||
c.genesis = genesisJson.Data
|
||||
})
|
||||
if doErr != nil {
|
||||
// Allow another call because the current one returned an error
|
||||
c.once = sync.Once{}
|
||||
}
|
||||
|
||||
if genesisJson.Data == nil {
|
||||
return nil, errors.New("genesis data is nil")
|
||||
}
|
||||
|
||||
return genesisJson.Data, nil
|
||||
return c.genesis, doErr
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v5/api/server/structs"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
@@ -66,3 +67,78 @@ func TestGetGenesis_NilData(t *testing.T) {
|
||||
_, err := genesisProvider.GetGenesis(ctx)
|
||||
assert.ErrorContains(t, "genesis data is nil", err)
|
||||
}
|
||||
|
||||
func TestGetGenesis_EndpointCalledOnlyOnce(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
genesisResponseJson := structs.GetGenesisResponse{}
|
||||
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
|
||||
jsonRestHandler.EXPECT().Get(
|
||||
ctx,
|
||||
"/eth/v1/beacon/genesis",
|
||||
&genesisResponseJson,
|
||||
).Return(
|
||||
nil,
|
||||
).SetArg(
|
||||
2,
|
||||
structs.GetGenesisResponse{
|
||||
Data: &structs.Genesis{
|
||||
GenesisTime: "1234",
|
||||
GenesisValidatorsRoot: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2",
|
||||
},
|
||||
},
|
||||
).Times(1)
|
||||
|
||||
genesisProvider := &beaconApiGenesisProvider{jsonRestHandler: jsonRestHandler}
|
||||
_, err := genesisProvider.GetGenesis(ctx)
|
||||
assert.NoError(t, err)
|
||||
resp, err := genesisProvider.GetGenesis(ctx)
|
||||
assert.NoError(t, err)
|
||||
require.NotNil(t, resp)
|
||||
assert.Equal(t, "1234", resp.GenesisTime)
|
||||
assert.Equal(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", resp.GenesisValidatorsRoot)
|
||||
}
|
||||
|
||||
func TestGetGenesis_EndpointCanBeCalledAgainAfterError(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
genesisResponseJson := structs.GetGenesisResponse{}
|
||||
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
|
||||
jsonRestHandler.EXPECT().Get(
|
||||
ctx,
|
||||
"/eth/v1/beacon/genesis",
|
||||
&genesisResponseJson,
|
||||
).Return(
|
||||
errors.New("foo"),
|
||||
).Times(1)
|
||||
jsonRestHandler.EXPECT().Get(
|
||||
ctx,
|
||||
"/eth/v1/beacon/genesis",
|
||||
&genesisResponseJson,
|
||||
).Return(
|
||||
nil,
|
||||
).SetArg(
|
||||
2,
|
||||
structs.GetGenesisResponse{
|
||||
Data: &structs.Genesis{
|
||||
GenesisTime: "1234",
|
||||
GenesisValidatorsRoot: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2",
|
||||
},
|
||||
},
|
||||
).Times(1)
|
||||
|
||||
genesisProvider := &beaconApiGenesisProvider{jsonRestHandler: jsonRestHandler}
|
||||
_, err := genesisProvider.GetGenesis(ctx)
|
||||
require.ErrorContains(t, "foo", err)
|
||||
resp, err := genesisProvider.GetGenesis(ctx)
|
||||
assert.NoError(t, err)
|
||||
require.NotNil(t, resp)
|
||||
assert.Equal(t, "1234", resp.GenesisTime)
|
||||
assert.Equal(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", resp.GenesisValidatorsRoot)
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ func TestWaitForChainStart_ValidGenesis(t *testing.T) {
|
||||
).Times(1)
|
||||
|
||||
genesisProvider := beaconApiGenesisProvider{jsonRestHandler: jsonRestHandler}
|
||||
validatorClient := beaconApiValidatorClient{genesisProvider: genesisProvider}
|
||||
validatorClient := beaconApiValidatorClient{genesisProvider: &genesisProvider}
|
||||
resp, err := validatorClient.WaitForChainStart(ctx, &emptypb.Empty{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
@@ -104,7 +104,7 @@ func TestWaitForChainStart_BadGenesis(t *testing.T) {
|
||||
).Times(1)
|
||||
|
||||
genesisProvider := beaconApiGenesisProvider{jsonRestHandler: jsonRestHandler}
|
||||
validatorClient := beaconApiValidatorClient{genesisProvider: genesisProvider}
|
||||
validatorClient := beaconApiValidatorClient{genesisProvider: &genesisProvider}
|
||||
_, err := validatorClient.WaitForChainStart(ctx, &emptypb.Empty{})
|
||||
assert.ErrorContains(t, testCase.errorMessage, err)
|
||||
})
|
||||
@@ -127,7 +127,7 @@ func TestWaitForChainStart_JsonResponseError(t *testing.T) {
|
||||
).Times(1)
|
||||
|
||||
genesisProvider := beaconApiGenesisProvider{jsonRestHandler: jsonRestHandler}
|
||||
validatorClient := beaconApiValidatorClient{genesisProvider: genesisProvider}
|
||||
validatorClient := beaconApiValidatorClient{genesisProvider: &genesisProvider}
|
||||
_, err := validatorClient.WaitForChainStart(ctx, &emptypb.Empty{})
|
||||
assert.ErrorContains(t, "failed to get genesis data", err)
|
||||
assert.ErrorContains(t, "some specific json error", err)
|
||||
@@ -172,7 +172,7 @@ func TestWaitForChainStart_JsonResponseError404(t *testing.T) {
|
||||
).Times(1)
|
||||
|
||||
genesisProvider := beaconApiGenesisProvider{jsonRestHandler: jsonRestHandler}
|
||||
validatorClient := beaconApiValidatorClient{genesisProvider: genesisProvider}
|
||||
validatorClient := beaconApiValidatorClient{genesisProvider: &genesisProvider}
|
||||
resp, err := validatorClient.WaitForChainStart(ctx, &emptypb.Empty{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
// CreateWallet via an API request, allowing a user to save a new
|
||||
// CreateWallet via an API request, allowing a user to save a new wallet.
|
||||
func (s *Server) CreateWallet(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, span := trace.StartSpan(r.Context(), "validator.web.CreateWallet")
|
||||
defer span.End()
|
||||
|
||||
Reference in New Issue
Block a user