mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-02-01 08:35:24 -05:00
Compare commits
22 Commits
e2e-debugg
...
hackSync
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79657b158c | ||
|
|
2c6e028600 | ||
|
|
a9dc6a1dbb | ||
|
|
713fd33eb5 | ||
|
|
5f56507bee | ||
|
|
07f0d5ee72 | ||
|
|
23bbf2380f | ||
|
|
9e96de033b | ||
|
|
fd41691178 | ||
|
|
5916c6e625 | ||
|
|
0312cb223a | ||
|
|
68cf7a59f2 | ||
|
|
537ddb1a24 | ||
|
|
7afaa6994b | ||
|
|
defb3ab87b | ||
|
|
81dce25c98 | ||
|
|
5c409b90bc | ||
|
|
aa47661602 | ||
|
|
7259a2b983 | ||
|
|
e9f511ac00 | ||
|
|
34a68715b8 | ||
|
|
c33e0575ab |
@@ -12,6 +12,7 @@ go_library(
|
|||||||
"forkchoice_update_execution.go",
|
"forkchoice_update_execution.go",
|
||||||
"head.go",
|
"head.go",
|
||||||
"head_sync_committee_info.go",
|
"head_sync_committee_info.go",
|
||||||
|
"holeskyhack.go",
|
||||||
"init_sync_process_block.go",
|
"init_sync_process_block.go",
|
||||||
"log.go",
|
"log.go",
|
||||||
"merge_ascii_art.go",
|
"merge_ascii_art.go",
|
||||||
|
|||||||
21
beacon-chain/blockchain/holeskyhack.go
Normal file
21
beacon-chain/blockchain/holeskyhack.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package blockchain
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
var errHoleskyForbiddenRoot = errors.New("refusing to process forbidden holesky block")
|
||||||
|
|
||||||
|
// hack to prevent bad holesky block importation
|
||||||
|
var badHoleskyRoot [32]byte
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
hexStr := "2db899881ed8546476d0b92c6aa9110bea9a4cd0dbeb5519eb0ea69575f1f359"
|
||||||
|
bytes, err := hex.DecodeString(hexStr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
badHoleskyRoot = [32]byte(bytes)
|
||||||
|
}
|
||||||
@@ -173,6 +173,9 @@ func (s *Service) onBlockBatch(ctx context.Context, blks []consensusblocks.ROBlo
|
|||||||
var set *bls.SignatureBatch
|
var set *bls.SignatureBatch
|
||||||
boundaries := make(map[[32]byte]state.BeaconState)
|
boundaries := make(map[[32]byte]state.BeaconState)
|
||||||
for i, b := range blks {
|
for i, b := range blks {
|
||||||
|
if b.Root() == badHoleskyRoot {
|
||||||
|
return errHoleskyForbiddenRoot
|
||||||
|
}
|
||||||
v, h, err := getStateVersionAndPayload(preState)
|
v, h, err := getStateVersionAndPayload(preState)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -64,6 +64,11 @@ type SlashingReceiver interface {
|
|||||||
func (s *Service) ReceiveBlock(ctx context.Context, block interfaces.ReadOnlySignedBeaconBlock, blockRoot [32]byte, avs das.AvailabilityStore) error {
|
func (s *Service) ReceiveBlock(ctx context.Context, block interfaces.ReadOnlySignedBeaconBlock, blockRoot [32]byte, avs das.AvailabilityStore) error {
|
||||||
ctx, span := trace.StartSpan(ctx, "blockChain.ReceiveBlock")
|
ctx, span := trace.StartSpan(ctx, "blockChain.ReceiveBlock")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
|
if blockRoot == badHoleskyRoot {
|
||||||
|
return errHoleskyForbiddenRoot
|
||||||
|
}
|
||||||
|
|
||||||
// Return early if the block has been synced
|
// Return early if the block has been synced
|
||||||
if s.InForkchoice(blockRoot) {
|
if s.InForkchoice(blockRoot) {
|
||||||
log.WithField("blockRoot", fmt.Sprintf("%#x", blockRoot)).Debug("Ignoring already synced block")
|
log.WithField("blockRoot", fmt.Sprintf("%#x", blockRoot)).Debug("Ignoring already synced block")
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import (
|
|||||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||||
prysmTime "github.com/prysmaticlabs/prysm/v5/time"
|
prysmTime "github.com/prysmaticlabs/prysm/v5/time"
|
||||||
"github.com/prysmaticlabs/prysm/v5/time/slots"
|
"github.com/prysmaticlabs/prysm/v5/time/slots"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Service represents a service that handles the internal
|
// Service represents a service that handles the internal
|
||||||
@@ -316,33 +317,40 @@ func (s *Service) originRootFromSavedState(ctx context.Context) ([32]byte, error
|
|||||||
return genesisBlkRoot, nil
|
return genesisBlkRoot, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// initializeHeadFromDB uses the finalized checkpoint and head block found in the database to set the current head.
|
// initializeHeadFromDB uses the finalized checkpoint and head block root from forkchoice to set the current head.
|
||||||
// Note that this may block until stategen replays blocks between the finalized and head blocks
|
// Note that this may block until stategen replays blocks between the finalized and head blocks
|
||||||
// if the head sync flag was specified and the gap between the finalized and head blocks is at least 128 epochs long.
|
// if the head sync flag was specified and the gap between the finalized and head blocks is at least 128 epochs long.
|
||||||
func (s *Service) initializeHeadFromDB(ctx context.Context, finalizedState state.BeaconState) error {
|
func (s *Service) initializeHead(ctx context.Context, st state.BeaconState) error {
|
||||||
cp := s.FinalizedCheckpt()
|
cp := s.FinalizedCheckpt()
|
||||||
fRoot := [32]byte(cp.Root)
|
fRoot := s.ensureRootNotZeros([32]byte(cp.Root))
|
||||||
finalizedRoot := s.ensureRootNotZeros(fRoot)
|
if st == nil || st.IsNil() {
|
||||||
|
|
||||||
if finalizedState == nil || finalizedState.IsNil() {
|
|
||||||
return errors.New("finalized state can't be nil")
|
return errors.New("finalized state can't be nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
finalizedBlock, err := s.getBlock(ctx, finalizedRoot)
|
s.cfg.ForkChoiceStore.RLock()
|
||||||
|
root := s.cfg.ForkChoiceStore.HighestReceivedBlockRoot()
|
||||||
|
s.cfg.ForkChoiceStore.RUnlock()
|
||||||
|
blk, err := s.cfg.BeaconDB.Block(ctx, root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "could not get finalized block")
|
return errors.Wrap(err, "could not get head block")
|
||||||
}
|
}
|
||||||
if err := s.setHead(&head{
|
if root != fRoot {
|
||||||
finalizedRoot,
|
st, err = s.cfg.StateGen.StateByRoot(ctx, root)
|
||||||
finalizedBlock,
|
if err != nil {
|
||||||
finalizedState,
|
return errors.Wrap(err, "could not get head state")
|
||||||
finalizedBlock.Block().Slot(),
|
}
|
||||||
|
}
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"root": fmt.Sprintf("%#x", root),
|
||||||
|
"slot": blk.Block().Slot(),
|
||||||
|
}).Info("Initialized head block from DB")
|
||||||
|
return errors.Wrap(s.setHead(&head{
|
||||||
|
root,
|
||||||
|
blk,
|
||||||
|
st,
|
||||||
|
blk.Block().Slot(),
|
||||||
false,
|
false,
|
||||||
}); err != nil {
|
}), "could not set head")
|
||||||
return errors.Wrap(err, "could not set head")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) startFromExecutionChain() error {
|
func (s *Service) startFromExecutionChain() error {
|
||||||
|
|||||||
@@ -2,28 +2,131 @@ package blockchain
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
forkchoicetypes "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice/types"
|
forkchoicetypes "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice/types"
|
||||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||||
"github.com/prysmaticlabs/prysm/v5/config/features"
|
"github.com/prysmaticlabs/prysm/v5/config/features"
|
||||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||||
|
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||||
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
|
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
|
||||||
|
"github.com/prysmaticlabs/prysm/v5/time/slots"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Service) setupForkchoice(st state.BeaconState) error {
|
func (s *Service) setupForkchoice(st state.BeaconState) error {
|
||||||
if err := s.setupForkchoiceCheckpoints(); err != nil {
|
if err := s.setupForkchoiceCheckpoints(); err != nil {
|
||||||
return errors.Wrap(err, "could not set up forkchoice checkpoints")
|
return errors.Wrap(err, "could not set up forkchoice checkpoints")
|
||||||
}
|
}
|
||||||
if err := s.setupForkchoiceRoot(st); err != nil {
|
if err := s.setupForkchoiceTree(st); err != nil {
|
||||||
return errors.Wrap(err, "could not set up forkchoice root")
|
return errors.Wrap(err, "could not set up forkchoice root")
|
||||||
}
|
}
|
||||||
if err := s.initializeHeadFromDB(s.ctx, st); err != nil {
|
if err := s.initializeHead(s.ctx, st); err != nil {
|
||||||
return errors.Wrap(err, "could not initialize head from db")
|
return errors.Wrap(err, "could not initialize head from db")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) startupHeadRoot() [32]byte {
|
||||||
|
headStr := features.Get().ForceHead
|
||||||
|
cp := s.FinalizedCheckpt()
|
||||||
|
fRoot := s.ensureRootNotZeros([32]byte(cp.Root))
|
||||||
|
if headStr == "" {
|
||||||
|
return fRoot
|
||||||
|
}
|
||||||
|
if headStr == "head" {
|
||||||
|
root, err := s.cfg.BeaconDB.HeadBlockRoot()
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Error("could not get head block root, starting with finalized block as head")
|
||||||
|
return fRoot
|
||||||
|
}
|
||||||
|
log.Infof("Using Head root of %#x", root)
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
root, err := bytesutil.DecodeHexWithLength(headStr, 32)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Error("could not parse head root, starting with finalized block as head")
|
||||||
|
return fRoot
|
||||||
|
}
|
||||||
|
return [32]byte(root)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) setupForkchoiceTree(st state.BeaconState) error {
|
||||||
|
headRoot := s.startupHeadRoot()
|
||||||
|
cp := s.FinalizedCheckpt()
|
||||||
|
fRoot := s.ensureRootNotZeros([32]byte(cp.Root))
|
||||||
|
if err := s.setupForkchoiceRoot(st); err != nil {
|
||||||
|
return errors.Wrap(err, "could not set up forkchoice root")
|
||||||
|
}
|
||||||
|
fBlk, err := s.cfg.BeaconDB.Block(s.ctx, fRoot)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "could not get finalized block")
|
||||||
|
}
|
||||||
|
if err := s.setHead(&head{
|
||||||
|
fRoot,
|
||||||
|
fBlk,
|
||||||
|
st,
|
||||||
|
fBlk.Block().Slot(),
|
||||||
|
false,
|
||||||
|
}); err != nil {
|
||||||
|
return errors.Wrap(err, "could not set head")
|
||||||
|
}
|
||||||
|
|
||||||
|
if headRoot == fRoot {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
blk, err := s.cfg.BeaconDB.Block(s.ctx, headRoot)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Error("could not get head block, starting with finalized block as head")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if slots.ToEpoch(blk.Block().Slot()) < cp.Epoch {
|
||||||
|
log.WithField("headRoot", fmt.Sprintf("%#x", headRoot)).Error("head block is older than finalized block, starting with finalized block as head")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
chain, err := s.buildForkchoiceChain(s.ctx, blk)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Error("could not build forkchoice chain, starting with finalized block as head")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
s.cfg.ForkChoiceStore.Lock()
|
||||||
|
defer s.cfg.ForkChoiceStore.Unlock()
|
||||||
|
return s.cfg.ForkChoiceStore.InsertChain(s.ctx, chain)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) buildForkchoiceChain(ctx context.Context, head interfaces.ReadOnlySignedBeaconBlock) ([]*forkchoicetypes.BlockAndCheckpoints, error) {
|
||||||
|
chain := []*forkchoicetypes.BlockAndCheckpoints{}
|
||||||
|
cp := s.FinalizedCheckpt()
|
||||||
|
fRoot := s.ensureRootNotZeros([32]byte(cp.Root))
|
||||||
|
jp := s.CurrentJustifiedCheckpt()
|
||||||
|
root, err := head.Block().HashTreeRoot()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not get head block root")
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
roblock, err := blocks.NewROBlockWithRoot(head, root)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// This chain sets the justified checkpoint for every block, including some that are older than jp.
|
||||||
|
// This should be however safe for forkchoice at startup.
|
||||||
|
chain = append(chain, &forkchoicetypes.BlockAndCheckpoints{Block: roblock, JustifiedCheckpoint: jp, FinalizedCheckpoint: cp})
|
||||||
|
root = head.Block().ParentRoot()
|
||||||
|
if root == fRoot {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
head, err = s.cfg.BeaconDB.Block(s.ctx, root)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not get block")
|
||||||
|
}
|
||||||
|
if slots.ToEpoch(head.Block().Slot()) < cp.Epoch {
|
||||||
|
return nil, errors.New("head block is not a descendant of the finalized checkpoint")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return chain, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) setupForkchoiceRoot(st state.BeaconState) error {
|
func (s *Service) setupForkchoiceRoot(st state.BeaconState) error {
|
||||||
cp := s.FinalizedCheckpt()
|
cp := s.FinalizedCheckpt()
|
||||||
fRoot := s.ensureRootNotZeros([32]byte(cp.Root))
|
fRoot := s.ensureRootNotZeros([32]byte(cp.Root))
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ type HeadAccessDatabase interface {
|
|||||||
|
|
||||||
// Block related methods.
|
// Block related methods.
|
||||||
HeadBlock(ctx context.Context) (interfaces.ReadOnlySignedBeaconBlock, error)
|
HeadBlock(ctx context.Context) (interfaces.ReadOnlySignedBeaconBlock, error)
|
||||||
|
HeadBlockRoot() ([32]byte, error)
|
||||||
SaveHeadBlockRoot(ctx context.Context, blockRoot [32]byte) error
|
SaveHeadBlockRoot(ctx context.Context, blockRoot [32]byte) error
|
||||||
|
|
||||||
// Genesis operations.
|
// Genesis operations.
|
||||||
|
|||||||
@@ -70,6 +70,21 @@ func (s *Store) OriginCheckpointBlockRoot(ctx context.Context) ([32]byte, error)
|
|||||||
return root, err
|
return root, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HeadBlockRoot returns the latest canonical block root in the Ethereum Beacon Chain.
|
||||||
|
func (s *Store) HeadBlockRoot() ([32]byte, error) {
|
||||||
|
var root [32]byte
|
||||||
|
err := s.db.View(func(tx *bolt.Tx) error {
|
||||||
|
bkt := tx.Bucket(blocksBucket)
|
||||||
|
headRoot := bkt.Get(headBlockRootKey)
|
||||||
|
if headRoot == nil {
|
||||||
|
return errors.New("no head block root found")
|
||||||
|
}
|
||||||
|
copy(root[:], headRoot)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return root, err
|
||||||
|
}
|
||||||
|
|
||||||
// HeadBlock returns the latest canonical block in the Ethereum Beacon Chain.
|
// HeadBlock returns the latest canonical block in the Ethereum Beacon Chain.
|
||||||
func (s *Store) HeadBlock(ctx context.Context) (interfaces.ReadOnlySignedBeaconBlock, error) {
|
func (s *Store) HeadBlock(ctx context.Context) (interfaces.ReadOnlySignedBeaconBlock, error) {
|
||||||
ctx, span := trace.StartSpan(ctx, "BeaconDB.HeadBlock")
|
ctx, span := trace.StartSpan(ctx, "BeaconDB.HeadBlock")
|
||||||
@@ -214,7 +229,8 @@ func (s *Store) DeleteBlock(ctx context.Context, root [32]byte) error {
|
|||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
if err := s.DeleteState(ctx, root); err != nil {
|
if err := s.DeleteState(ctx, root); err != nil {
|
||||||
return err
|
// TODO: Find out why invalid states are in the db
|
||||||
|
log.WithError(err).Error("Could not delete state")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.deleteStateSummary(root); err != nil {
|
if err := s.deleteStateSummary(root); err != nil {
|
||||||
|
|||||||
@@ -252,6 +252,13 @@ func (s *Store) tips() ([][32]byte, []primitives.Slot) {
|
|||||||
return roots, slots
|
return roots, slots
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *ForkChoice) HighestReceivedBlockRoot() [32]byte {
|
||||||
|
if f.store.highestReceivedNode == nil {
|
||||||
|
return [32]byte{}
|
||||||
|
}
|
||||||
|
return f.store.highestReceivedNode.root
|
||||||
|
}
|
||||||
|
|
||||||
// HighestReceivedBlockSlot returns the highest slot received by the forkchoice
|
// HighestReceivedBlockSlot returns the highest slot received by the forkchoice
|
||||||
func (f *ForkChoice) HighestReceivedBlockSlot() primitives.Slot {
|
func (f *ForkChoice) HighestReceivedBlockSlot() primitives.Slot {
|
||||||
if f.store.highestReceivedNode == nil {
|
if f.store.highestReceivedNode == nil {
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ type FastGetter interface {
|
|||||||
FinalizedPayloadBlockHash() [32]byte
|
FinalizedPayloadBlockHash() [32]byte
|
||||||
HasNode([32]byte) bool
|
HasNode([32]byte) bool
|
||||||
HighestReceivedBlockSlot() primitives.Slot
|
HighestReceivedBlockSlot() primitives.Slot
|
||||||
|
HighestReceivedBlockRoot() [32]byte
|
||||||
HighestReceivedBlockDelay() primitives.Slot
|
HighestReceivedBlockDelay() primitives.Slot
|
||||||
IsCanonical(root [32]byte) bool
|
IsCanonical(root [32]byte) bool
|
||||||
IsOptimistic(root [32]byte) (bool, error)
|
IsOptimistic(root [32]byte) (bool, error)
|
||||||
|
|||||||
@@ -114,6 +114,13 @@ func (ro *ROForkChoice) HighestReceivedBlockSlot() primitives.Slot {
|
|||||||
return ro.getter.HighestReceivedBlockSlot()
|
return ro.getter.HighestReceivedBlockSlot()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HighestReceivedBlockRoot delegates to the underlying forkchoice call, under a lock.
|
||||||
|
func (ro *ROForkChoice) HighestReceivedBlockRoot() [32]byte {
|
||||||
|
ro.l.RLock()
|
||||||
|
defer ro.l.RUnlock()
|
||||||
|
return ro.getter.HighestReceivedBlockRoot()
|
||||||
|
}
|
||||||
|
|
||||||
// HighestReceivedBlockDelay delegates to the underlying forkchoice call, under a lock.
|
// HighestReceivedBlockDelay delegates to the underlying forkchoice call, under a lock.
|
||||||
func (ro *ROForkChoice) HighestReceivedBlockDelay() primitives.Slot {
|
func (ro *ROForkChoice) HighestReceivedBlockDelay() primitives.Slot {
|
||||||
ro.l.RLock()
|
ro.l.RLock()
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ const (
|
|||||||
unrealizedJustifiedPayloadBlockHashCalled
|
unrealizedJustifiedPayloadBlockHashCalled
|
||||||
nodeCountCalled
|
nodeCountCalled
|
||||||
highestReceivedBlockSlotCalled
|
highestReceivedBlockSlotCalled
|
||||||
|
highestReceivedBlockRootCalled
|
||||||
highestReceivedBlockDelayCalled
|
highestReceivedBlockDelayCalled
|
||||||
receivedBlocksLastEpochCalled
|
receivedBlocksLastEpochCalled
|
||||||
weightCalled
|
weightCalled
|
||||||
@@ -252,6 +253,11 @@ func (ro *mockROForkchoice) HighestReceivedBlockSlot() primitives.Slot {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ro *mockROForkchoice) HighestReceivedBlockRoot() [32]byte {
|
||||||
|
ro.calls = append(ro.calls, highestReceivedBlockRootCalled)
|
||||||
|
return [32]byte{}
|
||||||
|
}
|
||||||
|
|
||||||
func (ro *mockROForkchoice) HighestReceivedBlockDelay() primitives.Slot {
|
func (ro *mockROForkchoice) HighestReceivedBlockDelay() primitives.Slot {
|
||||||
ro.calls = append(ro.calls, highestReceivedBlockDelayCalled)
|
ro.calls = append(ro.calls, highestReceivedBlockDelayCalled)
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||||
"github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1/attestation"
|
"github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1/attestation"
|
||||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SaveUnaggregatedAttestation saves an unaggregated attestation in cache.
|
// SaveUnaggregatedAttestation saves an unaggregated attestation in cache.
|
||||||
@@ -60,7 +61,8 @@ func (c *AttCaches) UnaggregatedAttestations() ([]ethpb.Att, error) {
|
|||||||
for _, att := range unAggregatedAtts {
|
for _, att := range unAggregatedAtts {
|
||||||
seen, err := c.hasSeenBit(att)
|
seen, err := c.hasSeenBit(att)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
log.WithError(err).Debug("Could not check if attestations bits have been seen")
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
if !seen {
|
if !seen {
|
||||||
atts = append(atts, att.Clone())
|
atts = append(atts, att.Clone())
|
||||||
@@ -163,7 +165,13 @@ func (c *AttCaches) DeleteSeenUnaggregatedAttestations() (int, error) {
|
|||||||
if att == nil || att.IsNil() || att.IsAggregated() {
|
if att == nil || att.IsNil() || att.IsAggregated() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if seen, err := c.hasSeenBit(att); err == nil && seen {
|
seen, err := c.hasSeenBit(att)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Debug("Could not check if attestations bits have been seen")
|
||||||
|
delete(c.unAggregatedAtt, r)
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
if seen {
|
||||||
delete(c.unAggregatedAtt, r)
|
delete(c.unAggregatedAtt, r)
|
||||||
count++
|
count++
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,13 +39,6 @@ func (vs *Server) packAttestations(ctx context.Context, latestState state.Beacon
|
|||||||
} else {
|
} else {
|
||||||
atts = vs.AttPool.AggregatedAttestations()
|
atts = vs.AttPool.AggregatedAttestations()
|
||||||
atts = vs.validateAndDeleteAttsInPool(ctx, latestState, atts)
|
atts = vs.validateAndDeleteAttsInPool(ctx, latestState, atts)
|
||||||
|
|
||||||
uAtts, err := vs.AttPool.UnaggregatedAttestations()
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "could not get unaggregated attestations")
|
|
||||||
}
|
|
||||||
uAtts = vs.validateAndDeleteAttsInPool(ctx, latestState, uAtts)
|
|
||||||
atts = append(atts, uAtts...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checking the state's version here will give the wrong result if the last slot of Deneb is missed.
|
// Checking the state's version here will give the wrong result if the last slot of Deneb is missed.
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ go_library(
|
|||||||
"//consensus-types/primitives:go_default_library",
|
"//consensus-types/primitives:go_default_library",
|
||||||
"//container/leaky-bucket:go_default_library",
|
"//container/leaky-bucket:go_default_library",
|
||||||
"//crypto/rand:go_default_library",
|
"//crypto/rand:go_default_library",
|
||||||
|
"//encoding/bytesutil:go_default_library",
|
||||||
"//math:go_default_library",
|
"//math:go_default_library",
|
||||||
"//monitoring/tracing/trace:go_default_library",
|
"//monitoring/tracing/trace:go_default_library",
|
||||||
"//proto/prysm/v1alpha1:go_default_library",
|
"//proto/prysm/v1alpha1:go_default_library",
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package initialsync
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -24,6 +25,7 @@ import (
|
|||||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||||
leakybucket "github.com/prysmaticlabs/prysm/v5/container/leaky-bucket"
|
leakybucket "github.com/prysmaticlabs/prysm/v5/container/leaky-bucket"
|
||||||
"github.com/prysmaticlabs/prysm/v5/crypto/rand"
|
"github.com/prysmaticlabs/prysm/v5/crypto/rand"
|
||||||
|
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
|
||||||
"github.com/prysmaticlabs/prysm/v5/math"
|
"github.com/prysmaticlabs/prysm/v5/math"
|
||||||
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
|
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
|
||||||
p2ppb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
p2ppb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||||
@@ -67,6 +69,8 @@ var (
|
|||||||
// Period to calculate expected limit for a single peer.
|
// Period to calculate expected limit for a single peer.
|
||||||
var blockLimiterPeriod = 30 * time.Second
|
var blockLimiterPeriod = 30 * time.Second
|
||||||
|
|
||||||
|
type isBannedBlock func(root [32]byte) bool
|
||||||
|
|
||||||
// blocksFetcherConfig is a config to setup the block fetcher.
|
// blocksFetcherConfig is a config to setup the block fetcher.
|
||||||
type blocksFetcherConfig struct {
|
type blocksFetcherConfig struct {
|
||||||
clock *startup.Clock
|
clock *startup.Clock
|
||||||
@@ -101,6 +105,7 @@ type blocksFetcher struct {
|
|||||||
capacityWeight float64 // how remaining capacity affects peer selection
|
capacityWeight float64 // how remaining capacity affects peer selection
|
||||||
mode syncMode // allows to use fetcher in different sync scenarios
|
mode syncMode // allows to use fetcher in different sync scenarios
|
||||||
quit chan struct{} // termination notifier
|
quit chan struct{} // termination notifier
|
||||||
|
isBannedBlock isBannedBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
// peerLock restricts fetcher actions on per peer basis. Currently, used for rate limiting.
|
// peerLock restricts fetcher actions on per peer basis. Currently, used for rate limiting.
|
||||||
@@ -126,6 +131,13 @@ type fetchRequestResponse struct {
|
|||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set in init()
|
||||||
|
var holeskyBadRoot [32]byte
|
||||||
|
|
||||||
|
func isHoleskyBannedBlock(root [32]byte) bool {
|
||||||
|
return root == holeskyBadRoot
|
||||||
|
}
|
||||||
|
|
||||||
// newBlocksFetcher creates ready to use fetcher.
|
// newBlocksFetcher creates ready to use fetcher.
|
||||||
func newBlocksFetcher(ctx context.Context, cfg *blocksFetcherConfig) *blocksFetcher {
|
func newBlocksFetcher(ctx context.Context, cfg *blocksFetcherConfig) *blocksFetcher {
|
||||||
blockBatchLimit := maxBatchLimit()
|
blockBatchLimit := maxBatchLimit()
|
||||||
@@ -160,6 +172,7 @@ func newBlocksFetcher(ctx context.Context, cfg *blocksFetcherConfig) *blocksFetc
|
|||||||
capacityWeight: capacityWeight,
|
capacityWeight: capacityWeight,
|
||||||
mode: cfg.mode,
|
mode: cfg.mode,
|
||||||
quit: make(chan struct{}),
|
quit: make(chan struct{}),
|
||||||
|
isBannedBlock: isHoleskyBannedBlock,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,6 +370,13 @@ func (f *blocksFetcher) fetchBlocksFromPeer(
|
|||||||
log.WithField("peer", p).WithError(err).Debug("invalid BeaconBlocksByRange response")
|
log.WithField("peer", p).WithError(err).Debug("invalid BeaconBlocksByRange response")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if f.isBannedBlock != nil {
|
||||||
|
for _, b := range robs {
|
||||||
|
if f.isBannedBlock(b.Block.Root()) {
|
||||||
|
return nil, p, prysmsync.ErrInvalidFetchedData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return robs, p, err
|
return robs, p, err
|
||||||
}
|
}
|
||||||
return nil, "", errNoPeersAvailable
|
return nil, "", errNoPeersAvailable
|
||||||
@@ -727,3 +747,11 @@ func dedupPeers(peers []peer.ID) []peer.ID {
|
|||||||
}
|
}
|
||||||
return newPeerList
|
return newPeerList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
bytes, err := hex.DecodeString("2db899881ed8546476d0b92c6aa9110bea9a4cd0dbeb5519eb0ea69575f1f359")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
holeskyBadRoot = bytesutil.ToBytes32(bytes)
|
||||||
|
}
|
||||||
|
|||||||
@@ -125,6 +125,7 @@ func (s *Service) syncToNonFinalizedEpoch(ctx context.Context, genesis time.Time
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for data := range queue.fetchedData {
|
for data := range queue.fetchedData {
|
||||||
s.processFetchedDataRegSync(ctx, genesis, s.cfg.Chain.HeadSlot(), data)
|
s.processFetchedDataRegSync(ctx, genesis, s.cfg.Chain.HeadSlot(), data)
|
||||||
}
|
}
|
||||||
@@ -169,6 +170,7 @@ func (s *Service) processFetchedDataRegSync(
|
|||||||
"firstSlot": data.bwb[0].Block.Block().Slot(),
|
"firstSlot": data.bwb[0].Block.Block().Slot(),
|
||||||
"firstUnprocessed": bwb[0].Block.Block().Slot(),
|
"firstUnprocessed": bwb[0].Block.Block().Slot(),
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, b := range bwb {
|
for _, b := range bwb {
|
||||||
if err := avs.Persist(s.clock.CurrentSlot(), b.Blobs...); err != nil {
|
if err := avs.Persist(s.clock.CurrentSlot(), b.Blobs...); err != nil {
|
||||||
log.WithError(err).WithFields(batchFields).WithFields(syncFields(b.Block)).Warn("Batch failure due to BlobSidecar issues")
|
log.WithError(err).WithFields(batchFields).WithFields(syncFields(b.Block)).Warn("Batch failure due to BlobSidecar issues")
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ package sync
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/hex"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -49,6 +50,9 @@ import (
|
|||||||
"github.com/prysmaticlabs/prysm/v5/time/slots"
|
"github.com/prysmaticlabs/prysm/v5/time/slots"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// hack to prevent bad holesky block importation
|
||||||
|
var badHoleskyRoot [32]byte
|
||||||
|
|
||||||
var _ runtime.Service = (*Service)(nil)
|
var _ runtime.Service = (*Service)(nil)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -383,3 +387,13 @@ type Checker interface {
|
|||||||
Status() error
|
Status() error
|
||||||
Resync() error
|
Resync() error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
hexStr := "2db899881ed8546476d0b92c6aa9110bea9a4cd0dbeb5519eb0ea69575f1f359"
|
||||||
|
bytes, err := hex.DecodeString(hexStr)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Could not decode hex string")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
badHoleskyRoot = [32]byte(bytes)
|
||||||
|
}
|
||||||
|
|||||||
@@ -399,6 +399,9 @@ func (s *Service) setSeenBlockIndexSlot(slot primitives.Slot, proposerIdx primit
|
|||||||
|
|
||||||
// Returns true if the block is marked as a bad block.
|
// Returns true if the block is marked as a bad block.
|
||||||
func (s *Service) hasBadBlock(root [32]byte) bool {
|
func (s *Service) hasBadBlock(root [32]byte) bool {
|
||||||
|
if root == badHoleskyRoot {
|
||||||
|
return true
|
||||||
|
}
|
||||||
s.badBlockLock.RLock()
|
s.badBlockLock.RLock()
|
||||||
defer s.badBlockLock.RUnlock()
|
defer s.badBlockLock.RUnlock()
|
||||||
_, seen := s.badBlockCache.Get(string(root[:]))
|
_, seen := s.badBlockCache.Get(string(root[:]))
|
||||||
|
|||||||
3
changelog/potuz_sync_from_head.md
Normal file
3
changelog/potuz_sync_from_head.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
### Added
|
||||||
|
|
||||||
|
- Added a feature flag to sync from an arbitrary beacon block root at startup.
|
||||||
@@ -86,6 +86,9 @@ type Flags struct {
|
|||||||
|
|
||||||
// AggregateIntervals specifies the time durations at which we aggregate attestations preparing for forkchoice.
|
// AggregateIntervals specifies the time durations at which we aggregate attestations preparing for forkchoice.
|
||||||
AggregateIntervals [3]time.Duration
|
AggregateIntervals [3]time.Duration
|
||||||
|
|
||||||
|
// Feature related flags (alignment forced in the end)
|
||||||
|
ForceHead string // ForceHead forces the head block to be a specific block root, the last head block, or the last finalized block.
|
||||||
}
|
}
|
||||||
|
|
||||||
var featureConfig *Flags
|
var featureConfig *Flags
|
||||||
@@ -268,6 +271,10 @@ func ConfigureBeaconChain(ctx *cli.Context) error {
|
|||||||
logEnabled(enableExperimentalAttestationPool)
|
logEnabled(enableExperimentalAttestationPool)
|
||||||
cfg.EnableExperimentalAttestationPool = true
|
cfg.EnableExperimentalAttestationPool = true
|
||||||
}
|
}
|
||||||
|
if ctx.IsSet(forceHeadFlag.Name) {
|
||||||
|
logEnabled(forceHeadFlag)
|
||||||
|
cfg.ForceHead = ctx.String(forceHeadFlag.Name)
|
||||||
|
}
|
||||||
|
|
||||||
cfg.AggregateIntervals = [3]time.Duration{aggregateFirstInterval.Value, aggregateSecondInterval.Value, aggregateThirdInterval.Value}
|
cfg.AggregateIntervals = [3]time.Duration{aggregateFirstInterval.Value, aggregateSecondInterval.Value, aggregateThirdInterval.Value}
|
||||||
Init(cfg)
|
Init(cfg)
|
||||||
|
|||||||
@@ -174,6 +174,12 @@ var (
|
|||||||
Name: "enable-experimental-attestation-pool",
|
Name: "enable-experimental-attestation-pool",
|
||||||
Usage: "Enables an experimental attestation pool design.",
|
Usage: "Enables an experimental attestation pool design.",
|
||||||
}
|
}
|
||||||
|
// forceHeadFlag is a flag to force the head of the beacon chain to a specific block.
|
||||||
|
forceHeadFlag = &cli.StringFlag{
|
||||||
|
Name: "sync-from",
|
||||||
|
Usage: "Forces the head of the beacon chain to a specific block root. Values can be 'head' or a block root." +
|
||||||
|
" The block root has to be known to the beacon node and correspond to a block newer than the current finalized checkpoint.",
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// devModeFlags holds list of flags that are set when development mode is on.
|
// devModeFlags holds list of flags that are set when development mode is on.
|
||||||
@@ -230,6 +236,7 @@ var BeaconChainFlags = combinedFlags([]cli.Flag{
|
|||||||
DisableCommitteeAwarePacking,
|
DisableCommitteeAwarePacking,
|
||||||
EnableDiscoveryReboot,
|
EnableDiscoveryReboot,
|
||||||
enableExperimentalAttestationPool,
|
enableExperimentalAttestationPool,
|
||||||
|
forceHeadFlag,
|
||||||
}, deprecatedBeaconFlags, deprecatedFlags, upcomingDeprecation)
|
}, deprecatedBeaconFlags, deprecatedFlags, upcomingDeprecation)
|
||||||
|
|
||||||
func combinedFlags(flags ...[]cli.Flag) []cli.Flag {
|
func combinedFlags(flags ...[]cli.Flag) []cli.Flag {
|
||||||
|
|||||||
@@ -7,15 +7,10 @@ func UseHoleskyNetworkConfig() {
|
|||||||
cfg := BeaconNetworkConfig().Copy()
|
cfg := BeaconNetworkConfig().Copy()
|
||||||
cfg.ContractDeploymentBlock = 0
|
cfg.ContractDeploymentBlock = 0
|
||||||
cfg.BootstrapNodes = []string{
|
cfg.BootstrapNodes = []string{
|
||||||
// EF
|
"enr:-Oa4QOuWj-_JX6iJWjdS_67qQkkVoomo3YztvdOLVF4lVwc3NzFR3D8y-8CmGjmQA16DJBOZWwbc3XMOw_w_ScU6-qCCAgSHYXR0bmV0c4gAAAMAAAAAAIZjbGllbnTYikxpZ2h0aG91c2WMNy4wLjAtYmV0YS4whGV0aDKQAZ4hrQYBcAD__________4JpZIJ2NIJpcISyE90mhHF1aWOCfLuJc2VjcDI1NmsxoQK-fTVglh3wyHIcyauubuyvLeFmn6QpUwog7Aio2OSucYhzeW5jbmV0cwCDdGNwgny6g3VkcIJ8ug",
|
||||||
"enr:-Ku4QFo-9q73SspYI8cac_4kTX7yF800VXqJW4Lj3HkIkb5CMqFLxciNHePmMt4XdJzHvhrCC5ADI4D_GkAsxGJRLnQBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpAhnTT-AQFwAP__________gmlkgnY0gmlwhLKAiOmJc2VjcDI1NmsxoQORcM6e19T1T9gi7jxEZjk_sjVLGFscUNqAY9obgZaxbIN1ZHCCIyk",
|
"enr:-PW4QAOnzqnCuwuNNrUEXebSD3MFMOe-9NApsb8UkAQK-MquYtUhj35Ksz4EWcmdB0Cmj43bGBJJEpt9fYMAg1vOHXobh2F0dG5ldHOIAAAYAAAAAACGY2xpZW502IpMaWdodGhvdXNljDcuMC4wLWJldGEuMIRldGgykAGeIa0GAXAA__________-CaWSCdjSCaXCEff1tSYRxdWljgiMphXF1aWM2giMpiXNlY3AyNTZrMaECUiAFSBathSIPGhDHbZjQS5gTqaPcRkAe4HECCk-vt6KIc3luY25ldHMPg3RjcIIjKIR0Y3A2giMog3VkcIIjKA",
|
||||||
"enr:-Ku4QPG7F72mbKx3gEQEx07wpYYusGDh-ni6SNkLvOS-hhN-BxIggN7tKlmalb0L5JPoAfqD-akTZ-gX06hFeBEz4WoBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpAhnTT-AQFwAP__________gmlkgnY0gmlwhJK-DYCJc2VjcDI1NmsxoQKLVXFOhp2uX6jeT0DvvDpPcU8FWMjQdR4wMuORMhpX24N1ZHCCIyk",
|
"enr:-QESuEA2tFgFDu5LX9T6j1_bayowdRzrtdQcjwmTq_zOVjwe1WQOsM7-Q4qRcgc7AjpAQOcdb2F3wyPDBkbP-vxW2dLgXYdhdHRuZXRziAADAAAAAAAAhmNsaWVudNiKTGlnaHRob3VzZYw3LjAuMC1iZXRhLjCEZXRoMpABniGtBgFwAP__________gmlkgnY0gmlwhIe1ME2DaXA2kCoBBPkwgDCeAAAAAAAAAAKEcXVpY4IjKYVxdWljNoIjg4lzZWNwMjU2azGhA4oHjOmlWOfLizFFIQSI_dzn4rzvDvMG8h7zmxhmOVzXiHN5bmNuZXRzD4N0Y3CCIyiEdGNwNoIjgoN1ZHCCIyiEdWRwNoIjgg",
|
||||||
"enr:-LK4QPxe-mDiSOtEB_Y82ozvxn9aQM07Ui8A-vQHNgYGMMthfsfOabaaTHhhJHFCBQQVRjBww_A5bM1rf8MlkJU_l68Eh2F0dG5ldHOIAADAAAAAAACEZXRoMpBpt9l0BAFwAAABAAAAAAAAgmlkgnY0gmlwhLKAiOmJc2VjcDI1NmsxoQJu6T9pclPObAzEVQ53DpVQqjadmVxdTLL-J3h9NFoCeIN0Y3CCIyiDdWRwgiMo",
|
"enr:-KG4QCvyykb0pA1T-EZJUPkl2P1PKYk8-4El8TqwWdKwtoI6NtIBGMJVDgGZKVy2eMszI0_ermORtQ340lj1dTHzGVVPhGV0aDKQAZ4hrQYBcAD__________4JpZIJ2NIJpcIQ5gNI3iXNlY3AyNTZrMaEDMQYffETNbuGwVzWEJSgCpA50LTxHUWU1A0TDfleEa5mDdGNwgjvFg3VkcII7xQ",
|
||||||
"enr:-Ly4QGbOw4xNel5EhmDsJJ-QhC9XycWtsetnWoZ0uRy381GHdHsNHJiCwDTOkb3S1Ade0SFQkWJX_pgb3g8Jfh93rvMBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpBpt9l0BAFwAAABAAAAAAAAgmlkgnY0gmlwhJK-DYCJc2VjcDI1NmsxoQOxKv9sv3zKF8GDewgFGGHKP5HCZZpPpTrwl9eXKAWGxIhzeW5jbmV0cwCDdGNwgiMog3VkcIIjKA",
|
|
||||||
// Teku
|
|
||||||
"enr:-LS4QG0uV4qvcpJ-HFDJRGBmnlD3TJo7yc4jwK8iP7iKaTlfQ5kZvIDspLMJhk7j9KapuL9yyHaZmwTEZqr10k9XumyCEcmHYXR0bmV0c4gAAAAABgAAAIRldGgykGm32XQEAXAAAAEAAAAAAACCaWSCdjSCaXCErK4j-YlzZWNwMjU2azGhAgfWRBEJlb7gAhXIB5ePmjj2b8io0UpEenq1Kl9cxStJg3RjcIIjKIN1ZHCCIyg",
|
|
||||||
// Sigma Prime
|
|
||||||
"enr:-Le4QLoE1wFHSlGcm48a9ZESb_MRLqPPu6G0vHqu4MaUcQNDHS69tsy-zkN0K6pglyzX8m24mkb-LtBcbjAYdP1uxm4BhGV0aDKQabfZdAQBcAAAAQAAAAAAAIJpZIJ2NIJpcIQ5gR6Wg2lwNpAgAUHQBwEQAAAAAAAAADR-iXNlY3AyNTZrMaEDPMSNdcL92uNIyCsS177Z6KTXlbZakQqxv3aQcWawNXeDdWRwgiMohHVkcDaCI4I",
|
|
||||||
}
|
}
|
||||||
OverrideBeaconNetworkConfig(cfg)
|
OverrideBeaconNetworkConfig(cfg)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,14 +22,10 @@ func IsHex(b []byte) bool {
|
|||||||
// DecodeHexWithLength takes a string and a length in bytes,
|
// DecodeHexWithLength takes a string and a length in bytes,
|
||||||
// and validates whether the string is a hex and has the correct length.
|
// and validates whether the string is a hex and has the correct length.
|
||||||
func DecodeHexWithLength(s string, length int) ([]byte, error) {
|
func DecodeHexWithLength(s string, length int) ([]byte, error) {
|
||||||
bytes, err := hexutil.Decode(s)
|
if len(s) != 2*length+2 {
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, fmt.Sprintf("%s is not a valid hex", s))
|
|
||||||
}
|
|
||||||
if len(bytes) != length {
|
|
||||||
return nil, fmt.Errorf("%s is not length %d bytes", s, length)
|
return nil, fmt.Errorf("%s is not length %d bytes", s, length)
|
||||||
}
|
}
|
||||||
return bytes, nil
|
return hexutil.Decode(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeHexWithMaxLength takes a string and a length in bytes,
|
// DecodeHexWithMaxLength takes a string and a length in bytes,
|
||||||
|
|||||||
Reference in New Issue
Block a user