mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-02-02 00:55:16 -05:00
Compare commits
83 Commits
e2e-debugg
...
blob-rotat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b8a38039b | ||
|
|
5410c30890 | ||
|
|
8024758ff4 | ||
|
|
826a930ed0 | ||
|
|
3d45b83059 | ||
|
|
9096c4a8c4 | ||
|
|
31f369c982 | ||
|
|
8a7ab754b2 | ||
|
|
752bb63ec4 | ||
|
|
52a87e912d | ||
|
|
3400af655c | ||
|
|
1e5c0778b9 | ||
|
|
a032cf2ccc | ||
|
|
f871d7668f | ||
|
|
5c2ebec369 | ||
|
|
a22d62e398 | ||
|
|
00c57e76ec | ||
|
|
1d800e42c5 | ||
|
|
1391ccedd2 | ||
|
|
e71124ee87 | ||
|
|
f04b2be9de | ||
|
|
080810ec25 | ||
|
|
37118e7815 | ||
|
|
a390c74721 | ||
|
|
9b260be2c7 | ||
|
|
bd6cf8d5d8 | ||
|
|
bff4435b72 | ||
|
|
d8187b7bb1 | ||
|
|
109a0f5f0f | ||
|
|
bc0ba2d508 | ||
|
|
5b53ad6cdf | ||
|
|
920e0757d9 | ||
|
|
bd01ffaa97 | ||
|
|
41f34aa6dd | ||
|
|
48c26b9eec | ||
|
|
eed1e47664 | ||
|
|
b18ebab455 | ||
|
|
ebe1e9ec3a | ||
|
|
b2b4aa9406 | ||
|
|
7d6f079697 | ||
|
|
b2a9a79e96 | ||
|
|
cb524c5cef | ||
|
|
2e0a6d6556 | ||
|
|
ac4a4cc80d | ||
|
|
027e49c120 | ||
|
|
ff822a6f4e | ||
|
|
901a087a6d | ||
|
|
be8c0293ad | ||
|
|
d5d1b33761 | ||
|
|
53bb657bd2 | ||
|
|
e2bf25e088 | ||
|
|
31e1999ddf | ||
|
|
cb3da77ff4 | ||
|
|
40c754e991 | ||
|
|
b6a05ecd32 | ||
|
|
3a6a7d7bcd | ||
|
|
27677da136 | ||
|
|
eb1c7bd5f6 | ||
|
|
b3d2ed1aaf | ||
|
|
bf1b5a5094 | ||
|
|
d3b6b2d8bc | ||
|
|
43814449c0 | ||
|
|
533a6b3f0c | ||
|
|
8e370da195 | ||
|
|
024ad7b433 | ||
|
|
13becadb30 | ||
|
|
e3f1a2d321 | ||
|
|
0f8c4431fc | ||
|
|
f566d50a43 | ||
|
|
7fc3a697d8 | ||
|
|
c5ee1c2735 | ||
|
|
658725a601 | ||
|
|
80546f83e9 | ||
|
|
d7489f9f0f | ||
|
|
aad947b83f | ||
|
|
7d2a257094 | ||
|
|
965280190a | ||
|
|
bcffe3d291 | ||
|
|
e3438cd9ee | ||
|
|
a8bc8af9e7 | ||
|
|
e70492ec8c | ||
|
|
ea9979f813 | ||
|
|
e504d31285 |
@@ -62,6 +62,7 @@ go_library(
|
|||||||
"//config/features:go_default_library",
|
"//config/features:go_default_library",
|
||||||
"//config/fieldparams:go_default_library",
|
"//config/fieldparams:go_default_library",
|
||||||
"//config/params:go_default_library",
|
"//config/params:go_default_library",
|
||||||
|
"//consensus-types/blobs:go_default_library",
|
||||||
"//consensus-types/blocks:go_default_library",
|
"//consensus-types/blocks:go_default_library",
|
||||||
"//consensus-types/interfaces:go_default_library",
|
"//consensus-types/interfaces:go_default_library",
|
||||||
"//consensus-types/primitives:go_default_library",
|
"//consensus-types/primitives:go_default_library",
|
||||||
|
|||||||
@@ -38,14 +38,14 @@ func logStateTransitionData(b interfaces.BeaconBlock) error {
|
|||||||
if len(b.Body().VoluntaryExits()) > 0 {
|
if len(b.Body().VoluntaryExits()) > 0 {
|
||||||
log = log.WithField("voluntaryExits", len(b.Body().VoluntaryExits()))
|
log = log.WithField("voluntaryExits", len(b.Body().VoluntaryExits()))
|
||||||
}
|
}
|
||||||
if b.Version() == version.Altair || b.Version() == version.Bellatrix {
|
if b.Version() == version.Altair || b.Version() == version.Bellatrix || b.Version() == version.EIP4844 {
|
||||||
agg, err := b.Body().SyncAggregate()
|
agg, err := b.Body().SyncAggregate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log = log.WithField("syncBitsCount", agg.SyncCommitteeBits.Count())
|
log = log.WithField("syncBitsCount", agg.SyncCommitteeBits.Count())
|
||||||
}
|
}
|
||||||
if b.Version() == version.Bellatrix {
|
if b.Version() == version.Bellatrix || b.Version() == version.EIP4844 {
|
||||||
p, err := b.Body().Execution()
|
p, err := b.Body().Execution()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -62,6 +62,13 @@ func logStateTransitionData(b interfaces.BeaconBlock) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
if b.Version() == version.EIP4844 {
|
||||||
|
k, err := b.Body().BlobKzgs()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log = log.WithField("blobKzgCount", len(k))
|
||||||
|
}
|
||||||
log.Info("Finished applying state transition")
|
log.Info("Finished applying state transition")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -328,7 +328,7 @@ func reportEpochMetrics(ctx context.Context, postState, headState state.BeaconSt
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case version.Altair, version.Bellatrix:
|
case version.Altair, version.Bellatrix, version.EIP4844:
|
||||||
v, b, err = altair.InitializePrecomputeValidators(ctx, headState)
|
v, b, err = altair.InitializePrecomputeValidators(ctx, headState)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import (
|
|||||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
|
||||||
"github.com/prysmaticlabs/prysm/v3/config/features"
|
"github.com/prysmaticlabs/prysm/v3/config/features"
|
||||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/consensus-types/blobs"
|
||||||
consensusblocks "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
consensusblocks "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
||||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
||||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||||
@@ -143,6 +144,16 @@ func (s *Service) onBlock(ctx context.Context, signed interfaces.SignedBeaconBlo
|
|||||||
if err := s.insertBlockToForkchoiceStore(ctx, signed.Block(), blockRoot, postState); err != nil {
|
if err := s.insertBlockToForkchoiceStore(ctx, signed.Block(), blockRoot, postState); err != nil {
|
||||||
return errors.Wrapf(err, "could not insert block %d to fork choice store", signed.Block().Slot())
|
return errors.Wrapf(err, "could not insert block %d to fork choice store", signed.Block().Slot())
|
||||||
}
|
}
|
||||||
|
hasSideCar, err := blobs.BlockContainsSidecar(signed)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if hasSideCar {
|
||||||
|
if err := s.cfg.ForkChoiceStore.SetValidData(ctx, blockRoot); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := s.handleBlockAttestations(ctx, signed.Block(), postState); err != nil {
|
if err := s.handleBlockAttestations(ctx, signed.Block(), postState); err != nil {
|
||||||
return errors.Wrap(err, "could not handle block's attestations")
|
return errors.Wrap(err, "could not handle block's attestations")
|
||||||
}
|
}
|
||||||
@@ -296,8 +307,7 @@ func getStateVersionAndPayload(st state.BeaconState) (int, *enginev1.ExecutionPa
|
|||||||
return preStateVersion, preStateHeader, nil
|
return preStateVersion, preStateHeader, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) onBlockBatch(ctx context.Context, blks []interfaces.SignedBeaconBlock,
|
func (s *Service) onBlockBatch(ctx context.Context, blks []interfaces.SignedBeaconBlock, blockRoots [][32]byte) error {
|
||||||
blockRoots [][32]byte) error {
|
|
||||||
ctx, span := trace.StartSpan(ctx, "blockChain.onBlockBatch")
|
ctx, span := trace.StartSpan(ctx, "blockChain.onBlockBatch")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
@@ -416,6 +426,20 @@ func (s *Service) onBlockBatch(ctx context.Context, blks []interfaces.SignedBeac
|
|||||||
tracing.AnnotateError(span, err)
|
tracing.AnnotateError(span, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
hasSideCar, err := blobs.BlockContainsSidecar(b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if hasSideCar {
|
||||||
|
if err := s.cfg.ForkChoiceStore.SetValidData(ctx, blockRoots[i]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.saveSidecar(ctx, b); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if i > 0 && jCheckpoints[i].Epoch > jCheckpoints[i-1].Epoch {
|
if i > 0 && jCheckpoints[i].Epoch > jCheckpoints[i-1].Epoch {
|
||||||
if err := s.cfg.BeaconDB.SaveJustifiedCheckpoint(ctx, jCheckpoints[i]); err != nil {
|
if err := s.cfg.BeaconDB.SaveJustifiedCheckpoint(ctx, jCheckpoints[i]); err != nil {
|
||||||
tracing.AnnotateError(span, err)
|
tracing.AnnotateError(span, err)
|
||||||
@@ -433,6 +457,7 @@ func (s *Service) onBlockBatch(ctx context.Context, blks []interfaces.SignedBeac
|
|||||||
if err := s.cfg.ForkChoiceStore.InsertOptimisticChain(ctx, pendingNodes); err != nil {
|
if err := s.cfg.ForkChoiceStore.InsertOptimisticChain(ctx, pendingNodes); err != nil {
|
||||||
return errors.Wrap(err, "could not insert batch to forkchoice")
|
return errors.Wrap(err, "could not insert batch to forkchoice")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert the last block to forkchoice
|
// Insert the last block to forkchoice
|
||||||
lastBR := blockRoots[len(blks)-1]
|
lastBR := blockRoots[len(blks)-1]
|
||||||
if err := s.cfg.ForkChoiceStore.InsertNode(ctx, preState, lastBR); err != nil {
|
if err := s.cfg.ForkChoiceStore.InsertNode(ctx, preState, lastBR); err != nil {
|
||||||
@@ -571,15 +596,36 @@ func (s *Service) InsertSlashingsToForkChoiceStore(ctx context.Context, slashing
|
|||||||
func (s *Service) savePostStateInfo(ctx context.Context, r [32]byte, b interfaces.SignedBeaconBlock, st state.BeaconState) error {
|
func (s *Service) savePostStateInfo(ctx context.Context, r [32]byte, b interfaces.SignedBeaconBlock, st state.BeaconState) error {
|
||||||
ctx, span := trace.StartSpan(ctx, "blockChain.savePostStateInfo")
|
ctx, span := trace.StartSpan(ctx, "blockChain.savePostStateInfo")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
if err := s.cfg.BeaconDB.SaveBlock(ctx, b); err != nil {
|
if err := s.cfg.BeaconDB.SaveBlock(ctx, b); err != nil {
|
||||||
return errors.Wrapf(err, "could not save block from slot %d", b.Block().Slot())
|
return errors.Wrapf(err, "could not save block from slot %d", b.Block().Slot())
|
||||||
}
|
}
|
||||||
|
if err := s.saveSidecar(ctx, b); err != nil {
|
||||||
|
return errors.Wrapf(err, "could not save sidecar from slot %d", b.Block().Slot())
|
||||||
|
}
|
||||||
if err := s.cfg.StateGen.SaveState(ctx, r, st); err != nil {
|
if err := s.cfg.StateGen.SaveState(ctx, r, st); err != nil {
|
||||||
return errors.Wrap(err, "could not save state")
|
return errors.Wrap(err, "could not save state")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Saves sidecar to the DB for the compatible block that contains the sidecar.
|
||||||
|
func (s *Service) saveSidecar(ctx context.Context, b interfaces.SignedBeaconBlock) error {
|
||||||
|
ok, err := blobs.BlockContainsSidecar(b)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "could not determine if block contains sidecar")
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
sc, err := b.SideCar()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "could not get sidecar")
|
||||||
|
}
|
||||||
|
return s.cfg.BeaconDB.SaveBlobsSidecar(ctx, sc.Message)
|
||||||
|
}
|
||||||
|
|
||||||
// This removes the attestations from the mem pool. It will only remove the attestations if input root `r` is canonical,
|
// This removes the attestations from the mem pool. It will only remove the attestations if input root `r` is canonical,
|
||||||
// meaning the block `b` is part of the canonical chain.
|
// meaning the block `b` is part of the canonical chain.
|
||||||
func (s *Service) pruneCanonicalAttsFromPool(ctx context.Context, r [32]byte, b interfaces.SignedBeaconBlock) error {
|
func (s *Service) pruneCanonicalAttsFromPool(ctx context.Context, r [32]byte, b interfaces.SignedBeaconBlock) error {
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ func (c *SyncCommitteeHeadStateCache) Get(slot types.Slot) (state.BeaconState, e
|
|||||||
return nil, ErrIncorrectType
|
return nil, ErrIncorrectType
|
||||||
}
|
}
|
||||||
switch st.Version() {
|
switch st.Version() {
|
||||||
case version.Altair, version.Bellatrix:
|
case version.Altair, version.Bellatrix, version.EIP4844:
|
||||||
default:
|
default:
|
||||||
return nil, ErrIncorrectType
|
return nil, ErrIncorrectType
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ func UpdateBalance(vp []*Validator, bBal *Balance, stateVersion int) *Balance {
|
|||||||
if stateVersion == version.Phase0 && v.IsPrevEpochAttester {
|
if stateVersion == version.Phase0 && v.IsPrevEpochAttester {
|
||||||
bBal.PrevEpochAttested += v.CurrentEpochEffectiveBalance
|
bBal.PrevEpochAttested += v.CurrentEpochEffectiveBalance
|
||||||
}
|
}
|
||||||
if (stateVersion == version.Altair || stateVersion == version.Bellatrix) && v.IsPrevEpochSourceAttester {
|
if (stateVersion == version.Altair || stateVersion == version.Bellatrix || stateVersion == version.EIP4844) && v.IsPrevEpochSourceAttester {
|
||||||
bBal.PrevEpochAttested += v.CurrentEpochEffectiveBalance
|
bBal.PrevEpochAttested += v.CurrentEpochEffectiveBalance
|
||||||
}
|
}
|
||||||
if v.IsPrevEpochTargetAttester {
|
if v.IsPrevEpochTargetAttester {
|
||||||
|
|||||||
@@ -83,3 +83,15 @@ func UpgradeToBellatrix(state state.BeaconState) (state.BeaconState, error) {
|
|||||||
|
|
||||||
return state_native.InitializeFromProtoUnsafeBellatrix(s)
|
return state_native.InitializeFromProtoUnsafeBellatrix(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpgradeToEip4844 updates inputs a generic state to return the version Eip4844 state.
|
||||||
|
func UpgradeToEip4844(state state.BeaconState) (state.BeaconState, error) {
|
||||||
|
if err := state.SetFork(ðpb.Fork{
|
||||||
|
PreviousVersion: state.Fork().CurrentVersion,
|
||||||
|
CurrentVersion: params.BeaconConfig().Eip4844ForkVersion,
|
||||||
|
Epoch: time.CurrentEpoch(state),
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return state, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -70,6 +70,12 @@ func CanUpgradeToBellatrix(slot types.Slot) bool {
|
|||||||
return epochStart && bellatrixEpoch
|
return epochStart && bellatrixEpoch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CanUpgradeToEip4844(slot types.Slot) bool {
|
||||||
|
epochStart := slots.IsEpochStart(slot)
|
||||||
|
e := slots.ToEpoch(slot) == params.BeaconConfig().Eip4844ForkEpoch
|
||||||
|
return epochStart && e
|
||||||
|
}
|
||||||
|
|
||||||
// CanProcessEpoch checks the eligibility to process epoch.
|
// CanProcessEpoch checks the eligibility to process epoch.
|
||||||
// The epoch can be processed at the end of the last slot of every epoch.
|
// The epoch can be processed at the end of the last slot of every epoch.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ go_library(
|
|||||||
"//beacon-chain/state/state-native:go_default_library",
|
"//beacon-chain/state/state-native:go_default_library",
|
||||||
"//beacon-chain/state/stateutil:go_default_library",
|
"//beacon-chain/state/stateutil:go_default_library",
|
||||||
"//config/params:go_default_library",
|
"//config/params:go_default_library",
|
||||||
|
"//consensus-types/blobs:go_default_library",
|
||||||
"//consensus-types/blocks:go_default_library",
|
"//consensus-types/blocks:go_default_library",
|
||||||
"//consensus-types/interfaces:go_default_library",
|
"//consensus-types/interfaces:go_default_library",
|
||||||
"//consensus-types/primitives:go_default_library",
|
"//consensus-types/primitives:go_default_library",
|
||||||
|
|||||||
@@ -255,7 +255,7 @@ func ProcessSlots(ctx context.Context, state state.BeaconState, slot types.Slot)
|
|||||||
tracing.AnnotateError(span, err)
|
tracing.AnnotateError(span, err)
|
||||||
return nil, errors.Wrap(err, "could not process epoch with optimizations")
|
return nil, errors.Wrap(err, "could not process epoch with optimizations")
|
||||||
}
|
}
|
||||||
case version.Altair, version.Bellatrix:
|
case version.Altair, version.Bellatrix, version.EIP4844:
|
||||||
state, err = altair.ProcessEpoch(ctx, state)
|
state, err = altair.ProcessEpoch(ctx, state)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tracing.AnnotateError(span, err)
|
tracing.AnnotateError(span, err)
|
||||||
@@ -285,6 +285,14 @@ func ProcessSlots(ctx context.Context, state state.BeaconState, slot types.Slot)
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if time.CanUpgradeToEip4844(state.Slot()) {
|
||||||
|
state, err = execution.UpgradeToEip4844(state)
|
||||||
|
if err != nil {
|
||||||
|
tracing.AnnotateError(span, err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if highestSlot < state.Slot() {
|
if highestSlot < state.Slot() {
|
||||||
|
|||||||
@@ -11,9 +11,11 @@ import (
|
|||||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/transition/interop"
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/transition/interop"
|
||||||
v "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/validators"
|
v "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/validators"
|
||||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/consensus-types/blobs"
|
||||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
||||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
||||||
"github.com/prysmaticlabs/prysm/v3/crypto/bls"
|
"github.com/prysmaticlabs/prysm/v3/crypto/bls"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||||
"github.com/prysmaticlabs/prysm/v3/monitoring/tracing"
|
"github.com/prysmaticlabs/prysm/v3/monitoring/tracing"
|
||||||
"github.com/prysmaticlabs/prysm/v3/runtime/version"
|
"github.com/prysmaticlabs/prysm/v3/runtime/version"
|
||||||
"go.opencensus.io/trace"
|
"go.opencensus.io/trace"
|
||||||
@@ -167,8 +169,14 @@ func ProcessBlockNoVerifyAnySig(
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if st.Version() != signed.Block().Version() {
|
sv := st.Version()
|
||||||
return nil, nil, fmt.Errorf("state and block are different version. %d != %d", st.Version(), signed.Block().Version())
|
bv := signed.Block().Version()
|
||||||
|
switch {
|
||||||
|
case sv == bv:
|
||||||
|
case sv == version.Bellatrix && bv == version.EIP4844:
|
||||||
|
// The EIP-4844 BeaconState is the same as Bellatrix's
|
||||||
|
default:
|
||||||
|
return nil, nil, fmt.Errorf("state and block are different version. %d != %d", sv, bv)
|
||||||
}
|
}
|
||||||
|
|
||||||
blk := signed.Block()
|
blk := signed.Block()
|
||||||
@@ -243,7 +251,7 @@ func ProcessOperationsNoVerifyAttsSigs(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
case version.Altair, version.Bellatrix:
|
case version.Altair, version.Bellatrix, version.EIP4844:
|
||||||
state, err = altairOperations(ctx, state, signedBeaconBlock)
|
state, err = altairOperations(ctx, state, signedBeaconBlock)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -255,6 +263,36 @@ func ProcessOperationsNoVerifyAttsSigs(
|
|||||||
return state, nil
|
return state, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ProcessBlobKzgs validates the blob kzgs in the beacon block.
|
||||||
|
// def process_blob_kzg_commitments(state: BeaconState, body: BeaconBlockBody):
|
||||||
|
// assert verify_kzg_commitments_against_transactions(body.execution_payload.transactions, body.blob_kzg_commitments
|
||||||
|
func ProcessBlobKzgs(ctx context.Context, state state.BeaconState, body interfaces.BeaconBlockBody) (state.BeaconState, error) {
|
||||||
|
_, span := trace.StartSpan(ctx, "core.state.ProocessBlobKzgs")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
|
payload, err := body.Execution()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not get execution payload from block")
|
||||||
|
}
|
||||||
|
blobKzgs, err := body.BlobKzgs()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not get blob kzgs from block")
|
||||||
|
}
|
||||||
|
blobKzgsInput := make([][48]byte, len(blobKzgs))
|
||||||
|
for i := range blobKzgs {
|
||||||
|
blobKzgsInput[i] = bytesutil.ToBytes48(blobKzgs[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
txs, err := payload.Transactions()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not get transactions from payload")
|
||||||
|
}
|
||||||
|
if err := blobs.VerifyKzgsAgainstTxs(txs, blobKzgsInput); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return state, nil
|
||||||
|
}
|
||||||
|
|
||||||
// ProcessBlockForStateRoot processes the state for state root computation. It skips proposer signature
|
// ProcessBlockForStateRoot processes the state for state root computation. It skips proposer signature
|
||||||
// and randao signature verifications.
|
// and randao signature verifications.
|
||||||
//
|
//
|
||||||
@@ -267,6 +305,7 @@ func ProcessOperationsNoVerifyAttsSigs(
|
|||||||
// process_eth1_data(state, block.body)
|
// process_eth1_data(state, block.body)
|
||||||
// process_operations(state, block.body)
|
// process_operations(state, block.body)
|
||||||
// process_sync_aggregate(state, block.body.sync_aggregate)
|
// process_sync_aggregate(state, block.body.sync_aggregate)
|
||||||
|
// process_blob_kzgs(state, block.body) # [New in EIP-4844]
|
||||||
func ProcessBlockForStateRoot(
|
func ProcessBlockForStateRoot(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
state state.BeaconState,
|
state state.BeaconState,
|
||||||
@@ -342,6 +381,15 @@ func ProcessBlockForStateRoot(
|
|||||||
return nil, errors.Wrap(err, "process_sync_aggregate failed")
|
return nil, errors.Wrap(err, "process_sync_aggregate failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if blocks.IsPreEIP4844Version(signed.Block().Version()) {
|
||||||
|
return state, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
state, err = ProcessBlobKzgs(ctx, state, signed.Block().Body())
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "process_blob_kzgs failed")
|
||||||
|
}
|
||||||
|
|
||||||
return state, nil
|
return state, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,10 @@ type ReadOnlyDatabase interface {
|
|||||||
GenesisBlockRoot(ctx context.Context) ([32]byte, error)
|
GenesisBlockRoot(ctx context.Context) ([32]byte, error)
|
||||||
IsFinalizedBlock(ctx context.Context, blockRoot [32]byte) bool
|
IsFinalizedBlock(ctx context.Context, blockRoot [32]byte) bool
|
||||||
FinalizedChildBlock(ctx context.Context, blockRoot [32]byte) (interfaces.SignedBeaconBlock, error)
|
FinalizedChildBlock(ctx context.Context, blockRoot [32]byte) (interfaces.SignedBeaconBlock, error)
|
||||||
|
// Blobs related methods.
|
||||||
|
BlobsSidecar(ctx context.Context, blockRoot [32]byte) (*ethpb.BlobsSidecar, error)
|
||||||
|
BlobsSidecarsBySlot(ctx context.Context, slot types.Slot) ([]*ethpb.BlobsSidecar, error)
|
||||||
|
HasBlobsSidecar(ctx context.Context, blockRoot [32]byte) bool
|
||||||
HighestRootsBelowSlot(ctx context.Context, slot types.Slot) (types.Slot, [][32]byte, error)
|
HighestRootsBelowSlot(ctx context.Context, slot types.Slot) (types.Slot, [][32]byte, error)
|
||||||
// State related methods.
|
// State related methods.
|
||||||
State(ctx context.Context, blockRoot [32]byte) (state.BeaconState, error)
|
State(ctx context.Context, blockRoot [32]byte) (state.BeaconState, error)
|
||||||
@@ -68,6 +72,9 @@ type NoHeadAccessDatabase interface {
|
|||||||
SaveBlock(ctx context.Context, block interfaces.SignedBeaconBlock) error
|
SaveBlock(ctx context.Context, block interfaces.SignedBeaconBlock) error
|
||||||
SaveBlocks(ctx context.Context, blocks []interfaces.SignedBeaconBlock) error
|
SaveBlocks(ctx context.Context, blocks []interfaces.SignedBeaconBlock) error
|
||||||
SaveGenesisBlockRoot(ctx context.Context, blockRoot [32]byte) error
|
SaveGenesisBlockRoot(ctx context.Context, blockRoot [32]byte) error
|
||||||
|
// Blob related methods.
|
||||||
|
SaveBlobsSidecar(ctx context.Context, blob *ethpb.BlobsSidecar) error
|
||||||
|
DeleteBlobsSidecar(ctx context.Context, blockRoot [32]byte) error
|
||||||
// State related methods.
|
// State related methods.
|
||||||
SaveState(ctx context.Context, state state.ReadOnlyBeaconState, blockRoot [32]byte) error
|
SaveState(ctx context.Context, state state.ReadOnlyBeaconState, blockRoot [32]byte) error
|
||||||
SaveStates(ctx context.Context, states []state.ReadOnlyBeaconState, blockRoots [][32]byte) error
|
SaveStates(ctx context.Context, states []state.ReadOnlyBeaconState, blockRoots [][32]byte) error
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ go_library(
|
|||||||
srcs = [
|
srcs = [
|
||||||
"archived_point.go",
|
"archived_point.go",
|
||||||
"backup.go",
|
"backup.go",
|
||||||
|
"blobs.go",
|
||||||
"blocks.go",
|
"blocks.go",
|
||||||
"checkpoint.go",
|
"checkpoint.go",
|
||||||
"deposit_contract.go",
|
"deposit_contract.go",
|
||||||
|
|||||||
180
beacon-chain/db/kv/blobs.go
Normal file
180
beacon-chain/db/kv/blobs.go
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
package kv
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||||
|
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||||
|
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||||
|
bolt "go.etcd.io/bbolt"
|
||||||
|
"go.opencensus.io/trace"
|
||||||
|
)
|
||||||
|
|
||||||
|
const blobSidecarKeyLength = 48 // slot_to_rotating_buffer(blob.slot) ++ blob.slot ++ blob.block_root
|
||||||
|
|
||||||
|
// SaveBlobsSidecar saves the blobs for a given epoch in the sidecar bucket. When we receive a blob:
|
||||||
|
// 1. Convert slot using a modulo operator to [0, maxSlots] where maxSlots = MAX_BLOB_EPOCHS*SLOTS_PER_EPOCH
|
||||||
|
// 2. Compute key for blob as bytes(slot_to_rotating_buffer(blob.slot)) ++ bytes(blob.slot) ++ blob.block_root
|
||||||
|
// 3. Begin the save algorithm: If the incoming blob has a slot bigger than the saved slot at the spot
|
||||||
|
// in the rotating keys buffer, we overwrite all elements for that slot.
|
||||||
|
//
|
||||||
|
// firstElemKey = getFirstElement(bucket)
|
||||||
|
// shouldOverwrite = blob.slot > bytes_to_slot(firstElemKey[8:16])
|
||||||
|
// if shouldOverwrite:
|
||||||
|
// for existingKey := seek prefix bytes(slot_to_rotating_buffer(blob.slot))
|
||||||
|
// bucket.delete(existingKey)
|
||||||
|
// bucket.put(key, blob)
|
||||||
|
func (s *Store) SaveBlobsSidecar(ctx context.Context, blobSidecar *ethpb.BlobsSidecar) error {
|
||||||
|
ctx, span := trace.StartSpan(ctx, "BeaconDB.SaveBlobsSidecar")
|
||||||
|
defer span.End()
|
||||||
|
return s.db.Update(func(tx *bolt.Tx) error {
|
||||||
|
encodedBlobSidecar, err := encode(ctx, blobSidecar)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
bkt := tx.Bucket(blobsBucket)
|
||||||
|
c := bkt.Cursor()
|
||||||
|
key := blobSidecarKey(blobSidecar)
|
||||||
|
rotatingBufferPrefix := key[0:8]
|
||||||
|
var firstElementKey []byte
|
||||||
|
for k, _ := c.Seek(rotatingBufferPrefix); bytes.HasPrefix(k, rotatingBufferPrefix); k, _ = c.Next() {
|
||||||
|
if len(k) != 0 {
|
||||||
|
firstElementKey = k
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If there is no element stored at blob.slot % MAX_SLOTS_TO_PERSIST_BLOBS, then we simply
|
||||||
|
// store the blob by key and exit early.
|
||||||
|
if len(firstElementKey) == 0 {
|
||||||
|
return bkt.Put(key, encodedBlobSidecar)
|
||||||
|
} else if len(firstElementKey) != len(key) {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"key length %d (%#x) != existing key length %d (%#x)",
|
||||||
|
len(key),
|
||||||
|
key,
|
||||||
|
len(firstElementKey),
|
||||||
|
firstElementKey,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
slotOfFirstElement := firstElementKey[8:16]
|
||||||
|
// If we should overwrite old blobs at the spot in the rotating buffer, we clear data at that spot.
|
||||||
|
shouldOverwrite := blobSidecar.BeaconBlockSlot > bytesutil.BytesToSlotBigEndian(slotOfFirstElement)
|
||||||
|
if shouldOverwrite {
|
||||||
|
for k, _ := c.Seek(rotatingBufferPrefix); bytes.HasPrefix(k, rotatingBufferPrefix); k, _ = c.Next() {
|
||||||
|
if err := bkt.Delete(k); err != nil {
|
||||||
|
log.Warnf("Could not delete blob with key %#x: %v", k, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bkt.Put(key, encodedBlobSidecar)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// BlobsSidecar retrieves the blobs given a beacon block root.
|
||||||
|
func (s *Store) BlobsSidecar(ctx context.Context, beaconBlockRoot [32]byte) (*ethpb.BlobsSidecar, error) {
|
||||||
|
ctx, span := trace.StartSpan(ctx, "BeaconDB.BlobsSidecar")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
|
var enc []byte
|
||||||
|
if err := s.db.View(func(tx *bolt.Tx) error {
|
||||||
|
c := tx.Bucket(blobsBucket).Cursor()
|
||||||
|
// Bucket size is bounded and bolt cursors are fast. Moreover, a thin caching layer can be added.
|
||||||
|
for k, v := c.First(); k != nil; k, v = c.Next() {
|
||||||
|
if bytes.HasSuffix(k, beaconBlockRoot[:]) {
|
||||||
|
enc = v
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(enc) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
blob := ðpb.BlobsSidecar{}
|
||||||
|
if err := decode(ctx, enc, blob); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return blob, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// BlobsSidecarsBySlot retrieves sidecars from a slot.
|
||||||
|
func (s *Store) BlobsSidecarsBySlot(ctx context.Context, slot types.Slot) ([]*ethpb.BlobsSidecar, error) {
|
||||||
|
ctx, span := trace.StartSpan(ctx, "BeaconDB.BlobsSidecarsBySlot")
|
||||||
|
defer span.End()
|
||||||
|
encodedItems := make([][]byte, 0)
|
||||||
|
if err := s.db.View(func(tx *bolt.Tx) error {
|
||||||
|
c := tx.Bucket(blobsBucket).Cursor()
|
||||||
|
// Bucket size is bounded and bolt cursors are fast. Moreover, a thin caching layer can be added.
|
||||||
|
for k, v := c.First(); k != nil; k, v = c.Next() {
|
||||||
|
if len(k) != blobSidecarKeyLength {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
slotInKey := bytesutil.BytesToSlotBigEndian(k[8:16])
|
||||||
|
if slotInKey == slot {
|
||||||
|
encodedItems = append(encodedItems, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sidecars := make([]*ethpb.BlobsSidecar, len(encodedItems))
|
||||||
|
if len(encodedItems) == 0 {
|
||||||
|
return sidecars, nil
|
||||||
|
}
|
||||||
|
for i, enc := range encodedItems {
|
||||||
|
blob := ðpb.BlobsSidecar{}
|
||||||
|
if err := decode(ctx, enc, blob); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sidecars[i] = blob
|
||||||
|
}
|
||||||
|
return sidecars, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasBlobsSidecar returns true if the blobs are in the db.
|
||||||
|
func (s *Store) HasBlobsSidecar(ctx context.Context, beaconBlockRoot [32]byte) bool {
|
||||||
|
ctx, span := trace.StartSpan(ctx, "BeaconDB.HasBlobsSidecar")
|
||||||
|
defer span.End()
|
||||||
|
blobSidecar, err := s.BlobsSidecar(ctx, beaconBlockRoot)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return blobSidecar != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteBlobsSidecar returns true if the blobs are in the db.
|
||||||
|
func (s *Store) DeleteBlobsSidecar(ctx context.Context, beaconBlockRoot [32]byte) error {
|
||||||
|
ctx, span := trace.StartSpan(ctx, "BeaconDB.DeleteBlobsSidecar")
|
||||||
|
defer span.End()
|
||||||
|
return s.db.Update(func(tx *bolt.Tx) error {
|
||||||
|
bkt := tx.Bucket(blobsBucket)
|
||||||
|
c := bkt.Cursor()
|
||||||
|
for k, _ := c.First(); k != nil; k, _ = c.Next() {
|
||||||
|
if bytes.HasSuffix(k, beaconBlockRoot[:]) {
|
||||||
|
if err := bkt.Delete(k); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// We define a blob sidecar key as: bytes(slot_to_rotating_buffer(blob.slot)) ++ bytes(blob.slot) ++ blob.block_root
|
||||||
|
// where slot_to_rotating_buffer(slot) = slot % MAX_SLOTS_TO_PERSIST_BLOBS.
|
||||||
|
func blobSidecarKey(blob *ethpb.BlobsSidecar) []byte {
|
||||||
|
slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch
|
||||||
|
maxEpochsToPersistBlobs := params.BeaconNetworkConfig().MinEpochsForBlobsSidecarsRequest
|
||||||
|
maxSlotsToPersistBlobs := types.Slot(maxEpochsToPersistBlobs.Mul(uint64(slotsPerEpoch)))
|
||||||
|
slotInRotatingBuffer := blob.BeaconBlockSlot.ModSlot(maxSlotsToPersistBlobs)
|
||||||
|
key := bytesutil.SlotToBytesBigEndian(slotInRotatingBuffer)
|
||||||
|
key = append(key, bytesutil.SlotToBytesBigEndian(blob.BeaconBlockSlot)...)
|
||||||
|
key = append(key, blob.BeaconBlockRoot...)
|
||||||
|
return key
|
||||||
|
}
|
||||||
101
beacon-chain/db/kv/blobs_test.go
Normal file
101
beacon-chain/db/kv/blobs_test.go
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
package kv
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||||
|
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||||
|
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||||
|
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/testing/require"
|
||||||
|
bolt "go.etcd.io/bbolt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBlobsSidecar_Overwriting(t *testing.T) {
|
||||||
|
params.SetupTestConfigCleanup(t)
|
||||||
|
cfg := params.BeaconNetworkConfig()
|
||||||
|
// For purposes of testing, we only keep blob sidecars around for 2 epochs. At third epoch, we will
|
||||||
|
// wrap around and overwrite the oldest epoch's elements as the keys for blobs work as a rotating buffer.
|
||||||
|
cfg.MinEpochsForBlobsSidecarsRequest = 2
|
||||||
|
params.OverrideBeaconNetworkConfig(cfg)
|
||||||
|
db := setupDB(t)
|
||||||
|
|
||||||
|
sidecars := make([]*ethpb.BlobsSidecar, 0)
|
||||||
|
numSlots := uint64(cfg.MinEpochsForBlobsSidecarsRequest) * uint64(params.BeaconConfig().SlotsPerEpoch)
|
||||||
|
for i := uint64(0); i < numSlots; i++ {
|
||||||
|
// There can be multiple blobs per slot with different block roots, so we create some
|
||||||
|
// in order to have a thorough test.
|
||||||
|
root1 := bytesutil.ToBytes32([]byte(fmt.Sprintf("foo-%d", i)))
|
||||||
|
root2 := bytesutil.ToBytes32([]byte(fmt.Sprintf("bar-%d", i)))
|
||||||
|
sidecars = append(sidecars, ðpb.BlobsSidecar{
|
||||||
|
BeaconBlockRoot: root1[:],
|
||||||
|
BeaconBlockSlot: types.Slot(i),
|
||||||
|
Blobs: make([]*enginev1.Blob, 0),
|
||||||
|
AggregatedProof: make([]byte, 48),
|
||||||
|
})
|
||||||
|
sidecars = append(sidecars, ðpb.BlobsSidecar{
|
||||||
|
BeaconBlockRoot: root2[:],
|
||||||
|
BeaconBlockSlot: types.Slot(i),
|
||||||
|
Blobs: make([]*enginev1.Blob, 0),
|
||||||
|
AggregatedProof: make([]byte, 48),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
ctx := context.Background()
|
||||||
|
for _, blobSidecar := range sidecars {
|
||||||
|
require.NoError(t, db.SaveBlobsSidecar(ctx, blobSidecar))
|
||||||
|
require.Equal(t, true, db.HasBlobsSidecar(ctx, bytesutil.ToBytes32(blobSidecar.BeaconBlockRoot)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// We check there are only two blob sidecars stored at slot 0, as an example.
|
||||||
|
keyPrefix := append(bytesutil.SlotToBytesBigEndian(0), bytesutil.SlotToBytesBigEndian(0)...)
|
||||||
|
numBlobs := countBlobsWithPrefix(t, db, keyPrefix)
|
||||||
|
require.Equal(t, 2, numBlobs)
|
||||||
|
|
||||||
|
// Attempting to save another blob sidecar with slot 0 and a new block root should result
|
||||||
|
// in three blob sidecars stored at slot 0. This means we are NOT overwriting old data.
|
||||||
|
root := bytesutil.ToBytes32([]byte("baz-0"))
|
||||||
|
sidecar := ðpb.BlobsSidecar{
|
||||||
|
BeaconBlockRoot: root[:],
|
||||||
|
BeaconBlockSlot: types.Slot(0),
|
||||||
|
Blobs: make([]*enginev1.Blob, 0),
|
||||||
|
AggregatedProof: make([]byte, 48),
|
||||||
|
}
|
||||||
|
require.NoError(t, db.SaveBlobsSidecar(ctx, sidecar))
|
||||||
|
require.Equal(t, true, db.HasBlobsSidecar(ctx, bytesutil.ToBytes32(sidecar.BeaconBlockRoot)))
|
||||||
|
|
||||||
|
numBlobs = countBlobsWithPrefix(t, db, keyPrefix)
|
||||||
|
require.Equal(t, 3, numBlobs)
|
||||||
|
|
||||||
|
// Now, we attempt to save a blob sidecar with slot = MAX_SLOTS_TO_PERSIST_BLOBS. This SHOULD cause us to
|
||||||
|
// overwrite ALL old data at slot 0, as slot % MAX_SLOTS_TO_PERSIST_BLOBS will be equal to 0.
|
||||||
|
// We should expect a single blob sidecar to exist at slot 0 after this operation.
|
||||||
|
root = bytesutil.ToBytes32([]byte(fmt.Sprintf("foo-%d", numSlots)))
|
||||||
|
sidecar = ðpb.BlobsSidecar{
|
||||||
|
BeaconBlockRoot: root[:],
|
||||||
|
BeaconBlockSlot: types.Slot(numSlots),
|
||||||
|
Blobs: make([]*enginev1.Blob, 0),
|
||||||
|
AggregatedProof: make([]byte, 48),
|
||||||
|
}
|
||||||
|
require.NoError(t, db.SaveBlobsSidecar(ctx, sidecar))
|
||||||
|
require.Equal(t, true, db.HasBlobsSidecar(ctx, bytesutil.ToBytes32(sidecar.BeaconBlockRoot)))
|
||||||
|
|
||||||
|
keyPrefix = append(bytesutil.SlotToBytesBigEndian(0), bytesutil.SlotToBytesBigEndian(64)...)
|
||||||
|
numBlobs = countBlobsWithPrefix(t, db, keyPrefix)
|
||||||
|
require.Equal(t, 1, numBlobs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func countBlobsWithPrefix(t *testing.T, db *Store, prefix []byte) int {
|
||||||
|
numBlobSidecars := 0
|
||||||
|
require.NoError(t, db.db.View(func(tx *bolt.Tx) error {
|
||||||
|
c := tx.Bucket(blobsBucket).Cursor()
|
||||||
|
for k, _ := c.Seek(prefix); bytes.HasPrefix(k, prefix); k, _ = c.Next() {
|
||||||
|
numBlobSidecars++
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}))
|
||||||
|
return numBlobSidecars
|
||||||
|
}
|
||||||
@@ -241,6 +241,10 @@ func (s *Store) DeleteBlock(ctx context.Context, root [32]byte) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := s.DeleteBlobsSidecar(ctx, root); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return s.db.Update(func(tx *bolt.Tx) error {
|
return s.db.Update(func(tx *bolt.Tx) error {
|
||||||
bkt := tx.Bucket(finalizedBlockRootsIndexBucket)
|
bkt := tx.Bucket(finalizedBlockRootsIndexBucket)
|
||||||
if b := bkt.Get(root[:]); b != nil {
|
if b := bkt.Get(root[:]); b != nil {
|
||||||
@@ -789,6 +793,11 @@ func unmarshalBlock(_ context.Context, enc []byte) (interfaces.SignedBeaconBlock
|
|||||||
if err := rawBlock.UnmarshalSSZ(enc[len(bellatrixBlindKey):]); err != nil {
|
if err := rawBlock.UnmarshalSSZ(enc[len(bellatrixBlindKey):]); err != nil {
|
||||||
return nil, errors.Wrap(err, "could not unmarshal blinded Bellatrix block")
|
return nil, errors.Wrap(err, "could not unmarshal blinded Bellatrix block")
|
||||||
}
|
}
|
||||||
|
case hasEip4844Key(enc):
|
||||||
|
rawBlock = ðpb.SignedBeaconBlockWithBlobKZGs{}
|
||||||
|
if err := rawBlock.UnmarshalSSZ(enc[len(eip4844Key):]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
// Marshal block bytes to phase 0 beacon block.
|
// Marshal block bytes to phase 0 beacon block.
|
||||||
rawBlock = ðpb.SignedBeaconBlock{}
|
rawBlock = ðpb.SignedBeaconBlock{}
|
||||||
@@ -828,6 +837,8 @@ func marshalBlock(_ context.Context, blk interfaces.SignedBeaconBlock) ([]byte,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch blockToSave.Version() {
|
switch blockToSave.Version() {
|
||||||
|
case version.EIP4844:
|
||||||
|
return snappy.Encode(nil, append(eip4844Key, encodedBlock...)), nil
|
||||||
case version.Bellatrix:
|
case version.Bellatrix:
|
||||||
if blockToSave.IsBlinded() {
|
if blockToSave.IsBlinded() {
|
||||||
return snappy.Encode(nil, append(bellatrixBlindKey, encodedBlock...)), nil
|
return snappy.Encode(nil, append(bellatrixBlindKey, encodedBlock...)), nil
|
||||||
|
|||||||
@@ -23,3 +23,10 @@ func hasBellatrixBlindKey(enc []byte) bool {
|
|||||||
}
|
}
|
||||||
return bytes.Equal(enc[:len(bellatrixBlindKey)], bellatrixBlindKey)
|
return bytes.Equal(enc[:len(bellatrixBlindKey)], bellatrixBlindKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func hasEip4844Key(enc []byte) bool {
|
||||||
|
if len(eip4844Key) >= len(enc) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return bytes.Equal(enc[:len(eip4844Key)], eip4844Key)
|
||||||
|
}
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ var BlockCacheSize = int64(1 << 21)
|
|||||||
// summary, it can be read in https://github.com/prysmaticlabs/prysm/issues/8274.
|
// summary, it can be read in https://github.com/prysmaticlabs/prysm/issues/8274.
|
||||||
var blockedBuckets = [][]byte{
|
var blockedBuckets = [][]byte{
|
||||||
blocksBucket,
|
blocksBucket,
|
||||||
|
blobsBucket,
|
||||||
stateSummaryBucket,
|
stateSummaryBucket,
|
||||||
blockParentRootIndicesBucket,
|
blockParentRootIndicesBucket,
|
||||||
blockSlotIndicesBucket,
|
blockSlotIndicesBucket,
|
||||||
@@ -159,6 +160,8 @@ func NewKVStore(ctx context.Context, dirPath string) (*Store, error) {
|
|||||||
tx,
|
tx,
|
||||||
attestationsBucket,
|
attestationsBucket,
|
||||||
blocksBucket,
|
blocksBucket,
|
||||||
|
blobsBucket,
|
||||||
|
blobsAgesBucket,
|
||||||
stateBucket,
|
stateBucket,
|
||||||
proposerSlashingsBucket,
|
proposerSlashingsBucket,
|
||||||
attesterSlashingsBucket,
|
attesterSlashingsBucket,
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ package kv
|
|||||||
var (
|
var (
|
||||||
attestationsBucket = []byte("attestations")
|
attestationsBucket = []byte("attestations")
|
||||||
blocksBucket = []byte("blocks")
|
blocksBucket = []byte("blocks")
|
||||||
|
blobsBucket = []byte("blobs")
|
||||||
|
blobsAgesBucket = []byte("blobs-ages")
|
||||||
stateBucket = []byte("state")
|
stateBucket = []byte("state")
|
||||||
stateSummaryBucket = []byte("state-summary")
|
stateSummaryBucket = []byte("state-summary")
|
||||||
proposerSlashingsBucket = []byte("proposer-slashings")
|
proposerSlashingsBucket = []byte("proposer-slashings")
|
||||||
@@ -52,6 +54,7 @@ var (
|
|||||||
altairKey = []byte("altair")
|
altairKey = []byte("altair")
|
||||||
bellatrixKey = []byte("merge")
|
bellatrixKey = []byte("merge")
|
||||||
bellatrixBlindKey = []byte("blind-bellatrix")
|
bellatrixBlindKey = []byte("blind-bellatrix")
|
||||||
|
eip4844Key = []byte("eip4844")
|
||||||
// block root included in the beacon state used by weak subjectivity initial sync
|
// block root included in the beacon state used by weak subjectivity initial sync
|
||||||
originCheckpointBlockRootKey = []byte("origin-checkpoint-block-root")
|
originCheckpointBlockRootKey = []byte("origin-checkpoint-block-root")
|
||||||
// block root tracking the progress of backfill, or pointing at genesis if backfill has not been initiated
|
// block root tracking the progress of backfill, or pointing at genesis if backfill has not been initiated
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ const (
|
|||||||
ForkchoiceUpdatedMethod = "engine_forkchoiceUpdatedV1"
|
ForkchoiceUpdatedMethod = "engine_forkchoiceUpdatedV1"
|
||||||
// GetPayloadMethod v1 request string for JSON-RPC.
|
// GetPayloadMethod v1 request string for JSON-RPC.
|
||||||
GetPayloadMethod = "engine_getPayloadV1"
|
GetPayloadMethod = "engine_getPayloadV1"
|
||||||
|
// GetBlobsBundleMethod v1 request string for JSON-RPC.
|
||||||
|
GetBlobsBundleMethod = "engine_getBlobsBundleV1"
|
||||||
// ExchangeTransitionConfigurationMethod v1 request string for JSON-RPC.
|
// ExchangeTransitionConfigurationMethod v1 request string for JSON-RPC.
|
||||||
ExchangeTransitionConfigurationMethod = "engine_exchangeTransitionConfigurationV1"
|
ExchangeTransitionConfigurationMethod = "engine_exchangeTransitionConfigurationV1"
|
||||||
// ExecutionBlockByHashMethod request string for JSON-RPC.
|
// ExecutionBlockByHashMethod request string for JSON-RPC.
|
||||||
@@ -75,6 +77,7 @@ type EngineCaller interface {
|
|||||||
) error
|
) error
|
||||||
ExecutionBlockByHash(ctx context.Context, hash common.Hash, withTxs bool) (*pb.ExecutionBlock, error)
|
ExecutionBlockByHash(ctx context.Context, hash common.Hash, withTxs bool) (*pb.ExecutionBlock, error)
|
||||||
GetTerminalBlockHash(ctx context.Context, transitionTime uint64) ([]byte, bool, error)
|
GetTerminalBlockHash(ctx context.Context, transitionTime uint64) ([]byte, bool, error)
|
||||||
|
GetBlobsBundle(ctx context.Context, payloadId [8]byte) (*pb.BlobsBundle, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPayload calls the engine_newPayloadV1 method via JSON-RPC.
|
// NewPayload calls the engine_newPayloadV1 method via JSON-RPC.
|
||||||
@@ -319,6 +322,19 @@ func (s *Service) ExecutionBlockByHash(ctx context.Context, hash common.Hash, wi
|
|||||||
return result, handleRPCError(err)
|
return result, handleRPCError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetBlobsBundle calls the engine_getBlobsV1 method via JSON-RPC.
|
||||||
|
func (s *Service) GetBlobsBundle(ctx context.Context, payloadId [8]byte) (*pb.BlobsBundle, error) {
|
||||||
|
ctx, span := trace.StartSpan(ctx, "powchain.engine-api-client.GetBlobsBundle")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
|
d := time.Now().Add(defaultEngineTimeout)
|
||||||
|
ctx, cancel := context.WithDeadline(ctx, d)
|
||||||
|
defer cancel()
|
||||||
|
result := &pb.BlobsBundle{}
|
||||||
|
err := s.rpcClient.CallContext(ctx, result, GetBlobsBundleMethod, pb.PayloadIDBytes(payloadId))
|
||||||
|
return result, handleRPCError(err)
|
||||||
|
}
|
||||||
|
|
||||||
// ExecutionBlocksByHashes fetches a batch of execution engine blocks by hash by calling
|
// ExecutionBlocksByHashes fetches a batch of execution engine blocks by hash by calling
|
||||||
// eth_blockByHash via JSON-RPC.
|
// eth_blockByHash via JSON-RPC.
|
||||||
func (s *Service) ExecutionBlocksByHashes(ctx context.Context, hashes []common.Hash, withTxs bool) ([]*pb.ExecutionBlock, error) {
|
func (s *Service) ExecutionBlocksByHashes(ctx context.Context, hashes []common.Hash, withTxs bool) ([]*pb.ExecutionBlock, error) {
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ type EngineClient struct {
|
|||||||
TerminalBlockHash []byte
|
TerminalBlockHash []byte
|
||||||
TerminalBlockHashExists bool
|
TerminalBlockHashExists bool
|
||||||
OverrideValidHash [32]byte
|
OverrideValidHash [32]byte
|
||||||
|
BlobsBundle *pb.BlobsBundle
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPayload --
|
// NewPayload --
|
||||||
@@ -158,3 +159,8 @@ func (e *EngineClient) GetTerminalBlockHash(ctx context.Context, transitionTime
|
|||||||
blk = parentBlk
|
blk = parentBlk
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetBlobsBundle --
|
||||||
|
func (e *EngineClient) GetBlobsBundle(ctx context.Context, payloadId [8]byte) (*pb.BlobsBundle, error) {
|
||||||
|
return e.BlobsBundle, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -394,6 +394,18 @@ func (f *ForkChoice) SetOptimisticToValid(ctx context.Context, root [fieldparams
|
|||||||
return node.setNodeAndParentValidated(ctx)
|
return node.setNodeAndParentValidated(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetValidData sets the node with the given root as a data available node
|
||||||
|
func (f *ForkChoice) SetValidData(ctx context.Context, root [fieldparams.RootLength]byte) error {
|
||||||
|
f.store.nodesLock.Lock()
|
||||||
|
defer f.store.nodesLock.Unlock()
|
||||||
|
node, ok := f.store.nodeByRoot[root]
|
||||||
|
if !ok || node == nil {
|
||||||
|
return errors.Wrap(ErrNilNode, "could not set node to valid data")
|
||||||
|
}
|
||||||
|
node.validData = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// BestJustifiedCheckpoint of fork choice store.
|
// BestJustifiedCheckpoint of fork choice store.
|
||||||
func (f *ForkChoice) BestJustifiedCheckpoint() *forkchoicetypes.Checkpoint {
|
func (f *ForkChoice) BestJustifiedCheckpoint() *forkchoicetypes.Checkpoint {
|
||||||
f.store.checkpointsLock.RLock()
|
f.store.checkpointsLock.RLock()
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ func (n *Node) updateBestDescendant(ctx context.Context, justifiedEpoch, finaliz
|
|||||||
if err := child.updateBestDescendant(ctx, justifiedEpoch, finalizedEpoch, currentEpoch); err != nil {
|
if err := child.updateBestDescendant(ctx, justifiedEpoch, finalizedEpoch, currentEpoch); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
childLeadsToViableHead := child.leadsToViableHead(justifiedEpoch, finalizedEpoch, currentEpoch)
|
childLeadsToViableHead := child.leadsToViableHead(justifiedEpoch, finalizedEpoch, currentEpoch)
|
||||||
if childLeadsToViableHead && !hasViableDescendant {
|
if childLeadsToViableHead && !hasViableDescendant {
|
||||||
// The child leads to a viable head, but the current
|
// The child leads to a viable head, but the current
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ func (s *Store) insert(ctx context.Context,
|
|||||||
slot types.Slot,
|
slot types.Slot,
|
||||||
root, parentRoot, payloadHash [fieldparams.RootLength]byte,
|
root, parentRoot, payloadHash [fieldparams.RootLength]byte,
|
||||||
justifiedEpoch, finalizedEpoch types.Epoch) (*Node, error) {
|
justifiedEpoch, finalizedEpoch types.Epoch) (*Node, error) {
|
||||||
ctx, span := trace.StartSpan(ctx, "doublyLinkedForkchoice.insert")
|
_, span := trace.StartSpan(ctx, "doublyLinkedForkchoice.insert")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
s.nodesLock.Lock()
|
s.nodesLock.Lock()
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ type Node struct {
|
|||||||
weight uint64 // weight of this node: the total balance including children
|
weight uint64 // weight of this node: the total balance including children
|
||||||
bestDescendant *Node // bestDescendant node of this node.
|
bestDescendant *Node // bestDescendant node of this node.
|
||||||
optimistic bool // whether the block has been fully validated or not
|
optimistic bool // whether the block has been fully validated or not
|
||||||
|
validData bool // whether the block has valid data or not
|
||||||
timestamp uint64 // The timestamp when the node was inserted.
|
timestamp uint64 // The timestamp when the node was inserted.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ type Getter interface {
|
|||||||
type Setter interface {
|
type Setter interface {
|
||||||
SetOptimisticToValid(context.Context, [fieldparams.RootLength]byte) error
|
SetOptimisticToValid(context.Context, [fieldparams.RootLength]byte) error
|
||||||
SetOptimisticToInvalid(context.Context, [fieldparams.RootLength]byte, [fieldparams.RootLength]byte, [fieldparams.RootLength]byte) ([][32]byte, error)
|
SetOptimisticToInvalid(context.Context, [fieldparams.RootLength]byte, [fieldparams.RootLength]byte, [fieldparams.RootLength]byte) ([][32]byte, error)
|
||||||
|
SetValidData(context.Context, [fieldparams.RootLength]byte) error
|
||||||
UpdateJustifiedCheckpoint(*forkchoicetypes.Checkpoint) error
|
UpdateJustifiedCheckpoint(*forkchoicetypes.Checkpoint) error
|
||||||
UpdateFinalizedCheckpoint(*forkchoicetypes.Checkpoint) error
|
UpdateFinalizedCheckpoint(*forkchoicetypes.Checkpoint) error
|
||||||
SetGenesisTime(uint64)
|
SetGenesisTime(uint64)
|
||||||
|
|||||||
@@ -242,6 +242,21 @@ func (f *ForkChoice) HasParent(root [32]byte) bool {
|
|||||||
return f.store.nodes[i].parent != NonExistentNode
|
return f.store.nodes[i].parent != NonExistentNode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetValidData sets the node with the given root as a data available node
|
||||||
|
func (f *ForkChoice) SetValidData(ctx context.Context, root [32]byte) error {
|
||||||
|
f.store.nodesLock.RLock()
|
||||||
|
defer f.store.nodesLock.RUnlock()
|
||||||
|
|
||||||
|
i, ok := f.store.nodesIndices[root]
|
||||||
|
if !ok || i >= uint64(len(f.store.nodes)) {
|
||||||
|
return ErrUnknownNodeRoot
|
||||||
|
}
|
||||||
|
|
||||||
|
f.store.nodes[i].validData = true
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// IsCanonical returns true if the given root is part of the canonical chain.
|
// IsCanonical returns true if the given root is part of the canonical chain.
|
||||||
func (f *ForkChoice) IsCanonical(root [32]byte) bool {
|
func (f *ForkChoice) IsCanonical(root [32]byte) bool {
|
||||||
f.store.nodesLock.RLock()
|
f.store.nodesLock.RLock()
|
||||||
@@ -489,7 +504,7 @@ func (s *Store) insert(ctx context.Context,
|
|||||||
slot types.Slot,
|
slot types.Slot,
|
||||||
root, parent, payloadHash [32]byte,
|
root, parent, payloadHash [32]byte,
|
||||||
justifiedEpoch, finalizedEpoch types.Epoch) (*Node, error) {
|
justifiedEpoch, finalizedEpoch types.Epoch) (*Node, error) {
|
||||||
ctx, span := trace.StartSpan(ctx, "protoArrayForkChoice.insert")
|
_, span := trace.StartSpan(ctx, "protoArrayForkChoice.insert")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
s.nodesLock.Lock()
|
s.nodesLock.Lock()
|
||||||
@@ -704,6 +719,10 @@ func (s *Store) updateBestChildAndDescendant(parentIndex, childIndex uint64) err
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// optimization: only run DA checks if viable
|
||||||
|
if childLeadsToViableHead {
|
||||||
|
childLeadsToViableHead = false
|
||||||
|
}
|
||||||
|
|
||||||
// Define 3 variables for the 3 outcomes mentioned above. This is to
|
// Define 3 variables for the 3 outcomes mentioned above. This is to
|
||||||
// set `parent.bestChild` and `parent.bestDescendant` to. These
|
// set `parent.bestChild` and `parent.bestDescendant` to. These
|
||||||
@@ -886,6 +905,7 @@ func (s *Store) viableForHead(node *Node) bool {
|
|||||||
// It's also viable if we are in genesis epoch.
|
// It's also viable if we are in genesis epoch.
|
||||||
justified := s.justifiedCheckpoint.Epoch == node.justifiedEpoch || s.justifiedCheckpoint.Epoch == 0
|
justified := s.justifiedCheckpoint.Epoch == node.justifiedEpoch || s.justifiedCheckpoint.Epoch == 0
|
||||||
finalized := s.finalizedCheckpoint.Epoch == node.finalizedEpoch || s.finalizedCheckpoint.Epoch == 0
|
finalized := s.finalizedCheckpoint.Epoch == node.finalizedEpoch || s.finalizedCheckpoint.Epoch == 0
|
||||||
|
|
||||||
if features.Get().EnableDefensivePull {
|
if features.Get().EnableDefensivePull {
|
||||||
currentEpoch := slots.EpochsSinceGenesis(time.Unix(int64(s.genesisTime), 0))
|
currentEpoch := slots.EpochsSinceGenesis(time.Unix(int64(s.genesisTime), 0))
|
||||||
if !justified && s.justifiedCheckpoint.Epoch+1 == currentEpoch {
|
if !justified && s.justifiedCheckpoint.Epoch+1 == currentEpoch {
|
||||||
@@ -897,7 +917,7 @@ func (s *Store) viableForHead(node *Node) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return justified && finalized
|
return justified && finalized && node.validData
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tips returns all possible chain heads (leaves of fork choice tree).
|
// Tips returns all possible chain heads (leaves of fork choice tree).
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ type Node struct {
|
|||||||
bestChild uint64 // bestChild index of this node.
|
bestChild uint64 // bestChild index of this node.
|
||||||
bestDescendant uint64 // bestDescendant of this node.
|
bestDescendant uint64 // bestDescendant of this node.
|
||||||
status status // optimistic status of this node
|
status status // optimistic status of this node
|
||||||
|
validData bool // whether the block has valid data or not.
|
||||||
}
|
}
|
||||||
|
|
||||||
// enum used as optimistic status of a node
|
// enum used as optimistic status of a node
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ go_library(
|
|||||||
],
|
],
|
||||||
deps = [
|
deps = [
|
||||||
"//api/gateway:go_default_library",
|
"//api/gateway:go_default_library",
|
||||||
|
"//async:go_default_library",
|
||||||
"//async/event:go_default_library",
|
"//async/event:go_default_library",
|
||||||
"//beacon-chain/blockchain:go_default_library",
|
"//beacon-chain/blockchain:go_default_library",
|
||||||
"//beacon-chain/builder:go_default_library",
|
"//beacon-chain/builder:go_default_library",
|
||||||
|
|||||||
@@ -14,10 +14,12 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
apigateway "github.com/prysmaticlabs/prysm/v3/api/gateway"
|
apigateway "github.com/prysmaticlabs/prysm/v3/api/gateway"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/async"
|
||||||
"github.com/prysmaticlabs/prysm/v3/async/event"
|
"github.com/prysmaticlabs/prysm/v3/async/event"
|
||||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/blockchain"
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/blockchain"
|
||||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/builder"
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/builder"
|
||||||
@@ -70,6 +72,8 @@ const testSkipPowFlag = "test-skip-pow"
|
|||||||
// 128MB max message size when enabling debug endpoints.
|
// 128MB max message size when enabling debug endpoints.
|
||||||
const debugGrpcMaxMsgSize = 1 << 27
|
const debugGrpcMaxMsgSize = 1 << 27
|
||||||
|
|
||||||
|
const blobsPruneInterval = time.Minute * 15
|
||||||
|
|
||||||
// Used as a struct to keep cli flag options for configuring services
|
// Used as a struct to keep cli flag options for configuring services
|
||||||
// for the beacon node. We keep this as a separate struct to not pollute the actual BeaconNode
|
// for the beacon node. We keep this as a separate struct to not pollute the actual BeaconNode
|
||||||
// struct, as it is merely used to pass down configuration options into the appropriate services.
|
// struct, as it is merely used to pass down configuration options into the appropriate services.
|
||||||
@@ -440,6 +444,8 @@ func (b *BeaconNode) startDB(cliCtx *cli.Context, depositAddress string) error {
|
|||||||
knownContract, addr.Bytes())
|
knownContract, addr.Bytes())
|
||||||
}
|
}
|
||||||
log.Infof("Deposit contract: %#x", addr.Bytes())
|
log.Infof("Deposit contract: %#x", addr.Bytes())
|
||||||
|
|
||||||
|
go b.pruneBlobs()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -979,3 +985,12 @@ func (b *BeaconNode) registerBuilderService() error {
|
|||||||
}
|
}
|
||||||
return b.services.RegisterService(svc)
|
return b.services.RegisterService(svc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *BeaconNode) pruneBlobs() {
|
||||||
|
async.RunEvery(b.ctx, blobsPruneInterval, func() {
|
||||||
|
err := b.db.CleanupBlobs(b.ctx)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Unable to prune blobs sidecars in db")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ func (s *Service) forkWatcher() {
|
|||||||
case currSlot := <-slotTicker.C():
|
case currSlot := <-slotTicker.C():
|
||||||
currEpoch := slots.ToEpoch(currSlot)
|
currEpoch := slots.ToEpoch(currSlot)
|
||||||
if currEpoch == params.BeaconConfig().AltairForkEpoch ||
|
if currEpoch == params.BeaconConfig().AltairForkEpoch ||
|
||||||
currEpoch == params.BeaconConfig().BellatrixForkEpoch {
|
currEpoch == params.BeaconConfig().BellatrixForkEpoch || currEpoch == params.BeaconConfig().Eip4844ForkEpoch {
|
||||||
// If we are in the fork epoch, we update our enr with
|
// If we are in the fork epoch, we update our enr with
|
||||||
// the updated fork digest. These repeatedly does
|
// the updated fork digest. These repeatedly does
|
||||||
// this over the epoch, which might be slightly wasteful
|
// this over the epoch, which might be slightly wasteful
|
||||||
@@ -27,7 +27,7 @@ func (s *Service) forkWatcher() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// from Bellatrix Epoch, the MaxGossipSize and the MaxChunkSize is changed to 10Mb.
|
// from Bellatrix Epoch, the MaxGossipSize and the MaxChunkSize is changed to 10Mb.
|
||||||
if currEpoch == params.BeaconConfig().BellatrixForkEpoch {
|
if currEpoch == params.BeaconConfig().BellatrixForkEpoch || currEpoch == params.BeaconConfig().Eip4844ForkEpoch {
|
||||||
encoder.SetMaxGossipSizeForBellatrix()
|
encoder.SetMaxGossipSizeForBellatrix()
|
||||||
encoder.SetMaxChunkSizeForBellatrix()
|
encoder.SetMaxChunkSizeForBellatrix()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,6 +116,9 @@ func (s *Service) topicScoreParams(topic string) (*pubsub.TopicScoreParams, erro
|
|||||||
return defaultProposerSlashingTopicParams(), nil
|
return defaultProposerSlashingTopicParams(), nil
|
||||||
case strings.Contains(topic, GossipAttesterSlashingMessage):
|
case strings.Contains(topic, GossipAttesterSlashingMessage):
|
||||||
return defaultAttesterSlashingTopicParams(), nil
|
return defaultAttesterSlashingTopicParams(), nil
|
||||||
|
case strings.Contains(topic, GossipBlobsMessage):
|
||||||
|
// TODO(EIP-4844): Using the block topic scoring for now. But this should be updated for blobs
|
||||||
|
return defaultBlockTopicParams(), nil
|
||||||
default:
|
default:
|
||||||
return nil, errors.Errorf("unrecognized topic provided for parameter registration: %s", topic)
|
return nil, errors.Errorf("unrecognized topic provided for parameter registration: %s", topic)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,12 +20,16 @@ var gossipTopicMappings = map[string]proto.Message{
|
|||||||
AggregateAndProofSubnetTopicFormat: ðpb.SignedAggregateAttestationAndProof{},
|
AggregateAndProofSubnetTopicFormat: ðpb.SignedAggregateAttestationAndProof{},
|
||||||
SyncContributionAndProofSubnetTopicFormat: ðpb.SignedContributionAndProof{},
|
SyncContributionAndProofSubnetTopicFormat: ðpb.SignedContributionAndProof{},
|
||||||
SyncCommitteeSubnetTopicFormat: ðpb.SyncCommitteeMessage{},
|
SyncCommitteeSubnetTopicFormat: ðpb.SyncCommitteeMessage{},
|
||||||
|
BlobsSubnetTopicFormat: ðpb.SignedBlobsSidecar{},
|
||||||
}
|
}
|
||||||
|
|
||||||
// GossipTopicMappings is a function to return the assigned data type
|
// GossipTopicMappings is a function to return the assigned data type
|
||||||
// versioned by epoch.
|
// versioned by epoch.
|
||||||
func GossipTopicMappings(topic string, epoch types.Epoch) proto.Message {
|
func GossipTopicMappings(topic string, epoch types.Epoch) proto.Message {
|
||||||
if topic == BlockSubnetTopicFormat {
|
if topic == BlockSubnetTopicFormat {
|
||||||
|
if epoch >= params.BeaconConfig().Eip4844ForkEpoch {
|
||||||
|
return ðpb.SignedBeaconBlockWithBlobKZGs{}
|
||||||
|
}
|
||||||
if epoch >= params.BeaconConfig().BellatrixForkEpoch {
|
if epoch >= params.BeaconConfig().BellatrixForkEpoch {
|
||||||
return ðpb.SignedBeaconBlockBellatrix{}
|
return ðpb.SignedBeaconBlockBellatrix{}
|
||||||
}
|
}
|
||||||
@@ -59,4 +63,6 @@ func init() {
|
|||||||
// Specially handle Bellatrix objects.
|
// Specially handle Bellatrix objects.
|
||||||
GossipTypeMapping[reflect.TypeOf(ðpb.SignedBeaconBlockBellatrix{})] = BlockSubnetTopicFormat
|
GossipTypeMapping[reflect.TypeOf(ðpb.SignedBeaconBlockBellatrix{})] = BlockSubnetTopicFormat
|
||||||
GossipTypeMapping[reflect.TypeOf(ðpb.SignedBlindedBeaconBlockBellatrix{})] = BlockSubnetTopicFormat
|
GossipTypeMapping[reflect.TypeOf(ðpb.SignedBlindedBeaconBlockBellatrix{})] = BlockSubnetTopicFormat
|
||||||
|
// Specially handle EIP4844 objects.
|
||||||
|
GossipTypeMapping[reflect.TypeOf(ðpb.SignedBeaconBlockWithBlobKZGs{})] = BlockSubnetTopicFormat
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ func postAltairMsgID(pmsg *pubsubpb.Message, fEpoch types.Epoch) string {
|
|||||||
|
|
||||||
// beyond Bellatrix epoch, allow 10 Mib gossip data size
|
// beyond Bellatrix epoch, allow 10 Mib gossip data size
|
||||||
gossipPubSubSize := params.BeaconNetworkConfig().GossipMaxSize
|
gossipPubSubSize := params.BeaconNetworkConfig().GossipMaxSize
|
||||||
if fEpoch >= params.BeaconConfig().BellatrixForkEpoch {
|
if fEpoch >= params.BeaconConfig().BellatrixForkEpoch || fEpoch >= params.BeaconConfig().Eip4844ForkEpoch {
|
||||||
gossipPubSubSize = params.BeaconNetworkConfig().GossipMaxSizeBellatrix
|
gossipPubSubSize = params.BeaconNetworkConfig().GossipMaxSizeBellatrix
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,11 +52,17 @@ func (s *Service) CanSubscribe(topic string) bool {
|
|||||||
log.WithError(err).Error("Could not determine Bellatrix fork digest")
|
log.WithError(err).Error("Could not determine Bellatrix fork digest")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
eip4844ForkDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().Eip4844ForkEpoch, s.genesisValidatorsRoot)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Could not determine eip4844 fork digest")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
switch parts[2] {
|
switch parts[2] {
|
||||||
case fmt.Sprintf("%x", phase0ForkDigest):
|
case fmt.Sprintf("%x", phase0ForkDigest):
|
||||||
case fmt.Sprintf("%x", altairForkDigest):
|
case fmt.Sprintf("%x", altairForkDigest):
|
||||||
case fmt.Sprintf("%x", bellatrixForkDigest):
|
case fmt.Sprintf("%x", bellatrixForkDigest):
|
||||||
|
case fmt.Sprintf("%x", eip4844ForkDigest):
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ const PingMessageName = "/ping"
|
|||||||
// MetadataMessageName specifies the name for the metadata message topic.
|
// MetadataMessageName specifies the name for the metadata message topic.
|
||||||
const MetadataMessageName = "/metadata"
|
const MetadataMessageName = "/metadata"
|
||||||
|
|
||||||
|
// BlobsSidecarsByRangeMessageName specifies the name for the blobs sidecars by range message topic.
|
||||||
|
const BlobsSidecarsByRangeMessageName = "/blobs_sidecars_by_range"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// V1 RPC Topics
|
// V1 RPC Topics
|
||||||
// RPCStatusTopicV1 defines the v1 topic for the status rpc method.
|
// RPCStatusTopicV1 defines the v1 topic for the status rpc method.
|
||||||
@@ -51,6 +54,8 @@ const (
|
|||||||
RPCPingTopicV1 = protocolPrefix + PingMessageName + SchemaVersionV1
|
RPCPingTopicV1 = protocolPrefix + PingMessageName + SchemaVersionV1
|
||||||
// RPCMetaDataTopicV1 defines the v1 topic for the metadata rpc method.
|
// RPCMetaDataTopicV1 defines the v1 topic for the metadata rpc method.
|
||||||
RPCMetaDataTopicV1 = protocolPrefix + MetadataMessageName + SchemaVersionV1
|
RPCMetaDataTopicV1 = protocolPrefix + MetadataMessageName + SchemaVersionV1
|
||||||
|
// RPCBlobsSidecarsByRangeTopicV1 defines the v1 topic for the blobs sidecars by range rpc method.
|
||||||
|
RPCBlobsSidecarsByRangeTopicV1 = protocolPrefix + BlobsSidecarsByRangeMessageName + SchemaVersionV1
|
||||||
|
|
||||||
// V2 RPC Topics
|
// V2 RPC Topics
|
||||||
// RPCBlocksByRangeTopicV2 defines v2 the topic for the blocks by range rpc method.
|
// RPCBlocksByRangeTopicV2 defines v2 the topic for the blocks by range rpc method.
|
||||||
@@ -83,6 +88,8 @@ var RPCTopicMappings = map[string]interface{}{
|
|||||||
// RPC Metadata Message
|
// RPC Metadata Message
|
||||||
RPCMetaDataTopicV1: new(interface{}),
|
RPCMetaDataTopicV1: new(interface{}),
|
||||||
RPCMetaDataTopicV2: new(interface{}),
|
RPCMetaDataTopicV2: new(interface{}),
|
||||||
|
// RPC Blobs Sidecars By Range Message
|
||||||
|
RPCBlobsSidecarsByRangeTopicV1: new(pb.BlobsSidecarsByRangeRequest),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Maps all registered protocol prefixes.
|
// Maps all registered protocol prefixes.
|
||||||
@@ -93,12 +100,13 @@ var protocolMapping = map[string]bool{
|
|||||||
// Maps all the protocol message names for the different rpc
|
// Maps all the protocol message names for the different rpc
|
||||||
// topics.
|
// topics.
|
||||||
var messageMapping = map[string]bool{
|
var messageMapping = map[string]bool{
|
||||||
StatusMessageName: true,
|
StatusMessageName: true,
|
||||||
GoodbyeMessageName: true,
|
GoodbyeMessageName: true,
|
||||||
BeaconBlocksByRangeMessageName: true,
|
BeaconBlocksByRangeMessageName: true,
|
||||||
BeaconBlocksByRootsMessageName: true,
|
BeaconBlocksByRootsMessageName: true,
|
||||||
PingMessageName: true,
|
PingMessageName: true,
|
||||||
MetadataMessageName: true,
|
MetadataMessageName: true,
|
||||||
|
BlobsSidecarsByRangeMessageName: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Maps all the RPC messages which are to updated in altair.
|
// Maps all the RPC messages which are to updated in altair.
|
||||||
|
|||||||
@@ -487,7 +487,7 @@ func (s *Service) isInitialized() bool {
|
|||||||
func (s *Service) increaseMaxMessageSizesForBellatrix() {
|
func (s *Service) increaseMaxMessageSizesForBellatrix() {
|
||||||
currentSlot := slots.Since(s.genesisTime)
|
currentSlot := slots.Since(s.genesisTime)
|
||||||
currentEpoch := slots.ToEpoch(currentSlot)
|
currentEpoch := slots.ToEpoch(currentSlot)
|
||||||
if currentEpoch >= params.BeaconConfig().BellatrixForkEpoch {
|
if currentEpoch >= params.BeaconConfig().BellatrixForkEpoch || currentEpoch >= params.BeaconConfig().Eip4844ForkEpoch {
|
||||||
encoder.SetMaxGossipSizeForBellatrix()
|
encoder.SetMaxGossipSizeForBellatrix()
|
||||||
encoder.SetMaxChunkSizeForBellatrix()
|
encoder.SetMaxChunkSizeForBellatrix()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ const (
|
|||||||
GossipAggregateAndProofMessage = "beacon_aggregate_and_proof"
|
GossipAggregateAndProofMessage = "beacon_aggregate_and_proof"
|
||||||
// GossipContributionAndProofMessage is the name for the sync contribution and proof message type.
|
// GossipContributionAndProofMessage is the name for the sync contribution and proof message type.
|
||||||
GossipContributionAndProofMessage = "sync_committee_contribution_and_proof"
|
GossipContributionAndProofMessage = "sync_committee_contribution_and_proof"
|
||||||
|
// GossipBlobsMessage is the name of the blobs message type.
|
||||||
|
GossipBlobsMessage = "blobs_sidecar"
|
||||||
|
|
||||||
// Topic Formats
|
// Topic Formats
|
||||||
//
|
//
|
||||||
@@ -45,4 +47,6 @@ const (
|
|||||||
AggregateAndProofSubnetTopicFormat = GossipProtocolAndDigest + GossipAggregateAndProofMessage
|
AggregateAndProofSubnetTopicFormat = GossipProtocolAndDigest + GossipAggregateAndProofMessage
|
||||||
// SyncContributionAndProofSubnetTopicFormat is the topic format for the sync aggregate and proof subnet.
|
// SyncContributionAndProofSubnetTopicFormat is the topic format for the sync aggregate and proof subnet.
|
||||||
SyncContributionAndProofSubnetTopicFormat = GossipProtocolAndDigest + GossipContributionAndProofMessage
|
SyncContributionAndProofSubnetTopicFormat = GossipProtocolAndDigest + GossipContributionAndProofMessage
|
||||||
|
// BlobsSubnetTopicFormat is the topic format for the blobs sidecar subnet.
|
||||||
|
BlobsSubnetTopicFormat = GossipProtocolAndDigest + GossipBlobsMessage
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -48,6 +48,11 @@ func InitializeDataMaps() {
|
|||||||
ðpb.SignedBeaconBlockBellatrix{Block: ðpb.BeaconBlockBellatrix{Body: ðpb.BeaconBlockBodyBellatrix{}}},
|
ðpb.SignedBeaconBlockBellatrix{Block: ðpb.BeaconBlockBellatrix{Body: ðpb.BeaconBlockBodyBellatrix{}}},
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
bytesutil.ToBytes4(params.BeaconConfig().Eip4844ForkVersion): func() (interfaces.SignedBeaconBlock, error) {
|
||||||
|
return blocks.NewSignedBeaconBlock(
|
||||||
|
ðpb.SignedBeaconBlockWithBlobKZGs{Block: ðpb.BeaconBlockWithBlobKZGs{Body: ðpb.BeaconBlockBodyWithBlobKZGs{}}},
|
||||||
|
)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset our metadata map.
|
// Reset our metadata map.
|
||||||
@@ -61,5 +66,8 @@ func InitializeDataMaps() {
|
|||||||
bytesutil.ToBytes4(params.BeaconConfig().BellatrixForkVersion): func() metadata.Metadata {
|
bytesutil.ToBytes4(params.BeaconConfig().BellatrixForkVersion): func() metadata.Metadata {
|
||||||
return wrapper.WrappedMetadataV1(ðpb.MetaDataV1{})
|
return wrapper.WrappedMetadataV1(ðpb.MetaDataV1{})
|
||||||
},
|
},
|
||||||
|
bytesutil.ToBytes4(params.BeaconConfig().Eip4844ForkVersion): func() metadata.Metadata {
|
||||||
|
return wrapper.WrappedMetadataV1(ðpb.MetaDataV1{})
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -238,6 +238,16 @@ type bellatrixPublishBlindedBlockRequestJson struct {
|
|||||||
Signature string `json:"signature" hex:"true"`
|
Signature string `json:"signature" hex:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type eip4844PublishBlockRequestJson struct {
|
||||||
|
Eip4844Block *beaconBlockEip4844Json `json:"eip4844_block"`
|
||||||
|
Signature string `json:"signature" hex:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type eip4844PublishBlindedBlockRequestJson struct {
|
||||||
|
Eip4844Block *blindedBeaconBlockEip4844Json `json:"eip4844_block"`
|
||||||
|
Signature string `json:"signature" hex:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
// setInitialPublishBlockPostRequest is triggered before we deserialize the request JSON into a struct.
|
// setInitialPublishBlockPostRequest is triggered before we deserialize the request JSON into a struct.
|
||||||
// We don't know which version of the block got posted, but we can determine it from the slot.
|
// We don't know which version of the block got posted, but we can determine it from the slot.
|
||||||
// We know that blocks of all versions have a Message field with a Slot field,
|
// We know that blocks of all versions have a Message field with a Slot field,
|
||||||
@@ -269,8 +279,10 @@ func setInitialPublishBlockPostRequest(endpoint *apimiddleware.Endpoint,
|
|||||||
endpoint.PostRequest = &signedBeaconBlockContainerJson{}
|
endpoint.PostRequest = &signedBeaconBlockContainerJson{}
|
||||||
} else if currentEpoch < params.BeaconConfig().BellatrixForkEpoch {
|
} else if currentEpoch < params.BeaconConfig().BellatrixForkEpoch {
|
||||||
endpoint.PostRequest = &signedBeaconBlockAltairContainerJson{}
|
endpoint.PostRequest = &signedBeaconBlockAltairContainerJson{}
|
||||||
} else {
|
} else if currentEpoch < params.BeaconConfig().Eip4844ForkEpoch {
|
||||||
endpoint.PostRequest = &signedBeaconBlockBellatrixContainerJson{}
|
endpoint.PostRequest = &signedBeaconBlockBellatrixContainerJson{}
|
||||||
|
} else {
|
||||||
|
endpoint.PostRequest = &signedBeaconBlockEip4844ContainerJson{}
|
||||||
}
|
}
|
||||||
req.Body = io.NopCloser(bytes.NewBuffer(buf))
|
req.Body = io.NopCloser(bytes.NewBuffer(buf))
|
||||||
return true, nil
|
return true, nil
|
||||||
@@ -308,6 +320,15 @@ func preparePublishedBlock(endpoint *apimiddleware.Endpoint, _ http.ResponseWrit
|
|||||||
endpoint.PostRequest = actualPostReq
|
endpoint.PostRequest = actualPostReq
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
if block, ok := endpoint.PostRequest.(*signedBeaconBlockEip4844ContainerJson); ok {
|
||||||
|
// Prepare post request that can be properly decoded on gRPC side.
|
||||||
|
actualPostReq := &eip4844PublishBlockRequestJson{
|
||||||
|
Eip4844Block: block.Message,
|
||||||
|
Signature: block.Signature,
|
||||||
|
}
|
||||||
|
endpoint.PostRequest = actualPostReq
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return apimiddleware.InternalServerError(errors.New("unsupported block type"))
|
return apimiddleware.InternalServerError(errors.New("unsupported block type"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,8 +363,10 @@ func setInitialPublishBlindedBlockPostRequest(endpoint *apimiddleware.Endpoint,
|
|||||||
endpoint.PostRequest = &signedBeaconBlockContainerJson{}
|
endpoint.PostRequest = &signedBeaconBlockContainerJson{}
|
||||||
} else if currentEpoch < params.BeaconConfig().BellatrixForkEpoch {
|
} else if currentEpoch < params.BeaconConfig().BellatrixForkEpoch {
|
||||||
endpoint.PostRequest = &signedBeaconBlockAltairContainerJson{}
|
endpoint.PostRequest = &signedBeaconBlockAltairContainerJson{}
|
||||||
} else {
|
} else if currentEpoch < params.BeaconConfig().Eip4844ForkEpoch {
|
||||||
endpoint.PostRequest = &signedBlindedBeaconBlockBellatrixContainerJson{}
|
endpoint.PostRequest = &signedBlindedBeaconBlockBellatrixContainerJson{}
|
||||||
|
} else {
|
||||||
|
endpoint.PostRequest = &signedBlindedBeaconBlockEip4844ContainerJson{}
|
||||||
}
|
}
|
||||||
req.Body = ioutil.NopCloser(bytes.NewBuffer(buf))
|
req.Body = ioutil.NopCloser(bytes.NewBuffer(buf))
|
||||||
return true, nil
|
return true, nil
|
||||||
@@ -381,6 +404,15 @@ func preparePublishedBlindedBlock(endpoint *apimiddleware.Endpoint, _ http.Respo
|
|||||||
endpoint.PostRequest = actualPostReq
|
endpoint.PostRequest = actualPostReq
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
if block, ok := endpoint.PostRequest.(*signedBlindedBeaconBlockEip4844ContainerJson); ok {
|
||||||
|
// Prepare post request that can be properly decoded on gRPC side.
|
||||||
|
actualPostReq := &eip4844PublishBlindedBlockRequestJson{
|
||||||
|
Eip4844Block: block.Message,
|
||||||
|
Signature: block.Signature,
|
||||||
|
}
|
||||||
|
endpoint.PostRequest = actualPostReq
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return apimiddleware.InternalServerError(errors.New("unsupported block type"))
|
return apimiddleware.InternalServerError(errors.New("unsupported block type"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -439,6 +471,11 @@ type bellatrixBlockResponseJson struct {
|
|||||||
ExecutionOptimistic bool `json:"execution_optimistic"`
|
ExecutionOptimistic bool `json:"execution_optimistic"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type eip4844BlockResponseJson struct {
|
||||||
|
Version string `json:"version"`
|
||||||
|
Data *signedBeaconBlockEip4844ContainerJson `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
func serializeV2Block(response interface{}) (apimiddleware.RunDefault, []byte, apimiddleware.ErrorJson) {
|
func serializeV2Block(response interface{}) (apimiddleware.RunDefault, []byte, apimiddleware.ErrorJson) {
|
||||||
respContainer, ok := response.(*blockV2ResponseJson)
|
respContainer, ok := response.(*blockV2ResponseJson)
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -474,6 +511,14 @@ func serializeV2Block(response interface{}) (apimiddleware.RunDefault, []byte, a
|
|||||||
},
|
},
|
||||||
ExecutionOptimistic: respContainer.ExecutionOptimistic,
|
ExecutionOptimistic: respContainer.ExecutionOptimistic,
|
||||||
}
|
}
|
||||||
|
case strings.EqualFold(respContainer.Version, strings.ToLower(ethpbv2.Version_EIP4844.String())):
|
||||||
|
actualRespContainer = &eip4844BlockResponseJson{
|
||||||
|
Version: respContainer.Version,
|
||||||
|
Data: &signedBeaconBlockEip4844ContainerJson{
|
||||||
|
Message: respContainer.Data.Eip4844Block,
|
||||||
|
Signature: respContainer.Data.Signature,
|
||||||
|
},
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return false, nil, apimiddleware.InternalServerError(fmt.Errorf("unsupported block version '%s'", respContainer.Version))
|
return false, nil, apimiddleware.InternalServerError(fmt.Errorf("unsupported block version '%s'", respContainer.Version))
|
||||||
}
|
}
|
||||||
@@ -500,6 +545,11 @@ type bellatrixStateResponseJson struct {
|
|||||||
Data *beaconStateBellatrixJson `json:"data"`
|
Data *beaconStateBellatrixJson `json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type eip4844StateResponseJson struct {
|
||||||
|
Version string `json:"version"`
|
||||||
|
Data *beaconStateEip4844Json `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
func serializeV2State(response interface{}) (apimiddleware.RunDefault, []byte, apimiddleware.ErrorJson) {
|
func serializeV2State(response interface{}) (apimiddleware.RunDefault, []byte, apimiddleware.ErrorJson) {
|
||||||
respContainer, ok := response.(*beaconStateV2ResponseJson)
|
respContainer, ok := response.(*beaconStateV2ResponseJson)
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -523,6 +573,11 @@ func serializeV2State(response interface{}) (apimiddleware.RunDefault, []byte, a
|
|||||||
Version: respContainer.Version,
|
Version: respContainer.Version,
|
||||||
Data: respContainer.Data.BellatrixState,
|
Data: respContainer.Data.BellatrixState,
|
||||||
}
|
}
|
||||||
|
case strings.EqualFold(respContainer.Version, strings.ToLower(ethpbv2.Version_EIP4844.String())):
|
||||||
|
actualRespContainer = &eip4844StateResponseJson{
|
||||||
|
Version: respContainer.Version,
|
||||||
|
Data: respContainer.Data.Eip4844State,
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return false, nil, apimiddleware.InternalServerError(fmt.Errorf("unsupported state version '%s'", respContainer.Version))
|
return false, nil, apimiddleware.InternalServerError(fmt.Errorf("unsupported state version '%s'", respContainer.Version))
|
||||||
}
|
}
|
||||||
@@ -554,6 +609,16 @@ type bellatrixProduceBlindedBlockResponseJson struct {
|
|||||||
Data *blindedBeaconBlockBellatrixJson `json:"data"`
|
Data *blindedBeaconBlockBellatrixJson `json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type eip4844ProduceBlockResponseJson struct {
|
||||||
|
Version string `json:"version"`
|
||||||
|
Data *beaconBlockEip4844Json `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type eip4844ProduceBlindedBlockResponseJson struct {
|
||||||
|
Version string `json:"version"`
|
||||||
|
Data *blindedBeaconBlockEip4844Json `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
func serializeProducedV2Block(response interface{}) (apimiddleware.RunDefault, []byte, apimiddleware.ErrorJson) {
|
func serializeProducedV2Block(response interface{}) (apimiddleware.RunDefault, []byte, apimiddleware.ErrorJson) {
|
||||||
respContainer, ok := response.(*produceBlockResponseV2Json)
|
respContainer, ok := response.(*produceBlockResponseV2Json)
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -577,6 +642,11 @@ func serializeProducedV2Block(response interface{}) (apimiddleware.RunDefault, [
|
|||||||
Version: respContainer.Version,
|
Version: respContainer.Version,
|
||||||
Data: respContainer.Data.BellatrixBlock,
|
Data: respContainer.Data.BellatrixBlock,
|
||||||
}
|
}
|
||||||
|
case strings.EqualFold(respContainer.Version, strings.ToLower(ethpbv2.Version_EIP4844.String())):
|
||||||
|
actualRespContainer = &eip4844ProduceBlockResponseJson{
|
||||||
|
Version: respContainer.Version,
|
||||||
|
Data: respContainer.Data.Eip4844Block,
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return false, nil, apimiddleware.InternalServerError(fmt.Errorf("unsupported block version '%s'", respContainer.Version))
|
return false, nil, apimiddleware.InternalServerError(fmt.Errorf("unsupported block version '%s'", respContainer.Version))
|
||||||
}
|
}
|
||||||
@@ -611,6 +681,11 @@ func serializeProducedBlindedBlock(response interface{}) (apimiddleware.RunDefau
|
|||||||
Version: respContainer.Version,
|
Version: respContainer.Version,
|
||||||
Data: respContainer.Data.BellatrixBlock,
|
Data: respContainer.Data.BellatrixBlock,
|
||||||
}
|
}
|
||||||
|
case strings.EqualFold(respContainer.Version, strings.ToLower(ethpbv2.Version_EIP4844.String())):
|
||||||
|
actualRespContainer = &eip4844ProduceBlindedBlockResponseJson{
|
||||||
|
Version: respContainer.Version,
|
||||||
|
Data: respContainer.Data.Eip4844Block,
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return false, nil, apimiddleware.InternalServerError(fmt.Errorf("unsupported block version '%s'", respContainer.Version))
|
return false, nil, apimiddleware.InternalServerError(fmt.Errorf("unsupported block version '%s'", respContainer.Version))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -330,6 +330,7 @@ type signedBeaconBlockContainerV2Json struct {
|
|||||||
Phase0Block *beaconBlockJson `json:"phase0_block"`
|
Phase0Block *beaconBlockJson `json:"phase0_block"`
|
||||||
AltairBlock *beaconBlockAltairJson `json:"altair_block"`
|
AltairBlock *beaconBlockAltairJson `json:"altair_block"`
|
||||||
BellatrixBlock *beaconBlockBellatrixJson `json:"bellatrix_block"`
|
BellatrixBlock *beaconBlockBellatrixJson `json:"bellatrix_block"`
|
||||||
|
Eip4844Block *beaconBlockEip4844Json `json:"eip4844_block"`
|
||||||
Signature string `json:"signature" hex:"true"`
|
Signature string `json:"signature" hex:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,12 +338,14 @@ type beaconBlockContainerV2Json struct {
|
|||||||
Phase0Block *beaconBlockJson `json:"phase0_block"`
|
Phase0Block *beaconBlockJson `json:"phase0_block"`
|
||||||
AltairBlock *beaconBlockAltairJson `json:"altair_block"`
|
AltairBlock *beaconBlockAltairJson `json:"altair_block"`
|
||||||
BellatrixBlock *beaconBlockBellatrixJson `json:"bellatrix_block"`
|
BellatrixBlock *beaconBlockBellatrixJson `json:"bellatrix_block"`
|
||||||
|
Eip4844Block *beaconBlockEip4844Json `json:"eip4844_block"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type blindedBeaconBlockContainerJson struct {
|
type blindedBeaconBlockContainerJson struct {
|
||||||
Phase0Block *beaconBlockJson `json:"phase0_block"`
|
Phase0Block *beaconBlockJson `json:"phase0_block"`
|
||||||
AltairBlock *beaconBlockAltairJson `json:"altair_block"`
|
AltairBlock *beaconBlockAltairJson `json:"altair_block"`
|
||||||
BellatrixBlock *blindedBeaconBlockBellatrixJson `json:"bellatrix_block"`
|
BellatrixBlock *blindedBeaconBlockBellatrixJson `json:"bellatrix_block"`
|
||||||
|
Eip4844Block *blindedBeaconBlockEip4844Json `json:"eip4844_block"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type signedBeaconBlockAltairContainerJson struct {
|
type signedBeaconBlockAltairContainerJson struct {
|
||||||
@@ -360,6 +363,16 @@ type signedBlindedBeaconBlockBellatrixContainerJson struct {
|
|||||||
Signature string `json:"signature" hex:"true"`
|
Signature string `json:"signature" hex:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type signedBeaconBlockEip4844ContainerJson struct {
|
||||||
|
Message *beaconBlockEip4844Json `json:"message"`
|
||||||
|
Signature string `json:"signature" hex:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type signedBlindedBeaconBlockEip4844ContainerJson struct {
|
||||||
|
Message *blindedBeaconBlockEip4844Json `json:"message"`
|
||||||
|
Signature string `json:"signature" hex:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
type beaconBlockAltairJson struct {
|
type beaconBlockAltairJson struct {
|
||||||
Slot string `json:"slot"`
|
Slot string `json:"slot"`
|
||||||
ProposerIndex string `json:"proposer_index"`
|
ProposerIndex string `json:"proposer_index"`
|
||||||
@@ -384,6 +397,22 @@ type blindedBeaconBlockBellatrixJson struct {
|
|||||||
Body *blindedBeaconBlockBodyBellatrixJson `json:"body"`
|
Body *blindedBeaconBlockBodyBellatrixJson `json:"body"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type beaconBlockEip4844Json struct {
|
||||||
|
Slot string `json:"slot"`
|
||||||
|
ProposerIndex string `json:"proposer_index"`
|
||||||
|
ParentRoot string `json:"parent_root" hex:"true"`
|
||||||
|
StateRoot string `json:"state_root" hex:"true"`
|
||||||
|
Body *beaconBlockBodyEip4844Json `json:"body"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type blindedBeaconBlockEip4844Json struct {
|
||||||
|
Slot string `json:"slot"`
|
||||||
|
ProposerIndex string `json:"proposer_index"`
|
||||||
|
ParentRoot string `json:"parent_root" hex:"true"`
|
||||||
|
StateRoot string `json:"state_root" hex:"true"`
|
||||||
|
Body *blindedBeaconBlockBodyEip4844Json `json:"body"`
|
||||||
|
}
|
||||||
|
|
||||||
type beaconBlockBodyAltairJson struct {
|
type beaconBlockBodyAltairJson struct {
|
||||||
RandaoReveal string `json:"randao_reveal" hex:"true"`
|
RandaoReveal string `json:"randao_reveal" hex:"true"`
|
||||||
Eth1Data *eth1DataJson `json:"eth1_data"`
|
Eth1Data *eth1DataJson `json:"eth1_data"`
|
||||||
@@ -422,6 +451,34 @@ type blindedBeaconBlockBodyBellatrixJson struct {
|
|||||||
ExecutionPayloadHeader *executionPayloadHeaderJson `json:"execution_payload_header"`
|
ExecutionPayloadHeader *executionPayloadHeaderJson `json:"execution_payload_header"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type beaconBlockBodyEip4844Json struct {
|
||||||
|
RandaoReveal string `json:"randao_reveal" hex:"true"`
|
||||||
|
Eth1Data *eth1DataJson `json:"eth1_data"`
|
||||||
|
Graffiti string `json:"graffiti" hex:"true"`
|
||||||
|
ProposerSlashings []*proposerSlashingJson `json:"proposer_slashings"`
|
||||||
|
AttesterSlashings []*attesterSlashingJson `json:"attester_slashings"`
|
||||||
|
Attestations []*attestationJson `json:"attestations"`
|
||||||
|
Deposits []*depositJson `json:"deposits"`
|
||||||
|
VoluntaryExits []*signedVoluntaryExitJson `json:"voluntary_exits"`
|
||||||
|
SyncAggregate *syncAggregateJson `json:"sync_aggregate"`
|
||||||
|
ExecutionPayload *executionPayloadJson `json:"execution_payload"`
|
||||||
|
BlobKzgs []string `json:"blob_kzgs" hex:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type blindedBeaconBlockBodyEip4844Json struct {
|
||||||
|
RandaoReveal string `json:"randao_reveal" hex:"true"`
|
||||||
|
Eth1Data *eth1DataJson `json:"eth1_data"`
|
||||||
|
Graffiti string `json:"graffiti" hex:"true"`
|
||||||
|
ProposerSlashings []*proposerSlashingJson `json:"proposer_slashings"`
|
||||||
|
AttesterSlashings []*attesterSlashingJson `json:"attester_slashings"`
|
||||||
|
Attestations []*attestationJson `json:"attestations"`
|
||||||
|
Deposits []*depositJson `json:"deposits"`
|
||||||
|
VoluntaryExits []*signedVoluntaryExitJson `json:"voluntary_exits"`
|
||||||
|
SyncAggregate *syncAggregateJson `json:"sync_aggregate"`
|
||||||
|
ExecutionPayloadHeader *executionPayloadHeaderJson `json:"execution_payload_header"`
|
||||||
|
BlobKzgs []string `json:"blob_kzgs" hex:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
type executionPayloadJson struct {
|
type executionPayloadJson struct {
|
||||||
ParentHash string `json:"parent_hash" hex:"true"`
|
ParentHash string `json:"parent_hash" hex:"true"`
|
||||||
FeeRecipient string `json:"fee_recipient" hex:"true"`
|
FeeRecipient string `json:"fee_recipient" hex:"true"`
|
||||||
@@ -659,10 +716,39 @@ type beaconStateBellatrixJson struct {
|
|||||||
LatestExecutionPayloadHeader *executionPayloadHeaderJson `json:"latest_execution_payload_header"`
|
LatestExecutionPayloadHeader *executionPayloadHeaderJson `json:"latest_execution_payload_header"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type beaconStateEip4844Json struct {
|
||||||
|
GenesisTime string `json:"genesis_time"`
|
||||||
|
GenesisValidatorsRoot string `json:"genesis_validators_root" hex:"true"`
|
||||||
|
Slot string `json:"slot"`
|
||||||
|
Fork *forkJson `json:"fork"`
|
||||||
|
LatestBlockHeader *beaconBlockHeaderJson `json:"latest_block_header"`
|
||||||
|
BlockRoots []string `json:"block_roots" hex:"true"`
|
||||||
|
StateRoots []string `json:"state_roots" hex:"true"`
|
||||||
|
HistoricalRoots []string `json:"historical_roots" hex:"true"`
|
||||||
|
Eth1Data *eth1DataJson `json:"eth1_data"`
|
||||||
|
Eth1DataVotes []*eth1DataJson `json:"eth1_data_votes"`
|
||||||
|
Eth1DepositIndex string `json:"eth1_deposit_index"`
|
||||||
|
Validators []*validatorJson `json:"validators"`
|
||||||
|
Balances []string `json:"balances"`
|
||||||
|
RandaoMixes []string `json:"randao_mixes" hex:"true"`
|
||||||
|
Slashings []string `json:"slashings"`
|
||||||
|
PreviousEpochParticipation EpochParticipation `json:"previous_epoch_participation"`
|
||||||
|
CurrentEpochParticipation EpochParticipation `json:"current_epoch_participation"`
|
||||||
|
JustificationBits string `json:"justification_bits" hex:"true"`
|
||||||
|
PreviousJustifiedCheckpoint *checkpointJson `json:"previous_justified_checkpoint"`
|
||||||
|
CurrentJustifiedCheckpoint *checkpointJson `json:"current_justified_checkpoint"`
|
||||||
|
FinalizedCheckpoint *checkpointJson `json:"finalized_checkpoint"`
|
||||||
|
InactivityScores []string `json:"inactivity_scores"`
|
||||||
|
CurrentSyncCommittee *syncCommitteeJson `json:"current_sync_committee"`
|
||||||
|
NextSyncCommittee *syncCommitteeJson `json:"next_sync_committee"`
|
||||||
|
LatestExecutionPayloadHeader *executionPayloadHeaderJson `json:"latest_execution_payload_header"`
|
||||||
|
}
|
||||||
|
|
||||||
type beaconStateContainerV2Json struct {
|
type beaconStateContainerV2Json struct {
|
||||||
Phase0State *beaconStateJson `json:"phase0_state"`
|
Phase0State *beaconStateJson `json:"phase0_state"`
|
||||||
AltairState *beaconStateAltairJson `json:"altair_state"`
|
AltairState *beaconStateAltairJson `json:"altair_state"`
|
||||||
BellatrixState *beaconStateBellatrixJson `json:"bellatrix_state"`
|
BellatrixState *beaconStateBellatrixJson `json:"bellatrix_state"`
|
||||||
|
Eip4844State *beaconStateEip4844Json `json:"eip4844_state"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type forkJson struct {
|
type forkJson struct {
|
||||||
|
|||||||
@@ -230,6 +230,7 @@ func (bs *Server) SubmitBlock(ctx context.Context, req *ethpbv2.SignedBeaconBloc
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// TODO(EIP-4844): submitEip4844Block
|
||||||
return &emptypb.Empty{}, nil
|
return &emptypb.Empty{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,7 +270,8 @@ func (bs *Server) SubmitBlockSSZ(ctx context.Context, req *ethpbv2.SSZContainer)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return &emptypb.Empty{}, status.Errorf(codes.Internal, "Could not compute block's hash tree root: %v", err)
|
return &emptypb.Empty{}, status.Errorf(codes.Internal, "Could not compute block's hash tree root: %v", err)
|
||||||
}
|
}
|
||||||
return &emptypb.Empty{}, bs.submitBlock(ctx, root, block)
|
// TODO(EIP-4844): Unmarshal Sidecar in Request
|
||||||
|
return &emptypb.Empty{}, bs.submitBlock(ctx, root, block, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubmitBlindedBlock instructs the beacon node to use the components of the `SignedBlindedBeaconBlock` to construct
|
// SubmitBlindedBlock instructs the beacon node to use the components of the `SignedBlindedBeaconBlock` to construct
|
||||||
@@ -360,7 +362,8 @@ func (bs *Server) SubmitBlindedBlockSSZ(ctx context.Context, req *ethpbv2.SSZCon
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return &emptypb.Empty{}, status.Errorf(codes.Internal, "Could not compute block's hash tree root: %v", err)
|
return &emptypb.Empty{}, status.Errorf(codes.Internal, "Could not compute block's hash tree root: %v", err)
|
||||||
}
|
}
|
||||||
return &emptypb.Empty{}, bs.submitBlock(ctx, root, block)
|
// TODO(EIP-4844): Unmarshal sidecar in request
|
||||||
|
return &emptypb.Empty{}, bs.submitBlock(ctx, root, block, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBlock retrieves block details for given block ID.
|
// GetBlock retrieves block details for given block ID.
|
||||||
@@ -530,6 +533,34 @@ func (bs *Server) GetBlockV2(ctx context.Context, req *ethpbv2.BlockRequestV2) (
|
|||||||
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
|
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
eip4844Blk, err := blk.PbEip4844Block()
|
||||||
|
if err == nil {
|
||||||
|
if eip4844Blk == nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "Nil block")
|
||||||
|
}
|
||||||
|
v2Blk, err := migration.V1Alpha1BeaconBlockEip4844ToV2(eip4844Blk.Block)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
|
||||||
|
}
|
||||||
|
root, err := blk.Block().HashTreeRoot()
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "Could not get block root: %v", err)
|
||||||
|
}
|
||||||
|
isOptimistic, err := bs.OptimisticModeFetcher.IsOptimisticForRoot(ctx, root)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "Could not check if block is optimistic: %v", err)
|
||||||
|
}
|
||||||
|
sig := blk.Signature()
|
||||||
|
return ðpbv2.BlockResponseV2{
|
||||||
|
Version: ethpbv2.Version_EIP4844,
|
||||||
|
Data: ðpbv2.SignedBeaconBlockContainer{
|
||||||
|
Message: ðpbv2.SignedBeaconBlockContainer_Eip4844Block{Eip4844Block: v2Blk},
|
||||||
|
Signature: sig[:],
|
||||||
|
},
|
||||||
|
ExecutionOptimistic: isOptimistic,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
return nil, status.Errorf(codes.Internal, "Unknown block type %T", blk)
|
return nil, status.Errorf(codes.Internal, "Unknown block type %T", blk)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -643,6 +674,27 @@ func (bs *Server) GetBlockSSZV2(ctx context.Context, req *ethpbv2.BlockRequestV2
|
|||||||
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
|
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
eip4844Blk, err := blk.PbEip4844Block()
|
||||||
|
if err == nil {
|
||||||
|
if eip4844Blk == nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "Nil block")
|
||||||
|
}
|
||||||
|
v2Blk, err := migration.V1Alpha1BeaconBlockEip4844ToV2(eip4844Blk.Block)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
|
||||||
|
}
|
||||||
|
sig := blk.Signature()
|
||||||
|
data := ðpbv2.SignedBeaconBlockEip4844{
|
||||||
|
Message: v2Blk,
|
||||||
|
Signature: sig[:],
|
||||||
|
}
|
||||||
|
sszData, err := data.MarshalSSZ()
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "Could not marshal block into SSZ: %v", err)
|
||||||
|
}
|
||||||
|
return ðpbv2.SSZContainer{Version: ethpbv2.Version_EIP4844, Data: sszData}, nil
|
||||||
|
}
|
||||||
|
|
||||||
return nil, status.Errorf(codes.Internal, "Unknown block type %T", blk)
|
return nil, status.Errorf(codes.Internal, "Unknown block type %T", blk)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -849,7 +901,7 @@ func (bs *Server) submitPhase0Block(ctx context.Context, phase0Blk *ethpbv1.Beac
|
|||||||
return status.Errorf(codes.InvalidArgument, "Could not tree hash block: %v", err)
|
return status.Errorf(codes.InvalidArgument, "Could not tree hash block: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return bs.submitBlock(ctx, root, wrappedPhase0Blk)
|
return bs.submitBlock(ctx, root, wrappedPhase0Blk, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *Server) submitAltairBlock(ctx context.Context, altairBlk *ethpbv2.BeaconBlockAltair, sig []byte) error {
|
func (bs *Server) submitAltairBlock(ctx context.Context, altairBlk *ethpbv2.BeaconBlockAltair, sig []byte) error {
|
||||||
@@ -867,7 +919,7 @@ func (bs *Server) submitAltairBlock(ctx context.Context, altairBlk *ethpbv2.Beac
|
|||||||
return status.Errorf(codes.InvalidArgument, "Could not tree hash block: %v", err)
|
return status.Errorf(codes.InvalidArgument, "Could not tree hash block: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return bs.submitBlock(ctx, root, wrappedAltairBlk)
|
return bs.submitBlock(ctx, root, wrappedAltairBlk, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *Server) submitBellatrixBlock(ctx context.Context, bellatrixBlk *ethpbv2.BeaconBlockBellatrix, sig []byte) error {
|
func (bs *Server) submitBellatrixBlock(ctx context.Context, bellatrixBlk *ethpbv2.BeaconBlockBellatrix, sig []byte) error {
|
||||||
@@ -885,7 +937,7 @@ func (bs *Server) submitBellatrixBlock(ctx context.Context, bellatrixBlk *ethpbv
|
|||||||
return status.Errorf(codes.InvalidArgument, "Could not tree hash block: %v", err)
|
return status.Errorf(codes.InvalidArgument, "Could not tree hash block: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return bs.submitBlock(ctx, root, wrappedBellatrixBlk)
|
return bs.submitBlock(ctx, root, wrappedBellatrixBlk, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *Server) submitBlindedBellatrixBlock(ctx context.Context, blindedBellatrixBlk *ethpbv2.BlindedBeaconBlockBellatrix, sig []byte) error {
|
func (bs *Server) submitBlindedBellatrixBlock(ctx context.Context, blindedBellatrixBlk *ethpbv2.BlindedBeaconBlockBellatrix, sig []byte) error {
|
||||||
@@ -904,10 +956,11 @@ func (bs *Server) submitBlindedBellatrixBlock(ctx context.Context, blindedBellat
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return status.Errorf(codes.Internal, "Could not propose blinded block: %v", err)
|
return status.Errorf(codes.Internal, "Could not propose blinded block: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *Server) submitBlock(ctx context.Context, blockRoot [fieldparams.RootLength]byte, block interfaces.SignedBeaconBlock) error {
|
func (bs *Server) submitBlock(ctx context.Context, blockRoot [fieldparams.RootLength]byte, block interfaces.SignedBeaconBlock, sidecar *eth.BlobsSidecar) error {
|
||||||
// Do not block proposal critical path with debug logging or block feed updates.
|
// Do not block proposal critical path with debug logging or block feed updates.
|
||||||
defer func() {
|
defer func() {
|
||||||
log.WithField("blockRoot", fmt.Sprintf("%#x", bytesutil.Trunc(blockRoot[:]))).Debugf(
|
log.WithField("blockRoot", fmt.Sprintf("%#x", bytesutil.Trunc(blockRoot[:]))).Debugf(
|
||||||
@@ -927,6 +980,11 @@ func (bs *Server) submitBlock(ctx context.Context, blockRoot [fieldparams.RootLe
|
|||||||
return status.Errorf(codes.Internal, "Could not broadcast block: %v", err)
|
return status.Errorf(codes.Internal, "Could not broadcast block: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if sidecar != nil {
|
||||||
|
if err := block.SetSideCar(ð.SignedBlobsSidecar{Message: sidecar}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
if err := bs.BlockReceiver.ReceiveBlock(ctx, block, blockRoot); err != nil {
|
if err := bs.BlockReceiver.ReceiveBlock(ctx, block, blockRoot); err != nil {
|
||||||
return status.Errorf(codes.Internal, "Could not process beacon block: %v", err)
|
return status.Errorf(codes.Internal, "Could not process beacon block: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,13 +71,17 @@ func (ds *Server) GetBeaconStateV2(ctx context.Context, req *ethpbv2.BeaconState
|
|||||||
},
|
},
|
||||||
ExecutionOptimistic: isOptimistic,
|
ExecutionOptimistic: isOptimistic,
|
||||||
}, nil
|
}, nil
|
||||||
case version.Bellatrix:
|
case version.Bellatrix, version.EIP4844:
|
||||||
protoState, err := migration.BeaconStateBellatrixToProto(beaconSt)
|
protoState, err := migration.BeaconStateBellatrixToProto(beaconSt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.Errorf(codes.Internal, "Could not convert state to proto: %v", err)
|
return nil, status.Errorf(codes.Internal, "Could not convert state to proto: %v", err)
|
||||||
}
|
}
|
||||||
|
v := ethpbv2.Version_BELLATRIX
|
||||||
|
if beaconSt.Version() == version.EIP4844 {
|
||||||
|
v = ethpbv2.Version_EIP4844
|
||||||
|
}
|
||||||
return ðpbv2.BeaconStateResponseV2{
|
return ðpbv2.BeaconStateResponseV2{
|
||||||
Version: ethpbv2.Version_BELLATRIX,
|
Version: v,
|
||||||
Data: ðpbv2.BeaconStateContainer{
|
Data: ðpbv2.BeaconStateContainer{
|
||||||
State: ðpbv2.BeaconStateContainer_BellatrixState{BellatrixState: protoState},
|
State: ðpbv2.BeaconStateContainer_BellatrixState{BellatrixState: protoState},
|
||||||
},
|
},
|
||||||
@@ -110,6 +114,8 @@ func (ds *Server) GetBeaconStateSSZV2(ctx context.Context, req *ethpbv2.BeaconSt
|
|||||||
ver = ethpbv2.Version_ALTAIR
|
ver = ethpbv2.Version_ALTAIR
|
||||||
case version.Bellatrix:
|
case version.Bellatrix:
|
||||||
ver = ethpbv2.Version_BELLATRIX
|
ver = ethpbv2.Version_BELLATRIX
|
||||||
|
case version.EIP4844:
|
||||||
|
ver = ethpbv2.Version_EIP4844
|
||||||
default:
|
default:
|
||||||
return nil, status.Error(codes.Internal, "Unsupported state version")
|
return nil, status.Error(codes.Internal, "Unsupported state version")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -335,6 +335,19 @@ func (vs *Server) ProduceBlockV2(ctx context.Context, req *ethpbv1.ProduceBlockR
|
|||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
eip4844Block, ok := v1alpha1resp.Block.(*ethpbalpha.GenericBeaconBlock_Eip4844)
|
||||||
|
if ok {
|
||||||
|
block, err := migration.V1Alpha1BeaconBlockEip4844ToV2(eip4844Block.Eip4844)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "Could not prepare beacon block: %v", err)
|
||||||
|
}
|
||||||
|
return ðpbv2.ProduceBlockResponseV2{
|
||||||
|
Version: ethpbv2.Version_EIP4844,
|
||||||
|
Data: ðpbv2.BeaconBlockContainerV2{
|
||||||
|
Block: ðpbv2.BeaconBlockContainerV2_Eip4844Block{Eip4844Block: block},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
return nil, status.Error(codes.InvalidArgument, "Unsupported block type")
|
return nil, status.Error(codes.InvalidArgument, "Unsupported block type")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -412,6 +425,21 @@ func (vs *Server) ProduceBlockV2SSZ(ctx context.Context, req *ethpbv1.ProduceBlo
|
|||||||
Data: sszBlock,
|
Data: sszBlock,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
eip4844Block, ok := v1alpha1resp.Block.(*ethpbalpha.GenericBeaconBlock_Eip4844)
|
||||||
|
if ok {
|
||||||
|
block, err := migration.V1Alpha1BeaconBlockEip4844ToV2(eip4844Block.Eip4844)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "Could not prepare beacon block: %v", err)
|
||||||
|
}
|
||||||
|
sszBlock, err := block.MarshalSSZ()
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "Could not marshal block into SSZ format: %v", err)
|
||||||
|
}
|
||||||
|
return ðpbv2.SSZContainer{
|
||||||
|
Version: ethpbv2.Version_EIP4844,
|
||||||
|
Data: sszBlock,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
return nil, status.Error(codes.InvalidArgument, "Unsupported block type")
|
return nil, status.Error(codes.InvalidArgument, "Unsupported block type")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -573,6 +601,21 @@ func (vs *Server) ProduceBlindedBlockSSZ(ctx context.Context, req *ethpbv1.Produ
|
|||||||
Data: sszBlock,
|
Data: sszBlock,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
eip4844Block, ok := v1alpha1resp.Block.(*ethpbalpha.GenericBeaconBlock_Eip4844)
|
||||||
|
if ok {
|
||||||
|
block, err := migration.V1Alpha1BeaconBlockEip4844ToV2Blinded(eip4844Block.Eip4844)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "Could not prepare beacon block: %v", err)
|
||||||
|
}
|
||||||
|
sszBlock, err := block.MarshalSSZ()
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "Could not marshal block into SSZ format: %v", err)
|
||||||
|
}
|
||||||
|
return ðpbv2.SSZContainer{
|
||||||
|
Version: ethpbv2.Version_EIP4844,
|
||||||
|
Data: sszBlock,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
return nil, status.Error(codes.InvalidArgument, "Unsupported block type")
|
return nil, status.Error(codes.InvalidArgument, "Unsupported block type")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -528,7 +528,7 @@ func (bs *Server) GetValidatorParticipation(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.Errorf(codes.Internal, "Could not pre compute attestations: %v", err)
|
return nil, status.Errorf(codes.Internal, "Could not pre compute attestations: %v", err)
|
||||||
}
|
}
|
||||||
case version.Altair, version.Bellatrix:
|
case version.Altair, version.Bellatrix, version.EIP4844:
|
||||||
v, b, err = altair.InitializePrecomputeValidators(ctx, beaconState)
|
v, b, err = altair.InitializePrecomputeValidators(ctx, beaconState)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.Errorf(codes.Internal, "Could not set up altair pre compute instance: %v", err)
|
return nil, status.Errorf(codes.Internal, "Could not set up altair pre compute instance: %v", err)
|
||||||
@@ -693,7 +693,7 @@ func (bs *Server) GetValidatorPerformance(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
validatorSummary = vp
|
validatorSummary = vp
|
||||||
case version.Altair, version.Bellatrix:
|
case version.Altair, version.Bellatrix, version.EIP4844:
|
||||||
vp, bp, err := altair.InitializePrecomputeValidators(ctx, headState)
|
vp, bp, err := altair.InitializePrecomputeValidators(ctx, headState)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -865,7 +865,7 @@ func (bs *Server) GetIndividualVotes(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.Errorf(codes.Internal, "Could not pre compute attestations: %v", err)
|
return nil, status.Errorf(codes.Internal, "Could not pre compute attestations: %v", err)
|
||||||
}
|
}
|
||||||
case version.Altair, version.Bellatrix:
|
case version.Altair, version.Bellatrix, version.EIP4844:
|
||||||
v, bal, err = altair.InitializePrecomputeValidators(ctx, st)
|
v, bal, err = altair.InitializePrecomputeValidators(ctx, st)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.Errorf(codes.Internal, "Could not set up altair pre compute instance: %v", err)
|
return nil, status.Errorf(codes.Internal, "Could not set up altair pre compute instance: %v", err)
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ go_library(
|
|||||||
"proposer_attestations.go",
|
"proposer_attestations.go",
|
||||||
"proposer_bellatrix.go",
|
"proposer_bellatrix.go",
|
||||||
"proposer_deposits.go",
|
"proposer_deposits.go",
|
||||||
|
"proposer_eip4844.go",
|
||||||
"proposer_eth1data.go",
|
"proposer_eth1data.go",
|
||||||
"proposer_execution_payload.go",
|
"proposer_execution_payload.go",
|
||||||
"proposer_phase0.go",
|
"proposer_phase0.go",
|
||||||
|
|||||||
@@ -53,14 +53,24 @@ func (vs *Server) GetBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (
|
|||||||
return nil, status.Errorf(codes.Internal, "Could not fetch Altair beacon block: %v", err)
|
return nil, status.Errorf(codes.Internal, "Could not fetch Altair beacon block: %v", err)
|
||||||
}
|
}
|
||||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Altair{Altair: blk}}, nil
|
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Altair{Altair: blk}}, nil
|
||||||
|
} else if slots.ToEpoch(req.Slot) < params.BeaconConfig().Eip4844ForkEpoch {
|
||||||
|
// An optimistic validator MUST NOT produce a block (i.e., sign across the DOMAIN_BEACON_PROPOSER domain).
|
||||||
|
if err := vs.optimisticStatus(ctx); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return vs.getBellatrixBeaconBlock(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// An optimistic validator MUST NOT produce a block (i.e., sign across the DOMAIN_BEACON_PROPOSER domain).
|
|
||||||
if err := vs.optimisticStatus(ctx); err != nil {
|
if err := vs.optimisticStatus(ctx); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
blk, sideCar, err := vs.getEip4844BeaconBlock(ctx, req)
|
||||||
return vs.getBellatrixBeaconBlock(ctx, req)
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "Could not fetch eip4844 beacon block: %v", err)
|
||||||
|
}
|
||||||
|
return ðpb.GenericBeaconBlock{
|
||||||
|
Block: ðpb.GenericBeaconBlock_Eip4844{Eip4844: blk},
|
||||||
|
Sidecar: sideCar,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProposeBeaconBlock is called by a proposer during its assigned slot to create a block in an attempt
|
// ProposeBeaconBlock is called by a proposer during its assigned slot to create a block in an attempt
|
||||||
@@ -72,7 +82,7 @@ func (vs *Server) ProposeBeaconBlock(ctx context.Context, req *ethpb.GenericSign
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.Errorf(codes.InvalidArgument, "Could not decode block: %v", err)
|
return nil, status.Errorf(codes.InvalidArgument, "Could not decode block: %v", err)
|
||||||
}
|
}
|
||||||
return vs.proposeGenericBeaconBlock(ctx, blk)
|
return vs.proposeGenericBeaconBlock(ctx, blk, req.Sidecar)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrepareBeaconProposer caches and updates the fee recipient for the given proposer.
|
// PrepareBeaconProposer caches and updates the fee recipient for the given proposer.
|
||||||
@@ -155,7 +165,7 @@ func (vs *Server) GetFeeRecipientByPubKey(ctx context.Context, request *ethpb.Fe
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vs *Server) proposeGenericBeaconBlock(ctx context.Context, blk interfaces.SignedBeaconBlock) (*ethpb.ProposeResponse, error) {
|
func (vs *Server) proposeGenericBeaconBlock(ctx context.Context, blk interfaces.SignedBeaconBlock, sidecar *ethpb.SignedBlobsSidecar) (*ethpb.ProposeResponse, error) {
|
||||||
ctx, span := trace.StartSpan(ctx, "ProposerServer.proposeGenericBeaconBlock")
|
ctx, span := trace.StartSpan(ctx, "ProposerServer.proposeGenericBeaconBlock")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
root, err := blk.Block().HashTreeRoot()
|
root, err := blk.Block().HashTreeRoot()
|
||||||
@@ -186,6 +196,14 @@ func (vs *Server) proposeGenericBeaconBlock(ctx context.Context, blk interfaces.
|
|||||||
if err := vs.P2P.Broadcast(ctx, blkPb); err != nil {
|
if err := vs.P2P.Broadcast(ctx, blkPb); err != nil {
|
||||||
return nil, fmt.Errorf("could not broadcast block: %v", err)
|
return nil, fmt.Errorf("could not broadcast block: %v", err)
|
||||||
}
|
}
|
||||||
|
if sidecar != nil {
|
||||||
|
if err := vs.P2P.Broadcast(ctx, sidecar); err != nil {
|
||||||
|
log.WithError(err).Error("Could not broadcast sidecar")
|
||||||
|
}
|
||||||
|
if err := blk.SetSideCar(sidecar); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
log.WithFields(logrus.Fields{
|
log.WithFields(logrus.Fields{
|
||||||
"blockRoot": hex.EncodeToString(root[:]),
|
"blockRoot": hex.EncodeToString(root[:]),
|
||||||
}).Debug("Broadcasting block")
|
}).Debug("Broadcasting block")
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ func (a proposerAtts) filter(ctx context.Context, st state.BeaconState) (propose
|
|||||||
switch st.Version() {
|
switch st.Version() {
|
||||||
case version.Phase0:
|
case version.Phase0:
|
||||||
attestationProcessor = blocks.ProcessAttestationNoVerifySignature
|
attestationProcessor = blocks.ProcessAttestationNoVerifySignature
|
||||||
case version.Altair, version.Bellatrix:
|
case version.Altair, version.Bellatrix, version.EIP4844:
|
||||||
// Use a wrapper here, as go needs strong typing for the function signature.
|
// Use a wrapper here, as go needs strong typing for the function signature.
|
||||||
attestationProcessor = func(ctx context.Context, st state.BeaconState, attestation *ethpb.Attestation) (state.BeaconState, error) {
|
attestationProcessor = func(ctx context.Context, st state.BeaconState, attestation *ethpb.Attestation) (state.BeaconState, error) {
|
||||||
totalBalance, err := helpers.TotalActiveBalance(st)
|
totalBalance, err := helpers.TotalActiveBalance(st)
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import (
|
|||||||
"github.com/prysmaticlabs/prysm/v3/runtime/version"
|
"github.com/prysmaticlabs/prysm/v3/runtime/version"
|
||||||
"github.com/prysmaticlabs/prysm/v3/time/slots"
|
"github.com/prysmaticlabs/prysm/v3/time/slots"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
"go.opencensus.io/trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
// builderGetPayloadMissCount tracks the number of misses when validator tries to get a payload from builder
|
// builderGetPayloadMissCount tracks the number of misses when validator tries to get a payload from builder
|
||||||
@@ -38,10 +39,12 @@ var builderGetPayloadMissCount = promauto.NewCounter(prometheus.CounterOpts{
|
|||||||
// block request. This value is known as `BUILDER_PROPOSAL_DELAY_TOLERANCE` in builder spec.
|
// block request. This value is known as `BUILDER_PROPOSAL_DELAY_TOLERANCE` in builder spec.
|
||||||
const blockBuilderTimeout = 1 * time.Second
|
const blockBuilderTimeout = 1 * time.Second
|
||||||
|
|
||||||
func (vs *Server) getBellatrixBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.GenericBeaconBlock, error) {
|
func (vs *Server) buildBellatrixBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.BeaconBlockBellatrix, enginev1.PayloadIDBytes, error) {
|
||||||
|
ctx, span := trace.StartSpan(ctx, "ProposerServer.buildBellatrixBeaconBlock")
|
||||||
|
defer span.End()
|
||||||
altairBlk, err := vs.BuildAltairBeaconBlock(ctx, req)
|
altairBlk, err := vs.BuildAltairBeaconBlock(ctx, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, enginev1.PayloadIDBytes{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !req.SkipMevBoost {
|
if !req.SkipMevBoost {
|
||||||
@@ -54,7 +57,7 @@ func (vs *Server) getBellatrixBeaconBlock(ctx context.Context, req *ethpb.BlockR
|
|||||||
"back to local execution client")
|
"back to local execution client")
|
||||||
builderGetPayloadMissCount.Inc()
|
builderGetPayloadMissCount.Inc()
|
||||||
} else if builderReady {
|
} else if builderReady {
|
||||||
return b, nil
|
return b.GetBellatrix(), enginev1.PayloadIDBytes{}, nil
|
||||||
}
|
}
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
log.WithError(err).WithFields(logrus.Fields{
|
log.WithError(err).WithFields(logrus.Fields{
|
||||||
@@ -63,12 +66,12 @@ func (vs *Server) getBellatrixBeaconBlock(ctx context.Context, req *ethpb.BlockR
|
|||||||
}).Error("Could not determine validator has registered. Defaulting to local execution client")
|
}).Error("Could not determine validator has registered. Defaulting to local execution client")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
payload, err := vs.getExecutionPayload(ctx, req.Slot, altairBlk.ProposerIndex, bytesutil.ToBytes32(altairBlk.ParentRoot))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
blk := ðpb.BeaconBlockBellatrix{
|
payload, payloadID, err := vs.getExecutionPayload(ctx, req.Slot, altairBlk.ProposerIndex, bytesutil.ToBytes32(altairBlk.ParentRoot))
|
||||||
|
if err != nil {
|
||||||
|
return nil, enginev1.PayloadIDBytes{}, err
|
||||||
|
}
|
||||||
|
return ðpb.BeaconBlockBellatrix{
|
||||||
Slot: altairBlk.Slot,
|
Slot: altairBlk.Slot,
|
||||||
ProposerIndex: altairBlk.ProposerIndex,
|
ProposerIndex: altairBlk.ProposerIndex,
|
||||||
ParentRoot: altairBlk.ParentRoot,
|
ParentRoot: altairBlk.ParentRoot,
|
||||||
@@ -85,6 +88,15 @@ func (vs *Server) getBellatrixBeaconBlock(ctx context.Context, req *ethpb.BlockR
|
|||||||
SyncAggregate: altairBlk.Body.SyncAggregate,
|
SyncAggregate: altairBlk.Body.SyncAggregate,
|
||||||
ExecutionPayload: payload,
|
ExecutionPayload: payload,
|
||||||
},
|
},
|
||||||
|
}, payloadID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vs *Server) getBellatrixBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.GenericBeaconBlock, error) {
|
||||||
|
ctx, span := trace.StartSpan(ctx, "ProposerServer.getBellatrixBeaconBlock")
|
||||||
|
defer span.End()
|
||||||
|
blk, _, err := vs.buildBellatrixBeaconBlock(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not build block data: %v", err)
|
||||||
}
|
}
|
||||||
// Compute state root with the newly constructed block.
|
// Compute state root with the newly constructed block.
|
||||||
wsb, err := consensusblocks.NewSignedBeaconBlock(
|
wsb, err := consensusblocks.NewSignedBeaconBlock(
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
package validator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/transition/interop"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
||||||
|
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||||
|
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (vs *Server) getEip4844BeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.BeaconBlockWithBlobKZGs, *ethpb.BlobsSidecar, error) {
|
||||||
|
bellatrixBlk, payloadID, err := vs.buildBellatrixBeaconBlock(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, errors.Wrap(err, "could not get bellatrix block")
|
||||||
|
}
|
||||||
|
|
||||||
|
blobsBundle, err := vs.ExecutionEngineCaller.GetBlobsBundle(ctx, payloadID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, errors.Wrap(err, "could not get blobs")
|
||||||
|
}
|
||||||
|
// sanity check the blobs bundle
|
||||||
|
if bytes.Compare(blobsBundle.BlockHash, bellatrixBlk.Body.ExecutionPayload.BlockHash) != 0 {
|
||||||
|
return nil, nil, errors.New("invalid blobs bundle received")
|
||||||
|
}
|
||||||
|
if len(blobsBundle.Blobs) != len(blobsBundle.Kzgs) {
|
||||||
|
return nil, nil, errors.New("mismatched blobs and kzgs length")
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
kzgs [][]byte
|
||||||
|
blobs []*enginev1.Blob
|
||||||
|
)
|
||||||
|
if len(blobsBundle.Kzgs) != 0 {
|
||||||
|
kzgs = blobsBundle.Kzgs
|
||||||
|
blobs = blobsBundle.Blobs
|
||||||
|
}
|
||||||
|
|
||||||
|
blk := ðpb.BeaconBlockWithBlobKZGs{
|
||||||
|
Slot: bellatrixBlk.Slot,
|
||||||
|
ProposerIndex: bellatrixBlk.ProposerIndex,
|
||||||
|
ParentRoot: bellatrixBlk.ParentRoot,
|
||||||
|
StateRoot: params.BeaconConfig().ZeroHash[:],
|
||||||
|
Body: ðpb.BeaconBlockBodyWithBlobKZGs{
|
||||||
|
RandaoReveal: bellatrixBlk.Body.RandaoReveal,
|
||||||
|
Eth1Data: bellatrixBlk.Body.Eth1Data,
|
||||||
|
Graffiti: bellatrixBlk.Body.Graffiti,
|
||||||
|
ProposerSlashings: bellatrixBlk.Body.ProposerSlashings,
|
||||||
|
AttesterSlashings: bellatrixBlk.Body.AttesterSlashings,
|
||||||
|
Attestations: bellatrixBlk.Body.Attestations,
|
||||||
|
Deposits: bellatrixBlk.Body.Deposits,
|
||||||
|
VoluntaryExits: bellatrixBlk.Body.VoluntaryExits,
|
||||||
|
SyncAggregate: bellatrixBlk.Body.SyncAggregate,
|
||||||
|
ExecutionPayload: bellatrixBlk.Body.ExecutionPayload,
|
||||||
|
BlobKzgs: kzgs,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
// Compute state root with the newly constructed block.
|
||||||
|
wsb, err := blocks.NewSignedBeaconBlock(
|
||||||
|
ðpb.SignedBeaconBlockWithBlobKZGs{
|
||||||
|
Block: blk,
|
||||||
|
Signature: make([]byte, 96),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
stateRoot, err := vs.computeStateRoot(ctx, wsb)
|
||||||
|
if err != nil {
|
||||||
|
interop.WriteBlockToDisk(wsb, true /*failed*/)
|
||||||
|
return nil, nil, fmt.Errorf("could not compute state root: %v", err)
|
||||||
|
}
|
||||||
|
blk.StateRoot = stateRoot
|
||||||
|
r, err := blk.HashTreeRoot()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var sideCar *ethpb.BlobsSidecar
|
||||||
|
if len(blobs) != 0 {
|
||||||
|
sideCar = ðpb.BlobsSidecar{
|
||||||
|
BeaconBlockRoot: r[:],
|
||||||
|
BeaconBlockSlot: blk.Slot,
|
||||||
|
Blobs: blobs,
|
||||||
|
AggregatedProof: blobsBundle.AggregatedProof,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return blk, sideCar, nil
|
||||||
|
}
|
||||||
@@ -40,7 +40,7 @@ var (
|
|||||||
|
|
||||||
// This returns the execution payload of a given slot. The function has full awareness of pre and post merge.
|
// This returns the execution payload of a given slot. The function has full awareness of pre and post merge.
|
||||||
// The payload is computed given the respected time of merge.
|
// The payload is computed given the respected time of merge.
|
||||||
func (vs *Server) getExecutionPayload(ctx context.Context, slot types.Slot, vIdx types.ValidatorIndex, headRoot [32]byte) (*enginev1.ExecutionPayload, error) {
|
func (vs *Server) getExecutionPayload(ctx context.Context, slot types.Slot, vIdx types.ValidatorIndex, headRoot [32]byte) (*enginev1.ExecutionPayload, enginev1.PayloadIDBytes, error) {
|
||||||
proposerID, payloadId, ok := vs.ProposerSlotIndexCache.GetProposerPayloadIDs(slot, headRoot)
|
proposerID, payloadId, ok := vs.ProposerSlotIndexCache.GetProposerPayloadIDs(slot, headRoot)
|
||||||
feeRecipient := params.BeaconConfig().DefaultFeeRecipient
|
feeRecipient := params.BeaconConfig().DefaultFeeRecipient
|
||||||
recipient, err := vs.BeaconDB.FeeRecipientByValidatorID(ctx, vIdx)
|
recipient, err := vs.BeaconDB.FeeRecipientByValidatorID(ctx, vIdx)
|
||||||
@@ -60,7 +60,7 @@ func (vs *Server) getExecutionPayload(ctx context.Context, slot types.Slot, vIdx
|
|||||||
"Please refer to our documentation for instructions")
|
"Please refer to our documentation for instructions")
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return nil, errors.Wrap(err, "could not get fee recipient in db")
|
return nil, enginev1.PayloadIDBytes{}, errors.Wrap(err, "could not get fee recipient in db")
|
||||||
}
|
}
|
||||||
|
|
||||||
if ok && proposerID == vIdx && payloadId != [8]byte{} { // Payload ID is cache hit. Return the cached payload ID.
|
if ok && proposerID == vIdx && payloadId != [8]byte{} { // Payload ID is cache hit. Return the cached payload ID.
|
||||||
@@ -71,78 +71,78 @@ func (vs *Server) getExecutionPayload(ctx context.Context, slot types.Slot, vIdx
|
|||||||
switch {
|
switch {
|
||||||
case err == nil:
|
case err == nil:
|
||||||
warnIfFeeRecipientDiffers(payload, feeRecipient)
|
warnIfFeeRecipientDiffers(payload, feeRecipient)
|
||||||
return payload, nil
|
return payload, payloadId, err
|
||||||
case errors.Is(err, context.DeadlineExceeded):
|
case errors.Is(err, context.DeadlineExceeded):
|
||||||
default:
|
default:
|
||||||
return nil, errors.Wrap(err, "could not get cached payload from execution client")
|
return nil, enginev1.PayloadIDBytes{}, errors.Wrap(err, "could not get cached payload from execution client")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
st, err := vs.HeadFetcher.HeadState(ctx)
|
st, err := vs.HeadFetcher.HeadState(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, enginev1.PayloadIDBytes{}, err
|
||||||
}
|
}
|
||||||
st, err = transition.ProcessSlotsIfPossible(ctx, st, slot)
|
st, err = transition.ProcessSlotsIfPossible(ctx, st, slot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, enginev1.PayloadIDBytes{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var parentHash []byte
|
var parentHash []byte
|
||||||
var hasTerminalBlock bool
|
var hasTerminalBlock bool
|
||||||
mergeComplete, err := blocks.IsMergeTransitionComplete(st)
|
mergeComplete, err := blocks.IsMergeTransitionComplete(st)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, enginev1.PayloadIDBytes{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
t, err := slots.ToTime(st.GenesisTime(), slot)
|
t, err := slots.ToTime(st.GenesisTime(), slot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, enginev1.PayloadIDBytes{}, err
|
||||||
}
|
}
|
||||||
if mergeComplete {
|
if mergeComplete {
|
||||||
header, err := st.LatestExecutionPayloadHeader()
|
header, err := st.LatestExecutionPayloadHeader()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, enginev1.PayloadIDBytes{}, err
|
||||||
}
|
}
|
||||||
parentHash = header.BlockHash
|
parentHash = header.BlockHash
|
||||||
} else {
|
} else {
|
||||||
if activationEpochNotReached(slot) {
|
if activationEpochNotReached(slot) {
|
||||||
return emptyPayload(), nil
|
return emptyPayload(), enginev1.PayloadIDBytes{}, nil
|
||||||
}
|
}
|
||||||
parentHash, hasTerminalBlock, err = vs.getTerminalBlockHashIfExists(ctx, uint64(t.Unix()))
|
parentHash, hasTerminalBlock, err = vs.getTerminalBlockHashIfExists(ctx, uint64(t.Unix()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, enginev1.PayloadIDBytes{}, err
|
||||||
}
|
}
|
||||||
if !hasTerminalBlock {
|
if !hasTerminalBlock {
|
||||||
return emptyPayload(), nil
|
return emptyPayload(), enginev1.PayloadIDBytes{}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
payloadIDCacheMiss.Inc()
|
payloadIDCacheMiss.Inc()
|
||||||
|
|
||||||
random, err := helpers.RandaoMix(st, time.CurrentEpoch(st))
|
random, err := helpers.RandaoMix(st, time.CurrentEpoch(st))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, enginev1.PayloadIDBytes{}, err
|
||||||
}
|
}
|
||||||
finalizedBlockHash := params.BeaconConfig().ZeroHash[:]
|
finalizedBlockHash := params.BeaconConfig().ZeroHash[:]
|
||||||
finalizedRoot := bytesutil.ToBytes32(st.FinalizedCheckpoint().Root)
|
finalizedRoot := bytesutil.ToBytes32(st.FinalizedCheckpoint().Root)
|
||||||
if finalizedRoot != [32]byte{} { // finalized root could be zeros before the first finalized block.
|
if finalizedRoot != [32]byte{} { // finalized root could be zeros before the first finalized block.
|
||||||
finalizedBlock, err := vs.BeaconDB.Block(ctx, bytesutil.ToBytes32(st.FinalizedCheckpoint().Root))
|
finalizedBlock, err := vs.BeaconDB.Block(ctx, bytesutil.ToBytes32(st.FinalizedCheckpoint().Root))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, enginev1.PayloadIDBytes{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := consensusblocks.BeaconBlockIsNil(finalizedBlock); err != nil {
|
if err := consensusblocks.BeaconBlockIsNil(finalizedBlock); err != nil {
|
||||||
return nil, err
|
return nil, enginev1.PayloadIDBytes{}, err
|
||||||
}
|
}
|
||||||
switch finalizedBlock.Version() {
|
switch finalizedBlock.Version() {
|
||||||
case version.Phase0, version.Altair: // Blocks before Bellatrix don't have execution payloads. Use zeros as the hash.
|
case version.Phase0, version.Altair: // Blocks before Bellatrix don't have execution payloads. Use zeros as the hash.
|
||||||
default:
|
default:
|
||||||
finalizedPayload, err := finalizedBlock.Block().Body().Execution()
|
finalizedPayload, err := finalizedBlock.Block().Body().Execution()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, enginev1.PayloadIDBytes{}, err
|
||||||
}
|
}
|
||||||
finalizedBlockHash = finalizedPayload.BlockHash()
|
finalizedBlockHash = finalizedPayload.BlockHash()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
f := &enginev1.ForkchoiceState{
|
f := &enginev1.ForkchoiceState{
|
||||||
HeadBlockHash: parentHash,
|
HeadBlockHash: parentHash,
|
||||||
SafeBlockHash: parentHash,
|
SafeBlockHash: parentHash,
|
||||||
@@ -156,17 +156,17 @@ func (vs *Server) getExecutionPayload(ctx context.Context, slot types.Slot, vIdx
|
|||||||
}
|
}
|
||||||
payloadID, _, err := vs.ExecutionEngineCaller.ForkchoiceUpdated(ctx, f, p)
|
payloadID, _, err := vs.ExecutionEngineCaller.ForkchoiceUpdated(ctx, f, p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "could not prepare payload")
|
return nil, enginev1.PayloadIDBytes{}, errors.Wrap(err, "could not prepare payload")
|
||||||
}
|
}
|
||||||
if payloadID == nil {
|
if payloadID == nil {
|
||||||
return nil, fmt.Errorf("nil payload with block hash: %#x", parentHash)
|
return nil, enginev1.PayloadIDBytes{}, fmt.Errorf("nil payload with block hash: %#x", parentHash)
|
||||||
}
|
}
|
||||||
payload, err := vs.ExecutionEngineCaller.GetPayload(ctx, *payloadID)
|
payload, err := vs.ExecutionEngineCaller.GetPayload(ctx, *payloadID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, enginev1.PayloadIDBytes{}, err
|
||||||
}
|
}
|
||||||
warnIfFeeRecipientDiffers(payload, feeRecipient)
|
warnIfFeeRecipientDiffers(payload, feeRecipient)
|
||||||
return payload, nil
|
return payload, enginev1.PayloadIDBytes{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// warnIfFeeRecipientDiffers logs a warning if the fee recipient in the included payload does not
|
// warnIfFeeRecipientDiffers logs a warning if the fee recipient in the included payload does not
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ func TestServer_getExecutionPayload(t *testing.T) {
|
|||||||
ProposerSlotIndexCache: cache.NewProposerPayloadIDsCache(),
|
ProposerSlotIndexCache: cache.NewProposerPayloadIDsCache(),
|
||||||
}
|
}
|
||||||
vs.ProposerSlotIndexCache.SetProposerAndPayloadIDs(tt.st.Slot(), 100, [8]byte{100}, [32]byte{'a'})
|
vs.ProposerSlotIndexCache.SetProposerAndPayloadIDs(tt.st.Slot(), 100, [8]byte{100}, [32]byte{'a'})
|
||||||
_, err := vs.getExecutionPayload(context.Background(), tt.st.Slot(), tt.validatorIndx, [32]byte{'a'})
|
_, _, err := vs.getExecutionPayload(context.Background(), tt.st.Slot(), tt.validatorIndx, [32]byte{'a'})
|
||||||
if tt.errString != "" {
|
if tt.errString != "" {
|
||||||
require.ErrorContains(t, tt.errString, err)
|
require.ErrorContains(t, tt.errString, err)
|
||||||
} else {
|
} else {
|
||||||
@@ -160,7 +160,7 @@ func TestServer_getExecutionPayloadContextTimeout(t *testing.T) {
|
|||||||
}
|
}
|
||||||
vs.ProposerSlotIndexCache.SetProposerAndPayloadIDs(nonTransitionSt.Slot(), 100, [8]byte{100}, [32]byte{'a'})
|
vs.ProposerSlotIndexCache.SetProposerAndPayloadIDs(nonTransitionSt.Slot(), 100, [8]byte{100}, [32]byte{'a'})
|
||||||
|
|
||||||
_, err = vs.getExecutionPayload(context.Background(), nonTransitionSt.Slot(), 100, [32]byte{'a'})
|
_, _, err = vs.getExecutionPayload(context.Background(), nonTransitionSt.Slot(), 100, [32]byte{'a'})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,7 +205,7 @@ func TestServer_getExecutionPayload_UnexpectedFeeRecipient(t *testing.T) {
|
|||||||
BeaconDB: beaconDB,
|
BeaconDB: beaconDB,
|
||||||
ProposerSlotIndexCache: cache.NewProposerPayloadIDsCache(),
|
ProposerSlotIndexCache: cache.NewProposerPayloadIDsCache(),
|
||||||
}
|
}
|
||||||
gotPayload, err := vs.getExecutionPayload(context.Background(), transitionSt.Slot(), 0, [32]byte{})
|
gotPayload, _, err := vs.getExecutionPayload(context.Background(), transitionSt.Slot(), 0, [32]byte{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotNil(t, gotPayload)
|
require.NotNil(t, gotPayload)
|
||||||
|
|
||||||
@@ -217,7 +217,7 @@ func TestServer_getExecutionPayload_UnexpectedFeeRecipient(t *testing.T) {
|
|||||||
payload.FeeRecipient = evilRecipientAddress[:]
|
payload.FeeRecipient = evilRecipientAddress[:]
|
||||||
vs.ProposerSlotIndexCache = cache.NewProposerPayloadIDsCache()
|
vs.ProposerSlotIndexCache = cache.NewProposerPayloadIDsCache()
|
||||||
|
|
||||||
gotPayload, err = vs.getExecutionPayload(context.Background(), transitionSt.Slot(), 0, [32]byte{})
|
gotPayload, _, err = vs.getExecutionPayload(context.Background(), transitionSt.Slot(), 0, [32]byte{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotNil(t, gotPayload)
|
require.NotNil(t, gotPayload)
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
|
|
||||||
func (b *BeaconState) ProportionalSlashingMultiplier() (uint64, error) {
|
func (b *BeaconState) ProportionalSlashingMultiplier() (uint64, error) {
|
||||||
switch b.version {
|
switch b.version {
|
||||||
case version.Bellatrix:
|
case version.EIP4844, version.Bellatrix:
|
||||||
return params.BeaconConfig().ProportionalSlashingMultiplierBellatrix, nil
|
return params.BeaconConfig().ProportionalSlashingMultiplierBellatrix, nil
|
||||||
case version.Altair:
|
case version.Altair:
|
||||||
return params.BeaconConfig().ProportionalSlashingMultiplierAltair, nil
|
return params.BeaconConfig().ProportionalSlashingMultiplierAltair, nil
|
||||||
@@ -19,7 +19,7 @@ func (b *BeaconState) ProportionalSlashingMultiplier() (uint64, error) {
|
|||||||
|
|
||||||
func (b *BeaconState) InactivityPenaltyQuotient() (uint64, error) {
|
func (b *BeaconState) InactivityPenaltyQuotient() (uint64, error) {
|
||||||
switch b.version {
|
switch b.version {
|
||||||
case version.Bellatrix:
|
case version.EIP4844, version.Bellatrix:
|
||||||
return params.BeaconConfig().InactivityPenaltyQuotientBellatrix, nil
|
return params.BeaconConfig().InactivityPenaltyQuotientBellatrix, nil
|
||||||
case version.Altair:
|
case version.Altair:
|
||||||
return params.BeaconConfig().InactivityPenaltyQuotientAltair, nil
|
return params.BeaconConfig().InactivityPenaltyQuotientAltair, nil
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ func ReplayProcessSlots(ctx context.Context, state state.BeaconState, slot types
|
|||||||
tracing.AnnotateError(span, err)
|
tracing.AnnotateError(span, err)
|
||||||
return nil, errors.Wrap(err, "could not process epoch with optimizations")
|
return nil, errors.Wrap(err, "could not process epoch with optimizations")
|
||||||
}
|
}
|
||||||
case version.Altair, version.Bellatrix:
|
case version.Altair, version.Bellatrix, version.EIP4844:
|
||||||
state, err = altair.ProcessEpoch(ctx, state)
|
state, err = altair.ProcessEpoch(ctx, state)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tracing.AnnotateError(span, err)
|
tracing.AnnotateError(span, err)
|
||||||
@@ -233,6 +233,14 @@ func ReplayProcessSlots(ctx context.Context, state state.BeaconState, slot types
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if prysmtime.CanUpgradeToEip4844(state.Slot()) {
|
||||||
|
state, err = execution.UpgradeToEip4844(state)
|
||||||
|
if err != nil {
|
||||||
|
tracing.AnnotateError(span, err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return state, nil
|
return state, nil
|
||||||
|
|||||||
@@ -67,12 +67,12 @@ func (f FieldIndex) String(stateVersion int) string {
|
|||||||
case Slashings:
|
case Slashings:
|
||||||
return "slashings"
|
return "slashings"
|
||||||
case PreviousEpochAttestations:
|
case PreviousEpochAttestations:
|
||||||
if version.Altair == stateVersion || version.Bellatrix == stateVersion {
|
if version.Altair == stateVersion || version.Bellatrix == stateVersion || version.EIP4844 == stateVersion {
|
||||||
return "previousEpochParticipationBits"
|
return "previousEpochParticipationBits"
|
||||||
}
|
}
|
||||||
return "previousEpochAttestations"
|
return "previousEpochAttestations"
|
||||||
case CurrentEpochAttestations:
|
case CurrentEpochAttestations:
|
||||||
if version.Altair == stateVersion || version.Bellatrix == stateVersion {
|
if version.Altair == stateVersion || version.Bellatrix == stateVersion || version.EIP4844 == stateVersion {
|
||||||
return "currentEpochParticipationBits"
|
return "currentEpochParticipationBits"
|
||||||
}
|
}
|
||||||
return "currentEpochAttestations"
|
return "currentEpochAttestations"
|
||||||
|
|||||||
@@ -16,10 +16,12 @@ go_library(
|
|||||||
"options.go",
|
"options.go",
|
||||||
"pending_attestations_queue.go",
|
"pending_attestations_queue.go",
|
||||||
"pending_blocks_queue.go",
|
"pending_blocks_queue.go",
|
||||||
|
"pending_sidecars_queue.go",
|
||||||
"rate_limiter.go",
|
"rate_limiter.go",
|
||||||
"rpc.go",
|
"rpc.go",
|
||||||
"rpc_beacon_blocks_by_range.go",
|
"rpc_beacon_blocks_by_range.go",
|
||||||
"rpc_beacon_blocks_by_root.go",
|
"rpc_beacon_blocks_by_root.go",
|
||||||
|
"rpc_blobs_sidecars_by_range.go",
|
||||||
"rpc_chunked_response.go",
|
"rpc_chunked_response.go",
|
||||||
"rpc_goodbye.go",
|
"rpc_goodbye.go",
|
||||||
"rpc_metadata.go",
|
"rpc_metadata.go",
|
||||||
@@ -31,6 +33,7 @@ go_library(
|
|||||||
"subscriber_beacon_aggregate_proof.go",
|
"subscriber_beacon_aggregate_proof.go",
|
||||||
"subscriber_beacon_attestation.go",
|
"subscriber_beacon_attestation.go",
|
||||||
"subscriber_beacon_blocks.go",
|
"subscriber_beacon_blocks.go",
|
||||||
|
"subscriber_blobs_sidecar.go",
|
||||||
"subscriber_handlers.go",
|
"subscriber_handlers.go",
|
||||||
"subscriber_sync_committee_message.go",
|
"subscriber_sync_committee_message.go",
|
||||||
"subscriber_sync_contribution_proof.go",
|
"subscriber_sync_contribution_proof.go",
|
||||||
@@ -40,6 +43,7 @@ go_library(
|
|||||||
"validate_attester_slashing.go",
|
"validate_attester_slashing.go",
|
||||||
"validate_beacon_attestation.go",
|
"validate_beacon_attestation.go",
|
||||||
"validate_beacon_blocks.go",
|
"validate_beacon_blocks.go",
|
||||||
|
"validate_blobs_sidecar.go",
|
||||||
"validate_proposer_slashing.go",
|
"validate_proposer_slashing.go",
|
||||||
"validate_sync_committee_message.go",
|
"validate_sync_committee_message.go",
|
||||||
"validate_sync_contribution_proof.go",
|
"validate_sync_contribution_proof.go",
|
||||||
@@ -84,6 +88,7 @@ go_library(
|
|||||||
"//cmd/beacon-chain/flags:go_default_library",
|
"//cmd/beacon-chain/flags:go_default_library",
|
||||||
"//config/features:go_default_library",
|
"//config/features:go_default_library",
|
||||||
"//config/params:go_default_library",
|
"//config/params:go_default_library",
|
||||||
|
"//consensus-types/blobs:go_default_library",
|
||||||
"//consensus-types/blocks:go_default_library",
|
"//consensus-types/blocks:go_default_library",
|
||||||
"//consensus-types/interfaces:go_default_library",
|
"//consensus-types/interfaces:go_default_library",
|
||||||
"//consensus-types/primitives:go_default_library",
|
"//consensus-types/primitives:go_default_library",
|
||||||
@@ -95,6 +100,7 @@ go_library(
|
|||||||
"//encoding/ssz/equality:go_default_library",
|
"//encoding/ssz/equality:go_default_library",
|
||||||
"//monitoring/tracing:go_default_library",
|
"//monitoring/tracing:go_default_library",
|
||||||
"//network/forks:go_default_library",
|
"//network/forks:go_default_library",
|
||||||
|
"//proto/engine/v1:go_default_library",
|
||||||
"//proto/prysm/v1alpha1:go_default_library",
|
"//proto/prysm/v1alpha1:go_default_library",
|
||||||
"//proto/prysm/v1alpha1/attestation:go_default_library",
|
"//proto/prysm/v1alpha1/attestation:go_default_library",
|
||||||
"//proto/prysm/v1alpha1/metadata:go_default_library",
|
"//proto/prysm/v1alpha1/metadata:go_default_library",
|
||||||
@@ -115,6 +121,7 @@ go_library(
|
|||||||
"@com_github_pkg_errors//:go_default_library",
|
"@com_github_pkg_errors//:go_default_library",
|
||||||
"@com_github_prometheus_client_golang//prometheus:go_default_library",
|
"@com_github_prometheus_client_golang//prometheus:go_default_library",
|
||||||
"@com_github_prometheus_client_golang//prometheus/promauto:go_default_library",
|
"@com_github_prometheus_client_golang//prometheus/promauto:go_default_library",
|
||||||
|
"@com_github_protolambda_go_kzg//bls:go_default_library",
|
||||||
"@com_github_prysmaticlabs_fastssz//:go_default_library",
|
"@com_github_prysmaticlabs_fastssz//:go_default_library",
|
||||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||||
"@com_github_sirupsen_logrus//:go_default_library",
|
"@com_github_sirupsen_logrus//:go_default_library",
|
||||||
@@ -138,6 +145,7 @@ go_test(
|
|||||||
"rate_limiter_test.go",
|
"rate_limiter_test.go",
|
||||||
"rpc_beacon_blocks_by_range_test.go",
|
"rpc_beacon_blocks_by_range_test.go",
|
||||||
"rpc_beacon_blocks_by_root_test.go",
|
"rpc_beacon_blocks_by_root_test.go",
|
||||||
|
"rpc_blobs_sidecars_by_range_test.go",
|
||||||
"rpc_chunked_response_test.go",
|
"rpc_chunked_response_test.go",
|
||||||
"rpc_goodbye_test.go",
|
"rpc_goodbye_test.go",
|
||||||
"rpc_metadata_test.go",
|
"rpc_metadata_test.go",
|
||||||
@@ -223,6 +231,7 @@ go_test(
|
|||||||
"@com_github_golang_snappy//:go_default_library",
|
"@com_github_golang_snappy//:go_default_library",
|
||||||
"@com_github_kevinms_leakybucket_go//:go_default_library",
|
"@com_github_kevinms_leakybucket_go//:go_default_library",
|
||||||
"@com_github_libp2p_go_libp2p_core//:go_default_library",
|
"@com_github_libp2p_go_libp2p_core//:go_default_library",
|
||||||
|
"@com_github_libp2p_go_libp2p_core//mux:go_default_library",
|
||||||
"@com_github_libp2p_go_libp2p_core//network:go_default_library",
|
"@com_github_libp2p_go_libp2p_core//network:go_default_library",
|
||||||
"@com_github_libp2p_go_libp2p_core//peer:go_default_library",
|
"@com_github_libp2p_go_libp2p_core//peer:go_default_library",
|
||||||
"@com_github_libp2p_go_libp2p_core//protocol:go_default_library",
|
"@com_github_libp2p_go_libp2p_core//protocol:go_default_library",
|
||||||
@@ -230,6 +239,7 @@ go_test(
|
|||||||
"@com_github_libp2p_go_libp2p_pubsub//pb:go_default_library",
|
"@com_github_libp2p_go_libp2p_pubsub//pb:go_default_library",
|
||||||
"@com_github_patrickmn_go_cache//:go_default_library",
|
"@com_github_patrickmn_go_cache//:go_default_library",
|
||||||
"@com_github_pkg_errors//:go_default_library",
|
"@com_github_pkg_errors//:go_default_library",
|
||||||
|
"@com_github_protolambda_ztyp//codec:go_default_library",
|
||||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||||
"@com_github_sirupsen_logrus//:go_default_library",
|
"@com_github_sirupsen_logrus//:go_default_library",
|
||||||
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
|
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
|
||||||
|
|||||||
@@ -69,6 +69,17 @@ func (s *Service) registerForUpcomingFork(currEpoch types.Epoch) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
s.registerSubscribers(nextEpoch, digest)
|
s.registerSubscribers(nextEpoch, digest)
|
||||||
|
case params.BeaconConfig().Eip4844ForkEpoch:
|
||||||
|
digest, err := forks.ForkDigestFromEpoch(nextEpoch, genRoot[:])
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "could not retrieve fork digest")
|
||||||
|
}
|
||||||
|
if s.subHandler.digestExists(digest) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
s.registerSubscribers(nextEpoch, digest)
|
||||||
|
|
||||||
|
s.registerRPCHandlersEIP4844()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -29,12 +29,16 @@ go_library(
|
|||||||
"//beacon-chain/sync:go_default_library",
|
"//beacon-chain/sync:go_default_library",
|
||||||
"//cmd/beacon-chain/flags:go_default_library",
|
"//cmd/beacon-chain/flags:go_default_library",
|
||||||
"//config/params:go_default_library",
|
"//config/params:go_default_library",
|
||||||
|
"//consensus-types/blobs:go_default_library",
|
||||||
|
"//consensus-types/blocks:go_default_library",
|
||||||
"//consensus-types/interfaces:go_default_library",
|
"//consensus-types/interfaces:go_default_library",
|
||||||
"//consensus-types/primitives:go_default_library",
|
"//consensus-types/primitives: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",
|
||||||
"//proto/prysm/v1alpha1:go_default_library",
|
"//proto/prysm/v1alpha1:go_default_library",
|
||||||
"//runtime:go_default_library",
|
"//runtime:go_default_library",
|
||||||
|
"//runtime/version:go_default_library",
|
||||||
"//time:go_default_library",
|
"//time:go_default_library",
|
||||||
"//time/slots:go_default_library",
|
"//time/slots:go_default_library",
|
||||||
"@com_github_kevinms_leakybucket_go//:go_default_library",
|
"@com_github_kevinms_leakybucket_go//:go_default_library",
|
||||||
|
|||||||
@@ -15,9 +15,12 @@ import (
|
|||||||
prysmsync "github.com/prysmaticlabs/prysm/v3/beacon-chain/sync"
|
prysmsync "github.com/prysmaticlabs/prysm/v3/beacon-chain/sync"
|
||||||
"github.com/prysmaticlabs/prysm/v3/cmd/beacon-chain/flags"
|
"github.com/prysmaticlabs/prysm/v3/cmd/beacon-chain/flags"
|
||||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/consensus-types/blobs"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
||||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
||||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||||
"github.com/prysmaticlabs/prysm/v3/crypto/rand"
|
"github.com/prysmaticlabs/prysm/v3/crypto/rand"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||||
p2ppb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
p2ppb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"go.opencensus.io/trace"
|
"go.opencensus.io/trace"
|
||||||
@@ -52,6 +55,9 @@ var (
|
|||||||
errBlockAlreadyProcessed = errors.New("block is already processed")
|
errBlockAlreadyProcessed = errors.New("block is already processed")
|
||||||
errParentDoesNotExist = errors.New("beacon node doesn't have a parent in db with root")
|
errParentDoesNotExist = errors.New("beacon node doesn't have a parent in db with root")
|
||||||
errNoPeersWithAltBlocks = errors.New("no peers with alternative blocks found")
|
errNoPeersWithAltBlocks = errors.New("no peers with alternative blocks found")
|
||||||
|
errInvalidSidecar = errors.New("sidecar verification failed")
|
||||||
|
errMissingSidecar = errors.New("block recieved without sidecar")
|
||||||
|
errUnexpectedSidecar = errors.New("received unexpected sidecar")
|
||||||
)
|
)
|
||||||
|
|
||||||
// blocksFetcherConfig is a config to setup the block fetcher.
|
// blocksFetcherConfig is a config to setup the block fetcher.
|
||||||
@@ -100,11 +106,12 @@ type fetchRequestParams struct {
|
|||||||
// fetchRequestResponse is a combined type to hold results of both successful executions and errors.
|
// fetchRequestResponse is a combined type to hold results of both successful executions and errors.
|
||||||
// Valid usage pattern will be to check whether result's `err` is nil, before using `blocks`.
|
// Valid usage pattern will be to check whether result's `err` is nil, before using `blocks`.
|
||||||
type fetchRequestResponse struct {
|
type fetchRequestResponse struct {
|
||||||
pid peer.ID
|
pid peer.ID
|
||||||
start types.Slot
|
start types.Slot
|
||||||
count uint64
|
count uint64
|
||||||
blocks []interfaces.SignedBeaconBlock
|
blocks []interfaces.SignedBeaconBlock
|
||||||
err error
|
sidecars []*p2ppb.BlobsSidecar
|
||||||
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
// newBlocksFetcher creates ready to use fetcher.
|
// newBlocksFetcher creates ready to use fetcher.
|
||||||
@@ -242,10 +249,11 @@ func (f *blocksFetcher) handleRequest(ctx context.Context, start types.Slot, cou
|
|||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
response := &fetchRequestResponse{
|
response := &fetchRequestResponse{
|
||||||
start: start,
|
start: start,
|
||||||
count: count,
|
count: count,
|
||||||
blocks: []interfaces.SignedBeaconBlock{},
|
blocks: []interfaces.SignedBeaconBlock{},
|
||||||
err: nil,
|
sidecars: []*p2ppb.BlobsSidecar{},
|
||||||
|
err: nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.Err() != nil {
|
if ctx.Err() != nil {
|
||||||
@@ -269,7 +277,7 @@ func (f *blocksFetcher) handleRequest(ctx context.Context, start types.Slot, cou
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
response.blocks, response.pid, response.err = f.fetchBlocksFromPeer(ctx, start, count, peers)
|
response.blocks, response.sidecars, response.pid, response.err = f.fetchBlocksFromPeer(ctx, start, count, peers)
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,7 +286,7 @@ func (f *blocksFetcher) fetchBlocksFromPeer(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
start types.Slot, count uint64,
|
start types.Slot, count uint64,
|
||||||
peers []peer.ID,
|
peers []peer.ID,
|
||||||
) ([]interfaces.SignedBeaconBlock, peer.ID, error) {
|
) ([]interfaces.SignedBeaconBlock, []*p2ppb.BlobsSidecar, peer.ID, error) {
|
||||||
ctx, span := trace.StartSpan(ctx, "initialsync.fetchBlocksFromPeer")
|
ctx, span := trace.StartSpan(ctx, "initialsync.fetchBlocksFromPeer")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
@@ -288,16 +296,34 @@ func (f *blocksFetcher) fetchBlocksFromPeer(
|
|||||||
Count: count,
|
Count: count,
|
||||||
Step: 1,
|
Step: 1,
|
||||||
}
|
}
|
||||||
|
sidecarReq := &p2ppb.BlobsSidecarsByRangeRequest{
|
||||||
|
StartSlot: start,
|
||||||
|
Count: count,
|
||||||
|
}
|
||||||
|
|
||||||
|
var sidecars []*p2ppb.BlobsSidecar
|
||||||
for i := 0; i < len(peers); i++ {
|
for i := 0; i < len(peers); i++ {
|
||||||
blocks, err := f.requestBlocks(ctx, req, peers[i])
|
blocks, err := f.requestBlocks(ctx, req, peers[i])
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
if sidecars, err := f.requestSidecars(ctx, sidecarReq, peers[i], blocks); err == nil {
|
||||||
|
if err = checkBlocksForAvailableSidecars(blocks, sidecars); err == nil {
|
||||||
|
f.p2p.Peers().Scorers().BlockProviderScorer().Touch(peers[i])
|
||||||
|
return blocks, sidecars, peers[i], err
|
||||||
|
}
|
||||||
|
}
|
||||||
f.p2p.Peers().Scorers().BlockProviderScorer().Touch(peers[i])
|
f.p2p.Peers().Scorers().BlockProviderScorer().Touch(peers[i])
|
||||||
return blocks, peers[i], err
|
return blocks, sidecars, peers[i], err
|
||||||
} else {
|
} else {
|
||||||
log.WithError(err).Debug("Could not request blocks by range")
|
log.WithError(err).Debug("Could not request blocks by range")
|
||||||
}
|
}
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"err": err,
|
||||||
|
"startSlot": start,
|
||||||
|
"count": count,
|
||||||
|
"peer": peers[i],
|
||||||
|
}).Trace("Error getting data from peer")
|
||||||
}
|
}
|
||||||
return nil, "", errNoPeersAvailable
|
return nil, nil, "", errNoPeersAvailable
|
||||||
}
|
}
|
||||||
|
|
||||||
// requestBlocks is a wrapper for handling BeaconBlocksByRangeRequest requests/streams.
|
// requestBlocks is a wrapper for handling BeaconBlocksByRangeRequest requests/streams.
|
||||||
@@ -359,6 +385,41 @@ func (f *blocksFetcher) requestBlocksByRoot(
|
|||||||
return prysmsync.SendBeaconBlocksByRootRequest(ctx, f.chain, f.p2p, pid, req, nil)
|
return prysmsync.SendBeaconBlocksByRootRequest(ctx, f.chain, f.p2p, pid, req, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *blocksFetcher) requestSidecars(
|
||||||
|
ctx context.Context,
|
||||||
|
req *p2ppb.BlobsSidecarsByRangeRequest,
|
||||||
|
pid peer.ID,
|
||||||
|
blkRefs []interfaces.SignedBeaconBlock,
|
||||||
|
) ([]*p2ppb.BlobsSidecar, error) {
|
||||||
|
if ctx.Err() != nil {
|
||||||
|
return nil, ctx.Err()
|
||||||
|
}
|
||||||
|
l := f.peerLock(pid)
|
||||||
|
l.Lock()
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"peer": pid,
|
||||||
|
"start": req.StartSlot,
|
||||||
|
"count": req.Count,
|
||||||
|
"capacity": f.rateLimiter.Remaining(pid.String()),
|
||||||
|
"score": f.p2p.Peers().Scorers().BlockProviderScorer().FormatScorePretty(pid),
|
||||||
|
}).Debug("Requesting sidecars")
|
||||||
|
// TODO(EIP-4844): sidecar-specific rate limiting
|
||||||
|
if f.rateLimiter.Remaining(pid.String()) < int64(req.Count) {
|
||||||
|
if err := f.waitForBandwidth(pid); err != nil {
|
||||||
|
l.Unlock()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.rateLimiter.Add(pid.String(), int64(req.Count))
|
||||||
|
l.Unlock()
|
||||||
|
|
||||||
|
var sidecarProcessor func(*p2ppb.BlobsSidecar) error
|
||||||
|
if blkRefs != nil {
|
||||||
|
sidecarProcessor = sidecarVerifier(blkRefs)
|
||||||
|
}
|
||||||
|
return prysmsync.SendBlobsSidecarsByRangeRequest(ctx, f.chain, f.p2p, pid, req, sidecarProcessor)
|
||||||
|
}
|
||||||
|
|
||||||
// waitForBandwidth blocks up until peer's bandwidth is restored.
|
// waitForBandwidth blocks up until peer's bandwidth is restored.
|
||||||
func (f *blocksFetcher) waitForBandwidth(pid peer.ID) error {
|
func (f *blocksFetcher) waitForBandwidth(pid peer.ID) error {
|
||||||
log.WithField("peer", pid).Debug("Slowing down for rate limit")
|
log.WithField("peer", pid).Debug("Slowing down for rate limit")
|
||||||
@@ -372,3 +433,66 @@ func (f *blocksFetcher) waitForBandwidth(pid peer.ID) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkBlocksForAvailableSidecars(blks []interfaces.SignedBeaconBlock, sidecars []*p2ppb.BlobsSidecar) error {
|
||||||
|
for _, b := range blks {
|
||||||
|
if blocks.IsPreEIP4844Version(b.Version()) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
blobKzgs, err := b.Block().Body().BlobKzgs()
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Could not get blob kzgs")
|
||||||
|
}
|
||||||
|
if len(blobKzgs) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
bRoot, err := b.Block().HashTreeRoot()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var foundSidecar bool
|
||||||
|
for _, s := range sidecars {
|
||||||
|
if b.Block().Slot() == s.BeaconBlockSlot && bRoot == bytesutil.ToBytes32(s.BeaconBlockRoot) {
|
||||||
|
foundSidecar = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !foundSidecar {
|
||||||
|
return fmt.Errorf("%w, slot: %d", errMissingSidecar, b.Block().Slot())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func sidecarVerifier(blks []interfaces.SignedBeaconBlock) func(*p2ppb.BlobsSidecar) error {
|
||||||
|
return func(sidecar *p2ppb.BlobsSidecar) error {
|
||||||
|
for _, b := range blks {
|
||||||
|
if blocks.IsPreEIP4844Version(b.Version()) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
blobKzgs, err := b.Block().Body().BlobKzgs()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(blobKzgs) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if b.Block().Slot() != sidecar.BeaconBlockSlot {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
bRoot, err := b.Block().HashTreeRoot()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if bRoot != bytesutil.ToBytes32(sidecar.BeaconBlockRoot) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err := blobs.VerifyBlobsSidecar(b.Block().Slot(), bRoot, bytesutil.ToBytes48Array(blobKzgs), sidecar); err != nil {
|
||||||
|
return errors.Wrap(errInvalidSidecar, err.Error())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// If here then we've received an unwanted sidecar. This is an error because it means some other valid sidecar got pushed out
|
||||||
|
return errUnexpectedSidecar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/libp2p/go-libp2p-core/peer"
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
|
p2ppb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||||
|
|
||||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/db"
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/db"
|
||||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/p2p"
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/p2p"
|
||||||
beaconsync "github.com/prysmaticlabs/prysm/v3/beacon-chain/sync"
|
beaconsync "github.com/prysmaticlabs/prysm/v3/beacon-chain/sync"
|
||||||
@@ -88,8 +90,9 @@ type blocksQueue struct {
|
|||||||
|
|
||||||
// blocksQueueFetchedData is a data container that is returned from a queue on each step.
|
// blocksQueueFetchedData is a data container that is returned from a queue on each step.
|
||||||
type blocksQueueFetchedData struct {
|
type blocksQueueFetchedData struct {
|
||||||
pid peer.ID
|
pid peer.ID
|
||||||
blocks []interfaces.SignedBeaconBlock
|
blocks []interfaces.SignedBeaconBlock
|
||||||
|
sidecars []*p2ppb.BlobsSidecar
|
||||||
}
|
}
|
||||||
|
|
||||||
// newBlocksQueue creates initialized priority queue.
|
// newBlocksQueue creates initialized priority queue.
|
||||||
@@ -333,6 +336,7 @@ func (q *blocksQueue) onDataReceivedEvent(ctx context.Context) eventHandlerFn {
|
|||||||
}
|
}
|
||||||
m.pid = response.pid
|
m.pid = response.pid
|
||||||
m.blocks = response.blocks
|
m.blocks = response.blocks
|
||||||
|
m.sidecars = response.sidecars
|
||||||
return stateDataParsed, nil
|
return stateDataParsed, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -353,8 +357,9 @@ func (q *blocksQueue) onReadyToSendEvent(ctx context.Context) eventHandlerFn {
|
|||||||
|
|
||||||
send := func() (stateID, error) {
|
send := func() (stateID, error) {
|
||||||
data := &blocksQueueFetchedData{
|
data := &blocksQueueFetchedData{
|
||||||
pid: m.pid,
|
pid: m.pid,
|
||||||
blocks: m.blocks,
|
blocks: m.blocks,
|
||||||
|
sidecars: m.sidecars,
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
|
|||||||
@@ -254,7 +254,7 @@ func TestBlocksQueue_Loop(t *testing.T) {
|
|||||||
highestExpectedSlot: tt.highestExpectedSlot,
|
highestExpectedSlot: tt.highestExpectedSlot,
|
||||||
})
|
})
|
||||||
assert.NoError(t, queue.start())
|
assert.NoError(t, queue.start())
|
||||||
processBlock := func(block interfaces.SignedBeaconBlock) error {
|
processBlock := func(block interfaces.SignedBeaconBlock, sidecar *eth.BlobsSidecar) error {
|
||||||
if !beaconDB.HasBlock(ctx, block.Block().ParentRoot()) {
|
if !beaconDB.HasBlock(ctx, block.Block().ParentRoot()) {
|
||||||
return fmt.Errorf("%w: %#x", errParentDoesNotExist, block.Block().ParentRoot())
|
return fmt.Errorf("%w: %#x", errParentDoesNotExist, block.Block().ParentRoot())
|
||||||
}
|
}
|
||||||
@@ -268,7 +268,14 @@ func TestBlocksQueue_Loop(t *testing.T) {
|
|||||||
var blocks []interfaces.SignedBeaconBlock
|
var blocks []interfaces.SignedBeaconBlock
|
||||||
for data := range queue.fetchedData {
|
for data := range queue.fetchedData {
|
||||||
for _, block := range data.blocks {
|
for _, block := range data.blocks {
|
||||||
if err := processBlock(block); err != nil {
|
var sidecar *eth.BlobsSidecar
|
||||||
|
for _, s := range data.sidecars {
|
||||||
|
if s.BeaconBlockSlot == block.Block().Slot() {
|
||||||
|
sidecar = s
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := processBlock(block, sidecar); err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
blocks = append(blocks, block)
|
blocks = append(blocks, block)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/libp2p/go-libp2p-core/peer"
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
||||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||||
|
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||||
prysmTime "github.com/prysmaticlabs/prysm/v3/time"
|
prysmTime "github.com/prysmaticlabs/prysm/v3/time"
|
||||||
"github.com/prysmaticlabs/prysm/v3/time/slots"
|
"github.com/prysmaticlabs/prysm/v3/time/slots"
|
||||||
)
|
)
|
||||||
@@ -42,12 +43,13 @@ type stateMachineManager struct {
|
|||||||
// stateMachine holds a state of a single block processing FSM.
|
// stateMachine holds a state of a single block processing FSM.
|
||||||
// Each FSM allows deterministic state transitions: State(S) x Event(E) -> Actions (A), State(S').
|
// Each FSM allows deterministic state transitions: State(S) x Event(E) -> Actions (A), State(S').
|
||||||
type stateMachine struct {
|
type stateMachine struct {
|
||||||
smm *stateMachineManager
|
smm *stateMachineManager
|
||||||
start types.Slot
|
start types.Slot
|
||||||
state stateID
|
state stateID
|
||||||
pid peer.ID
|
pid peer.ID
|
||||||
blocks []interfaces.SignedBeaconBlock
|
blocks []interfaces.SignedBeaconBlock
|
||||||
updated time.Time
|
sidecars []*ethpb.BlobsSidecar
|
||||||
|
updated time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// eventHandlerFn is an event handler function's signature.
|
// eventHandlerFn is an event handler function's signature.
|
||||||
@@ -75,11 +77,12 @@ func (smm *stateMachineManager) addEventHandler(event eventID, state stateID, fn
|
|||||||
// addStateMachine allocates memory for new FSM.
|
// addStateMachine allocates memory for new FSM.
|
||||||
func (smm *stateMachineManager) addStateMachine(startSlot types.Slot) *stateMachine {
|
func (smm *stateMachineManager) addStateMachine(startSlot types.Slot) *stateMachine {
|
||||||
smm.machines[startSlot] = &stateMachine{
|
smm.machines[startSlot] = &stateMachine{
|
||||||
smm: smm,
|
smm: smm,
|
||||||
start: startSlot,
|
start: startSlot,
|
||||||
state: stateNew,
|
state: stateNew,
|
||||||
blocks: []interfaces.SignedBeaconBlock{},
|
blocks: []interfaces.SignedBeaconBlock{},
|
||||||
updated: prysmTime.Now(),
|
sidecars: []*ethpb.BlobsSidecar{},
|
||||||
|
updated: prysmTime.Now(),
|
||||||
}
|
}
|
||||||
smm.recalculateMachineAttribs()
|
smm.recalculateMachineAttribs()
|
||||||
return smm.machines[startSlot]
|
return smm.machines[startSlot]
|
||||||
@@ -91,6 +94,7 @@ func (smm *stateMachineManager) removeStateMachine(startSlot types.Slot) error {
|
|||||||
return fmt.Errorf("state for machine %v is not found", startSlot)
|
return fmt.Errorf("state for machine %v is not found", startSlot)
|
||||||
}
|
}
|
||||||
smm.machines[startSlot].blocks = nil
|
smm.machines[startSlot].blocks = nil
|
||||||
|
smm.machines[startSlot].sidecars = nil
|
||||||
delete(smm.machines, startSlot)
|
delete(smm.machines, startSlot)
|
||||||
smm.recalculateMachineAttribs()
|
smm.recalculateMachineAttribs()
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -223,6 +223,13 @@ func connectPeer(t *testing.T, host *p2pt.TestP2P, datum *peerData, peerStatus *
|
|||||||
assert.NoError(t, beaconsync.WriteBlockChunk(stream, mChain, p.Encoding(), wsb))
|
assert.NoError(t, beaconsync.WriteBlockChunk(stream, mChain, p.Encoding(), wsb))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
p.SetStreamHandler("/eth2/beacon_chain/req/blobs_sidecars_by_range/1/ssz_snappy", func(stream network.Stream) {
|
||||||
|
defer func() {
|
||||||
|
assert.NoError(t, stream.Close())
|
||||||
|
}()
|
||||||
|
req := ðpb.BlobsSidecarsByRangeRequest{}
|
||||||
|
assert.NoError(t, p.Encoding().DecodeWithMaxLength(stream, req))
|
||||||
|
})
|
||||||
|
|
||||||
p.Connect(host)
|
p.Connect(host)
|
||||||
|
|
||||||
@@ -320,6 +327,15 @@ func connectPeerHavingBlocks(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
p.SetStreamHandler("/eth2/beacon_chain/req/blobs_sidecars_by_range/1/ssz_snappy", func(stream network.Stream) {
|
||||||
|
defer func() {
|
||||||
|
_err := stream.Close()
|
||||||
|
_ = _err
|
||||||
|
}()
|
||||||
|
req := new(ethpb.BlobsSidecarsByRangeRequest)
|
||||||
|
assert.NoError(t, p.Encoding().DecodeWithMaxLength(stream, req))
|
||||||
|
})
|
||||||
|
|
||||||
p.Connect(host)
|
p.Connect(host)
|
||||||
|
|
||||||
finalizedEpoch := slots.ToEpoch(finalizedSlot)
|
finalizedEpoch := slots.ToEpoch(finalizedSlot)
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import (
|
|||||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/transition"
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/transition"
|
||||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
||||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||||
|
eth "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/runtime/version"
|
||||||
"github.com/prysmaticlabs/prysm/v3/time/slots"
|
"github.com/prysmaticlabs/prysm/v3/time/slots"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
@@ -128,7 +130,7 @@ func (s *Service) processFetchedData(
|
|||||||
defer s.updatePeerScorerStats(data.pid, startSlot)
|
defer s.updatePeerScorerStats(data.pid, startSlot)
|
||||||
|
|
||||||
// Use Batch Block Verify to process and verify batches directly.
|
// Use Batch Block Verify to process and verify batches directly.
|
||||||
if err := s.processBatchedBlocks(ctx, genesis, data.blocks, s.cfg.Chain.ReceiveBlockBatch); err != nil {
|
if err := s.processBatchedBlocks(ctx, genesis, data.blocks, data.sidecars, s.cfg.Chain.ReceiveBlockBatch); err != nil {
|
||||||
log.WithError(err).Warn("Skip processing batched blocks")
|
log.WithError(err).Warn("Skip processing batched blocks")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -142,6 +144,20 @@ func (s *Service) processFetchedDataRegSync(
|
|||||||
invalidBlocks := 0
|
invalidBlocks := 0
|
||||||
blksWithoutParentCount := 0
|
blksWithoutParentCount := 0
|
||||||
for _, blk := range data.blocks {
|
for _, blk := range data.blocks {
|
||||||
|
var sidecar *eth.BlobsSidecar
|
||||||
|
for _, s := range data.sidecars {
|
||||||
|
if s.BeaconBlockSlot == blk.Block().Slot() {
|
||||||
|
sidecar = s
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if sidecar != nil && blk.Version() == version.EIP4844 {
|
||||||
|
if err := blk.SetSideCar(ð.SignedBlobsSidecar{Message: sidecar}); err != nil {
|
||||||
|
log.WithError(err).Error("Could not set sidecar")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := s.processBlock(ctx, genesis, blk, blockReceiver); err != nil {
|
if err := s.processBlock(ctx, genesis, blk, blockReceiver); err != nil {
|
||||||
switch {
|
switch {
|
||||||
case errors.Is(err, errBlockAlreadyProcessed):
|
case errors.Is(err, errBlockAlreadyProcessed):
|
||||||
@@ -241,11 +257,12 @@ func (s *Service) processBlock(
|
|||||||
if !s.cfg.Chain.HasBlock(ctx, blk.Block().ParentRoot()) {
|
if !s.cfg.Chain.HasBlock(ctx, blk.Block().ParentRoot()) {
|
||||||
return fmt.Errorf("%w: (in processBlock, slot=%d) %#x", errParentDoesNotExist, blk.Block().Slot(), blk.Block().ParentRoot())
|
return fmt.Errorf("%w: (in processBlock, slot=%d) %#x", errParentDoesNotExist, blk.Block().Slot(), blk.Block().ParentRoot())
|
||||||
}
|
}
|
||||||
|
|
||||||
return blockReceiver(ctx, blk, blkRoot)
|
return blockReceiver(ctx, blk, blkRoot)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) processBatchedBlocks(ctx context.Context, genesis time.Time,
|
func (s *Service) processBatchedBlocks(ctx context.Context, genesis time.Time,
|
||||||
blks []interfaces.SignedBeaconBlock, bFunc batchBlockReceiverFn) error {
|
blks []interfaces.SignedBeaconBlock, sidecars []*eth.BlobsSidecar, bFunc batchBlockReceiverFn) error {
|
||||||
if len(blks) == 0 {
|
if len(blks) == 0 {
|
||||||
return errors.New("0 blocks provided into method")
|
return errors.New("0 blocks provided into method")
|
||||||
}
|
}
|
||||||
@@ -284,7 +301,17 @@ func (s *Service) processBatchedBlocks(ctx context.Context, genesis time.Time,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
blockRoots[i] = blkRoot
|
blockRoots[i] = blkRoot
|
||||||
|
|
||||||
|
for _, sc := range sidecars {
|
||||||
|
if sc.BeaconBlockSlot == b.Block().Slot() {
|
||||||
|
if err := b.SetSideCar(ð.SignedBlobsSidecar{Message: sc}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
blks[i] = b
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return bFunc(ctx, blks, blockRoots)
|
return bFunc(ctx, blks, blockRoots)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -445,7 +445,7 @@ func TestService_processBlockBatch(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Process block normally.
|
// Process block normally.
|
||||||
err = s.processBatchedBlocks(ctx, genesis, batch, func(
|
err = s.processBatchedBlocks(ctx, genesis, batch, nil, func(
|
||||||
ctx context.Context, blks []interfaces.SignedBeaconBlock, blockRoots [][32]byte) error {
|
ctx context.Context, blks []interfaces.SignedBeaconBlock, blockRoots [][32]byte) error {
|
||||||
assert.NoError(t, s.cfg.Chain.ReceiveBlockBatch(ctx, blks, blockRoots))
|
assert.NoError(t, s.cfg.Chain.ReceiveBlockBatch(ctx, blks, blockRoots))
|
||||||
return nil
|
return nil
|
||||||
@@ -453,7 +453,7 @@ func TestService_processBlockBatch(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Duplicate processing should trigger error.
|
// Duplicate processing should trigger error.
|
||||||
err = s.processBatchedBlocks(ctx, genesis, batch, func(
|
err = s.processBatchedBlocks(ctx, genesis, batch, nil, func(
|
||||||
ctx context.Context, blocks []interfaces.SignedBeaconBlock, blockRoots [][32]byte) error {
|
ctx context.Context, blocks []interfaces.SignedBeaconBlock, blockRoots [][32]byte) error {
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
@@ -469,15 +469,15 @@ func TestService_processBlockBatch(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Bad batch should fail because it is non linear
|
// Bad batch should fail because it is non linear
|
||||||
err = s.processBatchedBlocks(ctx, genesis, badBatch2, func(
|
err = s.processBatchedBlocks(ctx, genesis, badBatch2, nil, func(
|
||||||
ctx context.Context, blks []interfaces.SignedBeaconBlock, blockRoots [][32]byte) error {
|
ctx context.Context, blks []interfaces.SignedBeaconBlock, blockRoots [][32]byte) error {
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
expectedSubErr := "expected linear block list"
|
expectedSubErr := "expected linear block list"
|
||||||
assert.ErrorContains(t, expectedSubErr, err)
|
assert.ErrorContains(t, expectedSubErr, err)
|
||||||
|
|
||||||
// Continue normal processing, should proceed w/o errors.
|
// continue normal processing, should proceed w/o errors.
|
||||||
err = s.processBatchedBlocks(ctx, genesis, batch2, func(
|
err = s.processBatchedBlocks(ctx, genesis, batch2, nil, func(
|
||||||
ctx context.Context, blks []interfaces.SignedBeaconBlock, blockRoots [][32]byte) error {
|
ctx context.Context, blks []interfaces.SignedBeaconBlock, blockRoots [][32]byte) error {
|
||||||
assert.NoError(t, s.cfg.Chain.ReceiveBlockBatch(ctx, blks, blockRoots))
|
assert.NoError(t, s.cfg.Chain.ReceiveBlockBatch(ctx, blks, blockRoots))
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -3,15 +3,18 @@ package sync
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"math"
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/prysmaticlabs/prysm/v3/async"
|
"github.com/prysmaticlabs/prysm/v3/async"
|
||||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/blockchain"
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/blockchain"
|
||||||
p2ptypes "github.com/prysmaticlabs/prysm/v3/beacon-chain/p2p/types"
|
p2ptypes "github.com/prysmaticlabs/prysm/v3/beacon-chain/p2p/types"
|
||||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/consensus-types/blobs"
|
||||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
||||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
||||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||||
@@ -19,6 +22,7 @@ import (
|
|||||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||||
"github.com/prysmaticlabs/prysm/v3/encoding/ssz/equality"
|
"github.com/prysmaticlabs/prysm/v3/encoding/ssz/equality"
|
||||||
"github.com/prysmaticlabs/prysm/v3/monitoring/tracing"
|
"github.com/prysmaticlabs/prysm/v3/monitoring/tracing"
|
||||||
|
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||||
"github.com/prysmaticlabs/prysm/v3/time/slots"
|
"github.com/prysmaticlabs/prysm/v3/time/slots"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/trailofbits/go-mutexasserts"
|
"github.com/trailofbits/go-mutexasserts"
|
||||||
@@ -59,6 +63,7 @@ func (s *Service) processPendingBlocks(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
ss := s.sortedPendingSlots()
|
ss := s.sortedPendingSlots()
|
||||||
var parentRoots [][32]byte
|
var parentRoots [][32]byte
|
||||||
|
missingSidecarRefs := make(map[types.Slot][][32]byte)
|
||||||
|
|
||||||
span.AddAttributes(
|
span.AddAttributes(
|
||||||
trace.Int64Attribute("numSlots", int64(len(ss))),
|
trace.Int64Attribute("numSlots", int64(len(ss))),
|
||||||
@@ -78,6 +83,7 @@ func (s *Service) processPendingBlocks(ctx context.Context) error {
|
|||||||
|
|
||||||
s.pendingQueueLock.RLock()
|
s.pendingQueueLock.RLock()
|
||||||
bs := s.pendingBlocksInCache(slot)
|
bs := s.pendingBlocksInCache(slot)
|
||||||
|
sidecars := s.pendingSidecarsInCache(slot)
|
||||||
// Skip if there's no block in the queue.
|
// Skip if there's no block in the queue.
|
||||||
if len(bs) == 0 {
|
if len(bs) == 0 {
|
||||||
s.pendingQueueLock.RUnlock()
|
s.pendingQueueLock.RUnlock()
|
||||||
@@ -100,6 +106,29 @@ func (s *Service) processPendingBlocks(ctx context.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasPeer := len(pids) != 0
|
||||||
|
|
||||||
|
var queuedSidecar *queuedBlobsSidecar
|
||||||
|
contains, err := blobs.BlockContainsKZGs(b.Block())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if contains {
|
||||||
|
queuedSidecar = findSidecarForBlock(b.Block(), blkRoot, sidecars)
|
||||||
|
if queuedSidecar == nil {
|
||||||
|
if hasPeer {
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"currentSlot": b.Block().Slot(),
|
||||||
|
"blkRoot": hex.EncodeToString(blkRoot[:]),
|
||||||
|
}).Debug("Requesting missing sidecar")
|
||||||
|
missingSidecarRefs[b.Block().Slot()] = append(missingSidecarRefs[slot], blkRoot)
|
||||||
|
}
|
||||||
|
|
||||||
|
span.End()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inDB := s.cfg.beaconDB.HasBlock(ctx, blkRoot)
|
inDB := s.cfg.beaconDB.HasBlock(ctx, blkRoot)
|
||||||
// No need to process the same block twice.
|
// No need to process the same block twice.
|
||||||
if inDB {
|
if inDB {
|
||||||
@@ -108,6 +137,12 @@ func (s *Service) processPendingBlocks(ctx context.Context) error {
|
|||||||
s.pendingQueueLock.Unlock()
|
s.pendingQueueLock.Unlock()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if queuedSidecar != nil {
|
||||||
|
if err := s.deleteSidecarFromPendingQueue(slot, queuedSidecar); err != nil {
|
||||||
|
s.pendingQueueLock.Unlock()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
s.pendingQueueLock.Unlock()
|
s.pendingQueueLock.Unlock()
|
||||||
span.End()
|
span.End()
|
||||||
continue
|
continue
|
||||||
@@ -126,7 +161,7 @@ func (s *Service) processPendingBlocks(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
parentInDb := s.cfg.beaconDB.HasBlock(ctx, b.Block().ParentRoot())
|
parentInDb := s.cfg.beaconDB.HasBlock(ctx, b.Block().ParentRoot())
|
||||||
hasPeer := len(pids) != 0
|
hasPeer = len(pids) != 0
|
||||||
|
|
||||||
// Only request for missing parent block if it's not in beaconDB, not in pending cache
|
// Only request for missing parent block if it's not in beaconDB, not in pending cache
|
||||||
// and has peer in the peer list.
|
// and has peer in the peer list.
|
||||||
@@ -159,6 +194,40 @@ func (s *Service) processPendingBlocks(ctx context.Context) error {
|
|||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var sidecar *ethpb.BlobsSidecar
|
||||||
|
if queuedSidecar != nil {
|
||||||
|
// Only for gossiped sidecars that skipped validation
|
||||||
|
if queuedSidecar.sig != nil && !queuedSidecar.validated {
|
||||||
|
res, err := s.validateBlobsSidecarSignature(ctx, b, queuedSidecar.AsSignedBlobsSidecar())
|
||||||
|
if err != nil || res != pubsub.ValidationAccept {
|
||||||
|
tracing.AnnotateError(span, err)
|
||||||
|
span.End()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sidecar = queuedSidecar.s
|
||||||
|
kzgs, err := b.Block().Body().BlobKzgs()
|
||||||
|
// an error shouldn't happen! A non-nil sidecar means we're dealing with a EIP-4844 block
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).WithField("slot", b.Block().Slot()).Debug("Could not get KZGs from block")
|
||||||
|
tracing.AnnotateError(span, err)
|
||||||
|
span.End()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err := blobs.VerifyBlobsSidecar(b.Block().Slot(), blkRoot, bytesutil.ToBytes48Array(kzgs), queuedSidecar.s); err != nil {
|
||||||
|
log.WithError(err).WithField("slot", b.Block().Slot()).Debug("Could not verify blobs sidecar")
|
||||||
|
}
|
||||||
|
if sidecar != nil {
|
||||||
|
if err := b.SetSideCar(ðpb.SignedBlobsSidecar{
|
||||||
|
Message: sidecar,
|
||||||
|
}); err != nil {
|
||||||
|
log.Error("Could not set sidecar on block", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := s.cfg.chain.ReceiveBlock(ctx, b, blkRoot); err != nil {
|
if err := s.cfg.chain.ReceiveBlock(ctx, b, blkRoot); err != nil {
|
||||||
if blockchain.IsInvalidBlock(err) {
|
if blockchain.IsInvalidBlock(err) {
|
||||||
r := blockchain.InvalidBlockRoot(err)
|
r := blockchain.InvalidBlockRoot(err)
|
||||||
@@ -187,12 +256,25 @@ func (s *Service) processPendingBlocks(ctx context.Context) error {
|
|||||||
log.WithError(err).Debug("Could not broadcast block")
|
log.WithError(err).Debug("Could not broadcast block")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if queuedSidecar != nil {
|
||||||
|
if queuedSidecar.IsSigned() {
|
||||||
|
if err := s.cfg.p2p.Broadcast(ctx, queuedSidecar.AsSignedBlobsSidecar()); err != nil {
|
||||||
|
log.WithError(err).Debug("Could not broadcast sidecar")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
s.pendingQueueLock.Lock()
|
s.pendingQueueLock.Lock()
|
||||||
if err := s.deleteBlockFromPendingQueue(slot, b, blkRoot); err != nil {
|
if err := s.deleteBlockFromPendingQueue(slot, b, blkRoot); err != nil {
|
||||||
s.pendingQueueLock.Unlock()
|
s.pendingQueueLock.Unlock()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if queuedSidecar != nil {
|
||||||
|
if err := s.deleteSidecarFromPendingQueue(slot, queuedSidecar); err != nil {
|
||||||
|
s.pendingQueueLock.Unlock()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
s.pendingQueueLock.Unlock()
|
s.pendingQueueLock.Unlock()
|
||||||
|
|
||||||
log.WithFields(logrus.Fields{
|
log.WithFields(logrus.Fields{
|
||||||
@@ -204,7 +286,12 @@ func (s *Service) processPendingBlocks(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.sendBatchRootRequest(ctx, parentRoots, randGen)
|
// TODO(EIP-4844): Rework this to send blocks and sidecar requests in lock-step. It's a more robust way of handling partial failures
|
||||||
|
var err error
|
||||||
|
if err = s.sendBatchRootRequest(ctx, parentRoots, randGen); err == nil {
|
||||||
|
err = s.sendBatchSidecarRequest(ctx, missingSidecarRefs, randGen)
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) checkIfBlockIsBad(
|
func (s *Service) checkIfBlockIsBad(
|
||||||
@@ -280,6 +367,71 @@ func (s *Service) sendBatchRootRequest(ctx context.Context, roots [][32]byte, ra
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) sendBatchSidecarRequest(ctx context.Context, reqs map[types.Slot][][32]byte, randGen *rand.Rand) error {
|
||||||
|
ctx, span := trace.StartSpan(ctx, "sendBatchSidecarRequests")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
|
if len(reqs) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
cp := s.cfg.chain.FinalizedCheckpt()
|
||||||
|
_, bestPeers := s.cfg.p2p.Peers().BestFinalized(maxPeerRequest, cp.Epoch)
|
||||||
|
if len(bestPeers) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
makeSidecarRangeRequest := func(reqs map[types.Slot][][32]byte) *ethpb.BlobsSidecarsByRangeRequest {
|
||||||
|
start := types.Slot(math.MaxUint64)
|
||||||
|
end := types.Slot(0)
|
||||||
|
for slot := range reqs {
|
||||||
|
if slot < start {
|
||||||
|
start = slot
|
||||||
|
}
|
||||||
|
if slot > end {
|
||||||
|
end = slot
|
||||||
|
}
|
||||||
|
}
|
||||||
|
count := uint64(end.SubSlot(start).Add(1))
|
||||||
|
if count > params.BeaconNetworkConfig().MaxRequestBlobsSidecars {
|
||||||
|
count = params.BeaconNetworkConfig().MaxRequestBlobsSidecars
|
||||||
|
}
|
||||||
|
return ðpb.BlobsSidecarsByRangeRequest{
|
||||||
|
StartSlot: start,
|
||||||
|
Count: count,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Randomly choose a peer to query from our best peers. If that peer cannot return
|
||||||
|
// all the requested blocks, we randomly select another peer.
|
||||||
|
pid := bestPeers[randGen.Int()%len(bestPeers)]
|
||||||
|
for i := 0; i < numOfTries; i++ {
|
||||||
|
sidecarReq := makeSidecarRangeRequest(reqs)
|
||||||
|
if err := s.sendRecentBlobSidecarsRequest(ctx, sidecarReq, pid); err != nil {
|
||||||
|
tracing.AnnotateError(span, err)
|
||||||
|
log.WithError(err).Debug("Could not send recent blob sidecar request")
|
||||||
|
}
|
||||||
|
|
||||||
|
newReqs := make(map[types.Slot][][32]byte)
|
||||||
|
s.pendingQueueLock.RLock()
|
||||||
|
for slot, roots := range reqs {
|
||||||
|
for _, rt := range roots {
|
||||||
|
if !s.seenPendingSidecars[rt] {
|
||||||
|
newReqs[slot] = append(newReqs[slot], rt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.pendingQueueLock.RUnlock()
|
||||||
|
if len(newReqs) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// Choosing a new peer with the leftover set of
|
||||||
|
// roots to request.
|
||||||
|
reqs = newReqs
|
||||||
|
pid = bestPeers[randGen.Int()%len(bestPeers)]
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) sortedPendingSlots() []types.Slot {
|
func (s *Service) sortedPendingSlots() []types.Slot {
|
||||||
s.pendingQueueLock.RLock()
|
s.pendingQueueLock.RLock()
|
||||||
defer s.pendingQueueLock.RUnlock()
|
defer s.pendingQueueLock.RUnlock()
|
||||||
@@ -299,7 +451,7 @@ func (s *Service) sortedPendingSlots() []types.Slot {
|
|||||||
|
|
||||||
// validatePendingSlots validates the pending blocks
|
// validatePendingSlots validates the pending blocks
|
||||||
// by their slot. If they are before the current finalized
|
// by their slot. If they are before the current finalized
|
||||||
// checkpoint, these blocks are removed from the queue.
|
// checkpoint, these blocks and their sidecars are removed from the queue.
|
||||||
func (s *Service) validatePendingSlots() error {
|
func (s *Service) validatePendingSlots() error {
|
||||||
s.pendingQueueLock.Lock()
|
s.pendingQueueLock.Lock()
|
||||||
defer s.pendingQueueLock.Unlock()
|
defer s.pendingQueueLock.Unlock()
|
||||||
@@ -341,6 +493,21 @@ func (s *Service) validatePendingSlots() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
items = s.slotToPendingSidecars.Items()
|
||||||
|
for k := range items {
|
||||||
|
slot := cacheKeyToSlot(k)
|
||||||
|
sidecars := s.pendingSidecarsInCache(slot)
|
||||||
|
for _, sc := range sidecars {
|
||||||
|
epoch := slots.ToEpoch(slot)
|
||||||
|
if finalizedEpoch > 0 && epoch <= finalizedEpoch {
|
||||||
|
if err := s.deleteSidecarFromPendingQueue(slot, sc); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,6 +516,8 @@ func (s *Service) clearPendingSlots() {
|
|||||||
defer s.pendingQueueLock.Unlock()
|
defer s.pendingQueueLock.Unlock()
|
||||||
s.slotToPendingBlocks.Flush()
|
s.slotToPendingBlocks.Flush()
|
||||||
s.seenPendingBlocks = make(map[[32]byte]bool)
|
s.seenPendingBlocks = make(map[[32]byte]bool)
|
||||||
|
s.slotToPendingSidecars.Flush()
|
||||||
|
s.seenPendingSidecars = make(map[[32]byte]bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete block from the list from the pending queue using the slot as key.
|
// Delete block from the list from the pending queue using the slot as key.
|
||||||
@@ -462,3 +631,16 @@ func slotToCacheKey(s types.Slot) string {
|
|||||||
b := bytesutil.SlotToBytesBigEndian(s)
|
b := bytesutil.SlotToBytesBigEndian(s)
|
||||||
return string(b)
|
return string(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func findSidecarForBlock(b interfaces.BeaconBlock, blkRoot [32]byte, sidecars []*queuedBlobsSidecar) *queuedBlobsSidecar {
|
||||||
|
for _, s := range sidecars {
|
||||||
|
if b.Slot() != s.s.BeaconBlockSlot {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if blkRoot != bytesutil.ToBytes32(s.s.BeaconBlockRoot) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -49,8 +49,10 @@ func TestRegularSyncBeaconBlockSubscriber_ProcessPendingBlocks1(t *testing.T) {
|
|||||||
},
|
},
|
||||||
stateGen: stategen.New(db),
|
stateGen: stategen.New(db),
|
||||||
},
|
},
|
||||||
slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
|
slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
|
||||||
seenPendingBlocks: make(map[[32]byte]bool),
|
slotToPendingSidecars: gcache.New(time.Second, 2*time.Second),
|
||||||
|
seenPendingBlocks: make(map[[32]byte]bool),
|
||||||
|
seenPendingSidecars: make(map[[32]byte]bool),
|
||||||
}
|
}
|
||||||
r.initCaches()
|
r.initCaches()
|
||||||
|
|
||||||
@@ -121,8 +123,10 @@ func TestRegularSyncBeaconBlockSubscriber_OptimisticStatus(t *testing.T) {
|
|||||||
},
|
},
|
||||||
stateGen: stategen.New(db),
|
stateGen: stategen.New(db),
|
||||||
},
|
},
|
||||||
slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
|
slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
|
||||||
seenPendingBlocks: make(map[[32]byte]bool),
|
slotToPendingSidecars: gcache.New(time.Second, 2*time.Second),
|
||||||
|
seenPendingBlocks: make(map[[32]byte]bool),
|
||||||
|
seenPendingSidecars: make(map[[32]byte]bool),
|
||||||
}
|
}
|
||||||
r.initCaches()
|
r.initCaches()
|
||||||
|
|
||||||
@@ -193,8 +197,10 @@ func TestRegularSyncBeaconBlockSubscriber_ExecutionEngineTimesOut(t *testing.T)
|
|||||||
},
|
},
|
||||||
stateGen: stategen.New(db),
|
stateGen: stategen.New(db),
|
||||||
},
|
},
|
||||||
slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
|
slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
|
||||||
seenPendingBlocks: make(map[[32]byte]bool),
|
slotToPendingSidecars: gcache.New(time.Second, 2*time.Second),
|
||||||
|
seenPendingBlocks: make(map[[32]byte]bool),
|
||||||
|
seenPendingSidecars: make(map[[32]byte]bool),
|
||||||
}
|
}
|
||||||
r.initCaches()
|
r.initCaches()
|
||||||
|
|
||||||
@@ -266,8 +272,10 @@ func TestRegularSync_InsertDuplicateBlocks(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
|
slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
|
||||||
seenPendingBlocks: make(map[[32]byte]bool),
|
slotToPendingSidecars: gcache.New(time.Second, 2*time.Second),
|
||||||
|
seenPendingBlocks: make(map[[32]byte]bool),
|
||||||
|
seenPendingSidecars: make(map[[32]byte]bool),
|
||||||
}
|
}
|
||||||
r.initCaches()
|
r.initCaches()
|
||||||
|
|
||||||
@@ -320,8 +328,10 @@ func TestRegularSyncBeaconBlockSubscriber_DoNotReprocessBlock(t *testing.T) {
|
|||||||
},
|
},
|
||||||
stateGen: stategen.New(db),
|
stateGen: stategen.New(db),
|
||||||
},
|
},
|
||||||
slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
|
slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
|
||||||
seenPendingBlocks: make(map[[32]byte]bool),
|
slotToPendingSidecars: gcache.New(time.Second, 2*time.Second),
|
||||||
|
seenPendingBlocks: make(map[[32]byte]bool),
|
||||||
|
seenPendingSidecars: make(map[[32]byte]bool),
|
||||||
}
|
}
|
||||||
r.initCaches()
|
r.initCaches()
|
||||||
|
|
||||||
@@ -385,8 +395,10 @@ func TestRegularSyncBeaconBlockSubscriber_ProcessPendingBlocks_2Chains(t *testin
|
|||||||
},
|
},
|
||||||
stateGen: stategen.New(db),
|
stateGen: stategen.New(db),
|
||||||
},
|
},
|
||||||
slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
|
slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
|
||||||
seenPendingBlocks: make(map[[32]byte]bool),
|
slotToPendingSidecars: gcache.New(time.Second, 2*time.Second),
|
||||||
|
seenPendingBlocks: make(map[[32]byte]bool),
|
||||||
|
seenPendingSidecars: make(map[[32]byte]bool),
|
||||||
}
|
}
|
||||||
r.initCaches()
|
r.initCaches()
|
||||||
|
|
||||||
@@ -484,8 +496,10 @@ func TestRegularSyncBeaconBlockSubscriber_PruneOldPendingBlocks(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
|
slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
|
||||||
seenPendingBlocks: make(map[[32]byte]bool),
|
slotToPendingSidecars: gcache.New(time.Second, 2*time.Second),
|
||||||
|
seenPendingBlocks: make(map[[32]byte]bool),
|
||||||
|
seenPendingSidecars: make(map[[32]byte]bool),
|
||||||
}
|
}
|
||||||
r.initCaches()
|
r.initCaches()
|
||||||
|
|
||||||
@@ -588,8 +602,10 @@ func TestService_BatchRootRequest(t *testing.T) {
|
|||||||
Genesis: time.Now(),
|
Genesis: time.Now(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
|
slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
|
||||||
seenPendingBlocks: make(map[[32]byte]bool),
|
slotToPendingSidecars: gcache.New(time.Second, 2*time.Second),
|
||||||
|
seenPendingBlocks: make(map[[32]byte]bool),
|
||||||
|
seenPendingSidecars: make(map[[32]byte]bool),
|
||||||
}
|
}
|
||||||
r.initCaches()
|
r.initCaches()
|
||||||
|
|
||||||
@@ -705,8 +721,10 @@ func TestService_ProcessPendingBlockOnCorrectSlot(t *testing.T) {
|
|||||||
chain: &mockChain,
|
chain: &mockChain,
|
||||||
stateGen: stategen.New(db),
|
stateGen: stategen.New(db),
|
||||||
},
|
},
|
||||||
slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
|
slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
|
||||||
seenPendingBlocks: make(map[[32]byte]bool),
|
slotToPendingSidecars: gcache.New(time.Second, 2*time.Second),
|
||||||
|
seenPendingBlocks: make(map[[32]byte]bool),
|
||||||
|
seenPendingSidecars: make(map[[32]byte]bool),
|
||||||
}
|
}
|
||||||
r.initCaches()
|
r.initCaches()
|
||||||
|
|
||||||
@@ -783,8 +801,10 @@ func TestService_ProcessBadPendingBlocks(t *testing.T) {
|
|||||||
chain: &mockChain,
|
chain: &mockChain,
|
||||||
stateGen: stategen.New(db),
|
stateGen: stategen.New(db),
|
||||||
},
|
},
|
||||||
slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
|
slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
|
||||||
seenPendingBlocks: make(map[[32]byte]bool),
|
slotToPendingSidecars: gcache.New(time.Second, 2*time.Second),
|
||||||
|
seenPendingBlocks: make(map[[32]byte]bool),
|
||||||
|
seenPendingSidecars: make(map[[32]byte]bool),
|
||||||
}
|
}
|
||||||
r.initCaches()
|
r.initCaches()
|
||||||
|
|
||||||
|
|||||||
100
beacon-chain/sync/pending_sidecars_queue.go
Normal file
100
beacon-chain/sync/pending_sidecars_queue.go
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
package sync
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/encoding/ssz/equality"
|
||||||
|
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||||
|
"github.com/trailofbits/go-mutexasserts"
|
||||||
|
)
|
||||||
|
|
||||||
|
const maxSidecarsPerSlot = maxBlocksPerSlot
|
||||||
|
|
||||||
|
// represents a possibly signed BlobsSidecar
|
||||||
|
type queuedBlobsSidecar struct {
|
||||||
|
s *ethpb.BlobsSidecar
|
||||||
|
sig []byte
|
||||||
|
validated bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *queuedBlobsSidecar) IsSigned() bool {
|
||||||
|
return s.sig != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *queuedBlobsSidecar) AsSignedBlobsSidecar() *ethpb.SignedBlobsSidecar {
|
||||||
|
return ðpb.SignedBlobsSidecar{Message: s.s, Signature: s.sig}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete sidecar from the list from the pending queue using the slot as key.
|
||||||
|
// Note: this helper is not thread safe.
|
||||||
|
func (s *Service) deleteSidecarFromPendingQueue(slot types.Slot, sc *queuedBlobsSidecar) error {
|
||||||
|
mutexasserts.AssertRWMutexLocked(&s.pendingQueueLock)
|
||||||
|
|
||||||
|
sidecars := s.pendingSidecarsInCache(slot)
|
||||||
|
if len(sidecars) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
newSidecars := make([]*queuedBlobsSidecar, 0, len(sidecars))
|
||||||
|
for _, sidecar := range sidecars {
|
||||||
|
if equality.DeepEqual(sidecar, sc) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
newSidecars = append(newSidecars, sidecar)
|
||||||
|
}
|
||||||
|
if len(newSidecars) == 0 {
|
||||||
|
s.slotToPendingSidecars.Delete(slotToCacheKey(slot))
|
||||||
|
delete(s.seenPendingSidecars, bytesutil.ToBytes32(sc.s.BeaconBlockRoot))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrease exp time in proportion to how many sidecars are still in the cache for slot key.
|
||||||
|
d := pendingSidecarExpTime / time.Duration(len(newSidecars))
|
||||||
|
if err := s.slotToPendingSidecars.Replace(slotToCacheKey(slot), newSidecars, d); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
delete(s.seenPendingSidecars, bytesutil.ToBytes32(sc.s.BeaconBlockRoot))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert sidecar to the list in the pending queue using its slot as key.
|
||||||
|
// Note: this helper is not thread safe.
|
||||||
|
func (s *Service) insertSidecarToPendingQueue(sidecar *queuedBlobsSidecar) {
|
||||||
|
mutexasserts.AssertRWMutexLocked(&s.pendingQueueLock)
|
||||||
|
|
||||||
|
root := bytesutil.ToBytes32(sidecar.s.BeaconBlockRoot)
|
||||||
|
if s.seenPendingSidecars[root] {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.addPendingSidecarToCache(sidecar)
|
||||||
|
s.seenPendingSidecars[root] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// This returns signed sidecars given input key from slotToPendingSidecars.
|
||||||
|
func (s *Service) pendingSidecarsInCache(slot types.Slot) []*queuedBlobsSidecar {
|
||||||
|
k := slotToCacheKey(slot)
|
||||||
|
value, ok := s.slotToPendingSidecars.Get(k)
|
||||||
|
if !ok {
|
||||||
|
return []*queuedBlobsSidecar{}
|
||||||
|
}
|
||||||
|
scs, ok := value.([]*queuedBlobsSidecar)
|
||||||
|
if !ok {
|
||||||
|
return []*queuedBlobsSidecar{}
|
||||||
|
}
|
||||||
|
return scs
|
||||||
|
}
|
||||||
|
|
||||||
|
// This adds input sidecar to slotToPendingSidecars cache.
|
||||||
|
func (s *Service) addPendingSidecarToCache(sc *queuedBlobsSidecar) {
|
||||||
|
sidecars := s.pendingSidecarsInCache(sc.s.BeaconBlockSlot)
|
||||||
|
if len(sidecars) >= maxSidecarsPerSlot {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sidecars = append(sidecars, sc)
|
||||||
|
k := slotToCacheKey(sc.s.BeaconBlockSlot)
|
||||||
|
s.slotToPendingSidecars.Set(k, sidecars, pendingSidecarExpTime)
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -36,6 +36,10 @@ func newRateLimiter(p2pProvider p2p.P2P) *limiter {
|
|||||||
allowedBlocksPerSecond := float64(flags.Get().BlockBatchLimit)
|
allowedBlocksPerSecond := float64(flags.Get().BlockBatchLimit)
|
||||||
allowedBlocksBurst := int64(flags.Get().BlockBatchLimitBurstFactor * flags.Get().BlockBatchLimit)
|
allowedBlocksBurst := int64(flags.Get().BlockBatchLimitBurstFactor * flags.Get().BlockBatchLimit)
|
||||||
|
|
||||||
|
// Initialize blobs sidecar transfer limits.
|
||||||
|
blobsTransferRate := float64(flags.Get().BlobsTransferRate)
|
||||||
|
blobsTransferRateThresh := int64(flags.Get().BlobsTransferRateThresh)
|
||||||
|
|
||||||
// Set topic map for all rpc topics.
|
// Set topic map for all rpc topics.
|
||||||
topicMap := make(map[string]*leakybucket.Collector, len(p2p.RPCTopicMappings))
|
topicMap := make(map[string]*leakybucket.Collector, len(p2p.RPCTopicMappings))
|
||||||
// Goodbye Message
|
// Goodbye Message
|
||||||
@@ -61,6 +65,9 @@ func newRateLimiter(p2pProvider p2p.P2P) *limiter {
|
|||||||
topicMap[addEncoding(p2p.RPCBlocksByRangeTopicV1)] = blockCollector
|
topicMap[addEncoding(p2p.RPCBlocksByRangeTopicV1)] = blockCollector
|
||||||
topicMap[addEncoding(p2p.RPCBlocksByRangeTopicV2)] = blockCollectorV2
|
topicMap[addEncoding(p2p.RPCBlocksByRangeTopicV2)] = blockCollectorV2
|
||||||
|
|
||||||
|
// BlobsSidecarsByRange requests
|
||||||
|
topicMap[addEncoding(p2p.RPCBlobsSidecarsByRangeTopicV1)] = leakybucket.NewCollector(blobsTransferRate, blobsTransferRateThresh, false /* deleteEmptyBucket */)
|
||||||
|
|
||||||
// General topic for all rpc requests.
|
// General topic for all rpc requests.
|
||||||
topicMap[rpcLimiterTopic] = leakybucket.NewCollector(5, defaultBurstLimit*2, false /* deleteEmptyBuckets */)
|
topicMap[rpcLimiterTopic] = leakybucket.NewCollector(5, defaultBurstLimit*2, false /* deleteEmptyBuckets */)
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,9 @@ func (s *Service) registerRPCHandlers() {
|
|||||||
s.pingHandler,
|
s.pingHandler,
|
||||||
)
|
)
|
||||||
s.registerRPCHandlersAltair()
|
s.registerRPCHandlersAltair()
|
||||||
|
if currEpoch >= params.BeaconConfig().Eip4844ForkEpoch {
|
||||||
|
s.registerRPCHandlersEIP4844()
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.registerRPC(
|
s.registerRPC(
|
||||||
@@ -93,6 +96,13 @@ func (s *Service) registerRPCHandlersAltair() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) registerRPCHandlersEIP4844() {
|
||||||
|
s.registerRPC(
|
||||||
|
p2p.RPCBlobsSidecarsByRangeTopicV1,
|
||||||
|
s.blobsSidecarsByRangeRPCHandler,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Remove all v1 Stream handlers that are no longer supported
|
// Remove all v1 Stream handlers that are no longer supported
|
||||||
// from altair onwards.
|
// from altair onwards.
|
||||||
func (s *Service) unregisterPhase0Handlers() {
|
func (s *Service) unregisterPhase0Handlers() {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ func (s *Service) sendRecentBeaconBlocksRequest(ctx context.Context, blockRoots
|
|||||||
}
|
}
|
||||||
s.pendingQueueLock.Lock()
|
s.pendingQueueLock.Lock()
|
||||||
if err := s.insertBlockToPendingQueue(blk.Block().Slot(), blk, blkRoot); err != nil {
|
if err := s.insertBlockToPendingQueue(blk.Block().Slot(), blk, blkRoot); err != nil {
|
||||||
|
s.pendingQueueLock.Unlock()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
s.pendingQueueLock.Unlock()
|
s.pendingQueueLock.Unlock()
|
||||||
|
|||||||
179
beacon-chain/sync/rpc_blobs_sidecars_by_range.go
Normal file
179
beacon-chain/sync/rpc_blobs_sidecars_by_range.go
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
package sync
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
libp2pcore "github.com/libp2p/go-libp2p-core"
|
||||||
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/blockchain"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/p2p"
|
||||||
|
p2ptypes "github.com/prysmaticlabs/prysm/v3/beacon-chain/p2p/types"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||||
|
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/monitoring/tracing"
|
||||||
|
pb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/time/slots"
|
||||||
|
"go.opencensus.io/trace"
|
||||||
|
)
|
||||||
|
|
||||||
|
// We assume a cost of 1 MiB per sidecar responded to a range request.
|
||||||
|
const avgSidecarBlobsTransferBytes = 1 << 10
|
||||||
|
|
||||||
|
type BlobsSidecarProcessor func(sidecar *pb.BlobsSidecar) error
|
||||||
|
|
||||||
|
// blobsSidecarsByRangeRPCHandler looks up the request blobs from the database from a given start slot index
|
||||||
|
func (s *Service) blobsSidecarsByRangeRPCHandler(ctx context.Context, msg interface{}, stream libp2pcore.Stream) error {
|
||||||
|
ctx, span := trace.StartSpan(ctx, "sync.BlobsSidecarsByRangeHandler")
|
||||||
|
defer span.End()
|
||||||
|
ctx, cancel := context.WithTimeout(ctx, respTimeout)
|
||||||
|
defer cancel()
|
||||||
|
SetRPCStreamDeadlines(stream)
|
||||||
|
|
||||||
|
r, ok := msg.(*pb.BlobsSidecarsByRangeRequest)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("message is not type *pb.BlobsSidecarsByRangeRequest")
|
||||||
|
}
|
||||||
|
|
||||||
|
startSlot := r.StartSlot
|
||||||
|
count := r.Count
|
||||||
|
endSlot := startSlot.Add(count)
|
||||||
|
|
||||||
|
var numBlobs uint64
|
||||||
|
maxRequestBlobsSidecars := params.BeaconNetworkConfig().MaxRequestBlobsSidecars
|
||||||
|
for slot := startSlot; slot < endSlot && numBlobs < maxRequestBlobsSidecars; slot = slot.Add(1) {
|
||||||
|
// TODO(XXX): With danksharding, there could be multiple sidecars per slot. As such, the cost requirement will be dynamic
|
||||||
|
if err := s.rateLimiter.validateRequest(stream, uint64(avgSidecarBlobsTransferBytes)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sidecars, err := s.cfg.beaconDB.BlobsSidecarsBySlot(ctx, slot)
|
||||||
|
if err != nil {
|
||||||
|
s.writeErrorResponseToStream(responseCodeServerError, p2ptypes.ErrGeneric.Error(), stream)
|
||||||
|
tracing.AnnotateError(span, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(sidecars) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var outLen int
|
||||||
|
for _, sidecar := range sidecars {
|
||||||
|
outLen += estimateBlobsSidecarCost(sidecar)
|
||||||
|
SetStreamWriteDeadline(stream, defaultWriteDuration)
|
||||||
|
if chunkErr := WriteBlobsSidecarChunk(stream, s.cfg.chain, s.cfg.p2p.Encoding(), sidecar); chunkErr != nil {
|
||||||
|
log.WithError(chunkErr).Debug("Could not send a chunked response")
|
||||||
|
s.writeErrorResponseToStream(responseCodeServerError, p2ptypes.ErrGeneric.Error(), stream)
|
||||||
|
tracing.AnnotateError(span, chunkErr)
|
||||||
|
return chunkErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
numBlobs++
|
||||||
|
s.rateLimiter.add(stream, int64(outLen))
|
||||||
|
|
||||||
|
// Short-circuit immediately once we've sent the last blob.
|
||||||
|
if slot.Add(1) >= endSlot {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
key := stream.Conn().RemotePeer().String()
|
||||||
|
sidecarLimiter, err := s.rateLimiter.topicCollector(string(stream.Protocol()))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Throttling - wait until we have enough tokens to send the next blobs
|
||||||
|
if sidecarLimiter.Remaining(key) < avgSidecarBlobsTransferBytes {
|
||||||
|
timer := time.NewTimer(sidecarLimiter.TillEmpty(key))
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
timer.Stop()
|
||||||
|
return ctx.Err()
|
||||||
|
case <-timer.C:
|
||||||
|
timer.Stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closeStream(stream, log)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendRecentBlobsSidecarsRequest retrieves sidecars and inserts them to the pending queue
|
||||||
|
func (s *Service) sendRecentBlobSidecarsRequest(ctx context.Context, req *pb.BlobsSidecarsByRangeRequest, pid peer.ID) error {
|
||||||
|
ctx, cancel := context.WithTimeout(ctx, respTimeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
_, err := SendBlobsSidecarsByRangeRequest(ctx, s.cfg.chain, s.cfg.p2p, pid, req, func(sc *pb.BlobsSidecar) error {
|
||||||
|
s.pendingQueueLock.Lock()
|
||||||
|
s.insertSidecarToPendingQueue(&queuedBlobsSidecar{s: sc})
|
||||||
|
s.pendingQueueLock.Unlock()
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func SendBlobsSidecarsByRangeRequest(
|
||||||
|
ctx context.Context, chain blockchain.ChainInfoFetcher, p2pProvider p2p.P2P, pid peer.ID,
|
||||||
|
req *pb.BlobsSidecarsByRangeRequest, sidecarProcessor BlobsSidecarProcessor) ([]*pb.BlobsSidecar, error) {
|
||||||
|
topic, err := p2p.TopicFromMessage(p2p.BlobsSidecarsByRangeMessageName, slots.ToEpoch(chain.CurrentSlot()))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
stream, err := p2pProvider.Send(ctx, req, topic, pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer closeStream(stream, log)
|
||||||
|
|
||||||
|
var sidecars []*pb.BlobsSidecar
|
||||||
|
process := func(sidecar *pb.BlobsSidecar) error {
|
||||||
|
sidecars = append(sidecars, sidecar)
|
||||||
|
if sidecarProcessor != nil {
|
||||||
|
return sidecarProcessor(sidecar)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var prevSlot types.Slot
|
||||||
|
for i := uint64(0); ; i++ {
|
||||||
|
isFirstChunk := len(sidecars) == 0
|
||||||
|
sidecar, err := ReadChunkedBlobsSidecar(stream, chain, p2pProvider, isFirstChunk)
|
||||||
|
if errors.Is(err, io.EOF) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if i >= req.Count || i >= params.BeaconNetworkConfig().MaxRequestBlobsSidecars {
|
||||||
|
return nil, ErrInvalidFetchedData
|
||||||
|
}
|
||||||
|
if sidecar.BeaconBlockSlot < req.StartSlot || sidecar.BeaconBlockSlot >= req.StartSlot.Add(req.Count) {
|
||||||
|
return nil, ErrInvalidFetchedData
|
||||||
|
}
|
||||||
|
// assert slots aren't out of order and always increasing
|
||||||
|
if prevSlot >= sidecar.BeaconBlockSlot {
|
||||||
|
return nil, ErrInvalidFetchedData
|
||||||
|
}
|
||||||
|
prevSlot = sidecar.BeaconBlockSlot
|
||||||
|
|
||||||
|
if err := process(sidecar); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sidecars, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func estimateBlobsSidecarCost(sidecar *pb.BlobsSidecar) int {
|
||||||
|
// This represents the fixed cost (in bytes) of the beacon_block_root and beacon_block_slot fields in the sidecar
|
||||||
|
const overheadCost = 32 + 8
|
||||||
|
cost := overheadCost
|
||||||
|
for _, blob := range sidecar.Blobs {
|
||||||
|
for _, b := range blob.Blob {
|
||||||
|
cost += len(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cost
|
||||||
|
}
|
||||||
166
beacon-chain/sync/rpc_blobs_sidecars_by_range_test.go
Normal file
166
beacon-chain/sync/rpc_blobs_sidecars_by_range_test.go
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
package sync
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/kevinms/leakybucket-go"
|
||||||
|
"github.com/libp2p/go-libp2p-core/mux"
|
||||||
|
"github.com/libp2p/go-libp2p-core/network"
|
||||||
|
"github.com/libp2p/go-libp2p-core/protocol"
|
||||||
|
chainMock "github.com/prysmaticlabs/prysm/v3/beacon-chain/blockchain/testing"
|
||||||
|
mock "github.com/prysmaticlabs/prysm/v3/beacon-chain/blockchain/testing"
|
||||||
|
db "github.com/prysmaticlabs/prysm/v3/beacon-chain/db/testing"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/p2p"
|
||||||
|
p2ptest "github.com/prysmaticlabs/prysm/v3/beacon-chain/p2p/testing"
|
||||||
|
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
||||||
|
consensusblock "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
||||||
|
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||||
|
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/testing/assert"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/testing/require"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/testing/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newBlobsSidecar() *ethpb.SignedBlobsSidecar {
|
||||||
|
return ðpb.SignedBlobsSidecar{
|
||||||
|
Message: ðpb.BlobsSidecar{
|
||||||
|
BeaconBlockRoot: make([]byte, fieldparams.RootLength),
|
||||||
|
},
|
||||||
|
Signature: make([]byte, fieldparams.BLSSignatureLength),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRPCBlobsSidecarsByRange_RPCHandlerReturnsBlobsSidecars(t *testing.T) {
|
||||||
|
p1 := p2ptest.NewTestP2P(t)
|
||||||
|
p2 := p2ptest.NewTestP2P(t)
|
||||||
|
p1.Connect(p2)
|
||||||
|
assert.Equal(t, 1, len(p1.BHost.Network().Peers()), "Expected peers to be connected")
|
||||||
|
d := db.SetupDB(t)
|
||||||
|
|
||||||
|
req := ðpb.BlobsSidecarsByRangeRequest{
|
||||||
|
StartSlot: 100,
|
||||||
|
Count: 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
var blocks []interfaces.SignedBeaconBlock
|
||||||
|
|
||||||
|
for i := req.StartSlot; i < req.StartSlot.Add(req.Count); i += types.Slot(1) {
|
||||||
|
// save the BeaconBlock to index the slots used to retrieve sidecars
|
||||||
|
blk := util.NewBeaconBlock()
|
||||||
|
blk.Block.Slot = i
|
||||||
|
wsb, err := consensusblock.NewSignedBeaconBlock(blk)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NoError(t, d.SaveBlock(context.Background(), wsb))
|
||||||
|
blocks = append(blocks, wsb)
|
||||||
|
|
||||||
|
sidecar := newBlobsSidecar()
|
||||||
|
root, err := blk.Block.HashTreeRoot()
|
||||||
|
require.NoError(t, err)
|
||||||
|
sidecar.Message.BeaconBlockRoot = root[:]
|
||||||
|
sidecar.Message.BeaconBlockSlot = blk.Block.Slot
|
||||||
|
require.NoError(t, d.SaveBlobsSidecar(context.Background(), sidecar.Message))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start service with 160 as allowed blocks capacity (and almost zero capacity recovery).
|
||||||
|
r := &Service{cfg: &config{p2p: p1, beaconDB: d, chain: &chainMock.ChainService{}}, rateLimiter: newRateLimiter(p1)}
|
||||||
|
pcl := protocol.ID(p2p.RPCBlobsSidecarsByRangeTopicV1)
|
||||||
|
topic := string(pcl)
|
||||||
|
r.rateLimiter.limiterMap[topic] = leakybucket.NewCollector(1000, 10000, false)
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(1)
|
||||||
|
p2.BHost.SetStreamHandler(pcl, func(stream network.Stream) {
|
||||||
|
defer wg.Done()
|
||||||
|
for i := req.StartSlot; i < req.StartSlot.Add(req.Count); i += types.Slot(1) {
|
||||||
|
expectSuccess(t, stream)
|
||||||
|
sidecar := new(ethpb.BlobsSidecar)
|
||||||
|
assert.NoError(t, r.cfg.p2p.Encoding().DecodeWithMaxLength(stream, sidecar))
|
||||||
|
assert.Equal(t, i, sidecar.BeaconBlockSlot)
|
||||||
|
|
||||||
|
idx := i - req.StartSlot
|
||||||
|
assert.Equal(t, true, int(idx) < len(blocks))
|
||||||
|
root, err := blocks[idx].Block().HashTreeRoot()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.DeepEqual(t, root[:], sidecar.BeaconBlockRoot)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
stream1, err := p1.BHost.NewStream(context.Background(), p2.BHost.ID(), pcl)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
err = r.blobsSidecarsByRangeRPCHandler(context.Background(), req, stream1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Make sure that rate limiter doesn't limit capacity exceedingly.
|
||||||
|
remainingCapacity := r.rateLimiter.limiterMap[topic].Remaining(p2.PeerID().String())
|
||||||
|
expectedCapacity := int64(10000 - 40*req.Count) // an empty sidecar is 40 bytes
|
||||||
|
require.Equal(t, expectedCapacity, remainingCapacity, "Unexpected rate limiting capacity")
|
||||||
|
|
||||||
|
if util.WaitTimeout(&wg, 1*time.Second) {
|
||||||
|
t.Fatal("Did not receive stream within 1 sec")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSendRequest_SendBlobsSidecarsByRangeRequest(t *testing.T) {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
req := ðpb.BlobsSidecarsByRangeRequest{
|
||||||
|
StartSlot: 20,
|
||||||
|
Count: 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
db := db.SetupDB(t)
|
||||||
|
knownSidecars := make([]*ethpb.BlobsSidecar, 0)
|
||||||
|
for i := req.StartSlot; i < req.StartSlot.Add(req.Count); i += types.Slot(1) {
|
||||||
|
// Save the blocks that will be used to verify blobs later
|
||||||
|
blk := util.HydrateEIP4844SignedBeaconBlock(new(ethpb.SignedBeaconBlockWithBlobKZGs))
|
||||||
|
blk.Block.Slot = types.Slot(i)
|
||||||
|
wsb, err := consensusblock.NewSignedBeaconBlock(blk)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NoError(t, db.SaveBlock(context.Background(), wsb))
|
||||||
|
|
||||||
|
sidecar := newBlobsSidecar()
|
||||||
|
root, err := blk.Block.HashTreeRoot()
|
||||||
|
require.NoError(t, err)
|
||||||
|
sidecar.Message.BeaconBlockRoot = root[:]
|
||||||
|
sidecar.Message.BeaconBlockSlot = blk.Block.Slot
|
||||||
|
knownSidecars = append(knownSidecars, sidecar.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
blobsProvider := func(p2pProvider p2p.P2P) func(stream network.Stream) {
|
||||||
|
return func(stream network.Stream) {
|
||||||
|
defer func() {
|
||||||
|
assert.NoError(t, stream.Close())
|
||||||
|
}()
|
||||||
|
req := ðpb.BlobsSidecarsByRangeRequest{}
|
||||||
|
assert.NoError(t, p2pProvider.Encoding().DecodeWithMaxLength(stream, req))
|
||||||
|
|
||||||
|
for i := req.StartSlot; i < req.StartSlot.Add(req.Count); i += types.Slot(1) {
|
||||||
|
chain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}}
|
||||||
|
idx := i - req.StartSlot
|
||||||
|
sidecar := knownSidecars[idx]
|
||||||
|
err := WriteBlobsSidecarChunk(stream, chain, p2pProvider.Encoding(), sidecar)
|
||||||
|
if err != nil && err.Error() != mux.ErrReset.Error() {
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p1 := p2ptest.NewTestP2P(t)
|
||||||
|
p2 := p2ptest.NewTestP2P(t)
|
||||||
|
p1.Connect(p2)
|
||||||
|
|
||||||
|
pcl := fmt.Sprintf("%s/ssz_snappy", p2p.RPCBlobsSidecarsByRangeTopicV1)
|
||||||
|
p2.SetStreamHandler(pcl, blobsProvider(p2))
|
||||||
|
|
||||||
|
chain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}}
|
||||||
|
sidecars, err := SendBlobsSidecarsByRangeRequest(ctx, chain, p1, p2.PeerID(), req, nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, req.Count, uint64(len(sidecars)))
|
||||||
|
}
|
||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
||||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||||
"github.com/prysmaticlabs/prysm/v3/network/forks"
|
"github.com/prysmaticlabs/prysm/v3/network/forks"
|
||||||
|
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||||
"github.com/prysmaticlabs/prysm/v3/runtime/version"
|
"github.com/prysmaticlabs/prysm/v3/runtime/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -53,6 +54,13 @@ func WriteBlockChunk(stream libp2pcore.Stream, chain blockchain.ChainInfoFetcher
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
obtainedCtx = digest[:]
|
obtainedCtx = digest[:]
|
||||||
|
case version.EIP4844:
|
||||||
|
valRoot := chain.GenesisValidatorsRoot()
|
||||||
|
digest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().Eip4844ForkEpoch, valRoot[:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
obtainedCtx = digest[:]
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := writeContextToStream(obtainedCtx, stream, chain); err != nil {
|
if err := writeContextToStream(obtainedCtx, stream, chain); err != nil {
|
||||||
@@ -73,6 +81,57 @@ func ReadChunkedBlock(stream libp2pcore.Stream, chain blockchain.ForkFetcher, p2
|
|||||||
return readResponseChunk(stream, chain, p2p)
|
return readResponseChunk(stream, chain, p2p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WriteBlobsChunk writes blobs chunk object to stream.
|
||||||
|
// response_chunk ::= <result> | <context-bytes> | <encoding-dependent-header> | <encoded-payload>
|
||||||
|
func WriteBlobsSidecarChunk(stream libp2pcore.Stream, chain blockchain.ChainInfoFetcher, encoding encoder.NetworkEncoding, blobs *ethpb.BlobsSidecar) error {
|
||||||
|
if _, err := stream.Write([]byte{responseCodeSuccess}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
valRoot := chain.GenesisValidatorsRoot()
|
||||||
|
ctxBytes, err := forks.ForkDigestFromEpoch(params.BeaconConfig().Eip4844ForkEpoch, valRoot[:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := writeContextToStream(ctxBytes[:], stream, chain); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = encoding.EncodeWithMaxLength(stream, blobs)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadChunkedBlobsSidecar(stream libp2pcore.Stream, chain blockchain.ChainInfoFetcher, p2p p2p.P2P, isFirstChunk bool) (*ethpb.BlobsSidecar, error) {
|
||||||
|
var (
|
||||||
|
code uint8
|
||||||
|
errMsg string
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if isFirstChunk {
|
||||||
|
code, errMsg, err = ReadStatusCode(stream, p2p.Encoding())
|
||||||
|
} else {
|
||||||
|
SetStreamReadDeadline(stream, respTimeout)
|
||||||
|
code, errMsg, err = readStatusCodeNoDeadline(stream, p2p.Encoding())
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if code != 0 {
|
||||||
|
return nil, errors.New(errMsg)
|
||||||
|
}
|
||||||
|
// No-op for now with the rpc context.
|
||||||
|
rpcCtx, err := readContextFromStream(stream, chain)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// blobs sidecars use v1
|
||||||
|
if len(rpcCtx) != 0 {
|
||||||
|
return nil, errors.New("unexpected fork digest in stream")
|
||||||
|
}
|
||||||
|
sidecar := new(ethpb.BlobsSidecar)
|
||||||
|
err = p2p.Encoding().DecodeWithMaxLength(stream, sidecar)
|
||||||
|
return sidecar, err
|
||||||
|
}
|
||||||
|
|
||||||
// readFirstChunkedBlock reads the first chunked block and applies the appropriate deadlines to
|
// readFirstChunkedBlock reads the first chunked block and applies the appropriate deadlines to
|
||||||
// it.
|
// it.
|
||||||
func readFirstChunkedBlock(stream libp2pcore.Stream, chain blockchain.ForkFetcher, p2p p2p.EncodingProvider) (interfaces.SignedBeaconBlock, error) {
|
func readFirstChunkedBlock(stream libp2pcore.Stream, chain blockchain.ForkFetcher, p2p p2p.EncodingProvider) (interfaces.SignedBeaconBlock, error) {
|
||||||
|
|||||||
@@ -51,10 +51,12 @@ const seenExitSize = 100
|
|||||||
const seenProposerSlashingSize = 100
|
const seenProposerSlashingSize = 100
|
||||||
const badBlockSize = 1000
|
const badBlockSize = 1000
|
||||||
const syncMetricsInterval = 10 * time.Second
|
const syncMetricsInterval = 10 * time.Second
|
||||||
|
const seenBlobsSidecarSize = 1000
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// Seconds in one epoch.
|
// Seconds in one epoch.
|
||||||
pendingBlockExpTime = time.Duration(params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().SecondsPerSlot)) * time.Second
|
pendingBlockExpTime = time.Duration(params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().SecondsPerSlot)) * time.Second
|
||||||
|
pendingSidecarExpTime = time.Duration(params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().SecondsPerSlot)) * time.Second
|
||||||
// time to allow processing early blocks.
|
// time to allow processing early blocks.
|
||||||
earlyBlockProcessingTolerance = slots.MultiplySlotBy(2)
|
earlyBlockProcessingTolerance = slots.MultiplySlotBy(2)
|
||||||
// time to allow processing early attestations.
|
// time to allow processing early attestations.
|
||||||
@@ -107,7 +109,9 @@ type Service struct {
|
|||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
slotToPendingBlocks *gcache.Cache
|
slotToPendingBlocks *gcache.Cache
|
||||||
|
slotToPendingSidecars *gcache.Cache
|
||||||
seenPendingBlocks map[[32]byte]bool
|
seenPendingBlocks map[[32]byte]bool
|
||||||
|
seenPendingSidecars map[[32]byte]bool
|
||||||
blkRootToPendingAtts map[[32]byte][]*ethpb.SignedAggregateAttestationAndProof
|
blkRootToPendingAtts map[[32]byte][]*ethpb.SignedAggregateAttestationAndProof
|
||||||
subHandler *subTopicHandler
|
subHandler *subTopicHandler
|
||||||
pendingAttsLock sync.RWMutex
|
pendingAttsLock sync.RWMutex
|
||||||
@@ -135,22 +139,27 @@ type Service struct {
|
|||||||
badBlockLock sync.RWMutex
|
badBlockLock sync.RWMutex
|
||||||
syncContributionBitsOverlapLock sync.RWMutex
|
syncContributionBitsOverlapLock sync.RWMutex
|
||||||
syncContributionBitsOverlapCache *lru.Cache
|
syncContributionBitsOverlapCache *lru.Cache
|
||||||
|
seenBlobsSidecarLock sync.RWMutex
|
||||||
|
seenBlobsSidecarCache *lru.Cache
|
||||||
signatureChan chan *signatureVerifier
|
signatureChan chan *signatureVerifier
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewService initializes new regular sync service.
|
// NewService initializes new regular sync service.
|
||||||
func NewService(ctx context.Context, opts ...Option) *Service {
|
func NewService(ctx context.Context, opts ...Option) *Service {
|
||||||
c := gcache.New(pendingBlockExpTime /* exp time */, 2*pendingBlockExpTime /* prune time */)
|
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
c := gcache.New(pendingBlockExpTime /* exp time */, 2*pendingBlockExpTime /* prune time */)
|
||||||
|
sidecarCache := gcache.New(pendingSidecarExpTime /* exp time */, 2*pendingSidecarExpTime /* prune time */)
|
||||||
r := &Service{
|
r := &Service{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
chainStarted: abool.New(),
|
chainStarted: abool.New(),
|
||||||
cfg: &config{},
|
cfg: &config{},
|
||||||
slotToPendingBlocks: c,
|
slotToPendingBlocks: c,
|
||||||
seenPendingBlocks: make(map[[32]byte]bool),
|
slotToPendingSidecars: sidecarCache,
|
||||||
blkRootToPendingAtts: make(map[[32]byte][]*ethpb.SignedAggregateAttestationAndProof),
|
seenPendingBlocks: make(map[[32]byte]bool),
|
||||||
signatureChan: make(chan *signatureVerifier, verifierLimit),
|
seenPendingSidecars: make(map[[32]byte]bool),
|
||||||
|
blkRootToPendingAtts: make(map[[32]byte][]*ethpb.SignedAggregateAttestationAndProof),
|
||||||
|
signatureChan: make(chan *signatureVerifier, verifierLimit),
|
||||||
}
|
}
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
if err := opt(r); err != nil {
|
if err := opt(r); err != nil {
|
||||||
@@ -227,6 +236,7 @@ func (s *Service) initCaches() {
|
|||||||
s.seenAttesterSlashingCache = make(map[uint64]bool)
|
s.seenAttesterSlashingCache = make(map[uint64]bool)
|
||||||
s.seenProposerSlashingCache = lruwrpr.New(seenProposerSlashingSize)
|
s.seenProposerSlashingCache = lruwrpr.New(seenProposerSlashingSize)
|
||||||
s.badBlockCache = lruwrpr.New(badBlockSize)
|
s.badBlockCache = lruwrpr.New(badBlockSize)
|
||||||
|
s.seenBlobsSidecarCache = lruwrpr.New(seenBlobsSidecarSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) registerHandlers() {
|
func (s *Service) registerHandlers() {
|
||||||
|
|||||||
@@ -118,6 +118,15 @@ func (s *Service) registerSubscribers(epoch types.Epoch, digest [4]byte) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// EIP-4844 Fork Version
|
||||||
|
if epoch >= params.BeaconConfig().Eip4844ForkEpoch {
|
||||||
|
s.subscribe(
|
||||||
|
p2p.BlobsSubnetTopicFormat,
|
||||||
|
s.validateBlobsSidecarPubSub,
|
||||||
|
s.blobsSidecarSubscriber,
|
||||||
|
digest,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// subscribe to a given topic with a given validator and subscription handler.
|
// subscribe to a given topic with a given validator and subscription handler.
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/blockchain"
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/blockchain"
|
||||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/helpers"
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/helpers"
|
||||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/transition/interop"
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/transition/interop"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/consensus-types/blobs"
|
||||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
||||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
@@ -29,6 +30,39 @@ func (s *Service) beaconBlockSubscriber(ctx context.Context, msg proto.Message)
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var sidecar *ethpb.BlobsSidecar
|
||||||
|
contains, err := blobs.BlockContainsKZGs(block)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if contains {
|
||||||
|
slot := block.Slot()
|
||||||
|
s.pendingQueueLock.RLock()
|
||||||
|
sidecars := s.pendingSidecarsInCache(slot)
|
||||||
|
s.pendingQueueLock.RUnlock()
|
||||||
|
|
||||||
|
queuedSidecar := findSidecarForBlock(block, root, sidecars)
|
||||||
|
if queuedSidecar == nil {
|
||||||
|
// re-schedule block to be processed later.
|
||||||
|
// TODO(XXX): This is a bit inefficient as the block will be validated again
|
||||||
|
s.pendingQueueLock.Lock()
|
||||||
|
if err := s.insertBlockToPendingQueue(slot, signed, root); err != nil {
|
||||||
|
s.pendingQueueLock.Unlock()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.pendingQueueLock.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
sidecar = queuedSidecar.s
|
||||||
|
if sidecar != nil {
|
||||||
|
if err := signed.SetSideCar(ðpb.SignedBlobsSidecar{
|
||||||
|
Message: sidecar,
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := s.cfg.chain.ReceiveBlock(ctx, signed, root); err != nil {
|
if err := s.cfg.chain.ReceiveBlock(ctx, signed, root); err != nil {
|
||||||
if blockchain.IsInvalidBlock(err) {
|
if blockchain.IsInvalidBlock(err) {
|
||||||
r := blockchain.InvalidBlockRoot(err)
|
r := blockchain.InvalidBlockRoot(err)
|
||||||
|
|||||||
26
beacon-chain/sync/subscriber_blobs_sidecar.go
Normal file
26
beacon-chain/sync/subscriber_blobs_sidecar.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package sync
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Service) blobsSidecarSubscriber(ctx context.Context, msg proto.Message) error {
|
||||||
|
m, ok := msg.(*ethpb.SignedBlobsSidecar)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("message was not type *eth.SignedBlobsSidecar, type=%T", msg)
|
||||||
|
}
|
||||||
|
if m == nil {
|
||||||
|
return errors.New("nil blobs sidecar message")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sidecars are handled by the block queue processing routine
|
||||||
|
s.pendingQueueLock.Lock()
|
||||||
|
s.insertSidecarToPendingQueue(&queuedBlobsSidecar{m.Message, m.Signature, true})
|
||||||
|
s.pendingQueueLock.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/libp2p/go-libp2p-core/peer"
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/protolambda/go-kzg/bls"
|
||||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/blocks"
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/blocks"
|
||||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/feed"
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/feed"
|
||||||
blockfeed "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/feed/block"
|
blockfeed "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/feed/block"
|
||||||
@@ -16,11 +17,13 @@ import (
|
|||||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
|
||||||
"github.com/prysmaticlabs/prysm/v3/config/features"
|
"github.com/prysmaticlabs/prysm/v3/config/features"
|
||||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/consensus-types/blobs"
|
||||||
consensusblocks "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
consensusblocks "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
||||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
||||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||||
"github.com/prysmaticlabs/prysm/v3/monitoring/tracing"
|
"github.com/prysmaticlabs/prysm/v3/monitoring/tracing"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/runtime/version"
|
||||||
prysmTime "github.com/prysmaticlabs/prysm/v3/time"
|
prysmTime "github.com/prysmaticlabs/prysm/v3/time"
|
||||||
"github.com/prysmaticlabs/prysm/v3/time/slots"
|
"github.com/prysmaticlabs/prysm/v3/time/slots"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
@@ -244,7 +247,7 @@ func (s *Service) validateBeaconBlock(ctx context.Context, blk interfaces.Signed
|
|||||||
return errors.New("incorrect proposer index")
|
return errors.New("incorrect proposer index")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = s.validateBellatrixBeaconBlock(ctx, parentState, blk.Block()); err != nil {
|
if err = s.validateEIP4844BeaconBlock(ctx, parentState, blk.Block()); err != nil {
|
||||||
if errors.Is(err, ErrOptimisticParent) {
|
if errors.Is(err, ErrOptimisticParent) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -255,6 +258,59 @@ func (s *Service) validateBeaconBlock(ctx context.Context, blk interfaces.Signed
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validateEIP4844BeaconBlock validates the block for the EIP-4844 fork.
|
||||||
|
// In addition to the spec for validateBellatrixBeaconBlock:
|
||||||
|
// [REJECT] The KZG commitments of the blobs are all correctly encoded compressed BLS G1 Points.
|
||||||
|
// -- i.e. `all(bls.KeyValidate(commitment) for commitment in block.body.blob_kzgs)`
|
||||||
|
// [REJECT] The KZG commitments correspond to the versioned hashes in the transactions list.
|
||||||
|
// -- i.e. `verify_kzgs_against_transactions(block.body.execution_payload.transactions, block.body.blob_kzgs)`
|
||||||
|
func (s *Service) validateEIP4844BeaconBlock(ctx context.Context, parentState state.BeaconState, blk interfaces.BeaconBlock) error {
|
||||||
|
if err := s.validateBellatrixBeaconBlock(ctx, parentState, blk); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
body := blk.Body()
|
||||||
|
executionEnabled, err := blocks.IsExecutionEnabled(parentState, body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !executionEnabled {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
payload, err := body.Execution()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if payload == nil {
|
||||||
|
return errors.New("execution payload is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if consensusblocks.IsPreEIP4844Version(blk.Version()) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
blobKzgs, err := body.BlobKzgs()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
blobKzgsInput := make([][48]byte, len(blobKzgs))
|
||||||
|
for i := range blobKzgs {
|
||||||
|
if len(blobKzgs[i]) != 48 {
|
||||||
|
return errors.New("invalid blob kzg length")
|
||||||
|
}
|
||||||
|
if _, err := bls.FromCompressedG1(blobKzgs[i]); err != nil {
|
||||||
|
return errors.Wrap(err, "invalid blob kzg encoding")
|
||||||
|
}
|
||||||
|
blobKzgsInput[i] = bytesutil.ToBytes48(blobKzgs[i])
|
||||||
|
}
|
||||||
|
txs, err := payload.Transactions()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return blobs.VerifyKzgsAgainstTxs(txs, blobKzgsInput)
|
||||||
|
}
|
||||||
|
|
||||||
// validateBellatrixBeaconBlock validates the block for the Bellatrix fork.
|
// validateBellatrixBeaconBlock validates the block for the Bellatrix fork.
|
||||||
// spec code:
|
// spec code:
|
||||||
//
|
//
|
||||||
@@ -269,8 +325,13 @@ func (s *Service) validateBeaconBlock(ctx context.Context, blk interfaces.Signed
|
|||||||
// [IGNORE] The block's parent (defined by block.parent_root) passes all validation (including execution
|
// [IGNORE] The block's parent (defined by block.parent_root) passes all validation (including execution
|
||||||
// node verification of the block.body.execution_payload).
|
// node verification of the block.body.execution_payload).
|
||||||
func (s *Service) validateBellatrixBeaconBlock(ctx context.Context, parentState state.BeaconState, blk interfaces.BeaconBlock) error {
|
func (s *Service) validateBellatrixBeaconBlock(ctx context.Context, parentState state.BeaconState, blk interfaces.BeaconBlock) error {
|
||||||
// Error if block and state are not the same version
|
sv := parentState.Version()
|
||||||
if parentState.Version() != blk.Version() {
|
bv := blk.Version()
|
||||||
|
switch {
|
||||||
|
case sv == bv:
|
||||||
|
case sv == version.Bellatrix && bv == version.EIP4844:
|
||||||
|
// The EIP-4844 BeaconState is the same as Bellatrix's
|
||||||
|
default:
|
||||||
return errors.New("block and state are not the same version")
|
return errors.New("block and state are not the same version")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package sync
|
package sync
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
@@ -9,9 +10,12 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
gethTypes "github.com/ethereum/go-ethereum/core/types"
|
||||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||||
pubsubpb "github.com/libp2p/go-libp2p-pubsub/pb"
|
pubsubpb "github.com/libp2p/go-libp2p-pubsub/pb"
|
||||||
gcache "github.com/patrickmn/go-cache"
|
gcache "github.com/patrickmn/go-cache"
|
||||||
|
"github.com/protolambda/ztyp/codec"
|
||||||
"github.com/prysmaticlabs/prysm/v3/async/abool"
|
"github.com/prysmaticlabs/prysm/v3/async/abool"
|
||||||
mock "github.com/prysmaticlabs/prysm/v3/beacon-chain/blockchain/testing"
|
mock "github.com/prysmaticlabs/prysm/v3/beacon-chain/blockchain/testing"
|
||||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/helpers"
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/helpers"
|
||||||
@@ -1394,3 +1398,171 @@ func Test_getBlockFields(t *testing.T) {
|
|||||||
require.LogsContain(t, hook, "nil block")
|
require.LogsContain(t, hook, "nil block")
|
||||||
require.LogsContain(t, hook, "bad block")
|
require.LogsContain(t, hook, "bad block")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestValidateBeaconBlockPubSub_ValidBlobKzgs(t *testing.T) {
|
||||||
|
db := dbtest.SetupDB(t)
|
||||||
|
p := p2ptest.NewTestP2P(t)
|
||||||
|
ctx := context.Background()
|
||||||
|
beaconState, privKeys := util.DeterministicGenesisStateBellatrix(t, 100)
|
||||||
|
parentBlock := util.HydrateEIP4844SignedBeaconBlock(ðpb.SignedBeaconBlockWithBlobKZGs{})
|
||||||
|
signedParentBlock, err := blocks.NewSignedBeaconBlock(parentBlock)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NoError(t, db.SaveBlock(ctx, signedParentBlock))
|
||||||
|
bRoot, err := parentBlock.Block.HashTreeRoot()
|
||||||
|
require.NoError(t, err)
|
||||||
|
presentTime := time.Now().Unix()
|
||||||
|
require.NoError(t, beaconState.SetGenesisTime(uint64(presentTime)))
|
||||||
|
require.NoError(t, db.SaveState(ctx, beaconState, bRoot))
|
||||||
|
require.NoError(t, db.SaveStateSummary(ctx, ðpb.StateSummary{Root: bRoot[:]}))
|
||||||
|
copied := beaconState.Copy()
|
||||||
|
require.NoError(t, copied.SetSlot(1))
|
||||||
|
proposerIdx, err := helpers.BeaconProposerIndex(ctx, copied)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
msg := util.HydrateEIP4844SignedBeaconBlock(ðpb.SignedBeaconBlockWithBlobKZGs{})
|
||||||
|
msg.Block.ParentRoot = bRoot[:]
|
||||||
|
msg.Block.Slot = 1
|
||||||
|
msg.Block.ProposerIndex = proposerIdx
|
||||||
|
msg.Block.Body.ExecutionPayload.Timestamp = uint64(presentTime) + params.BeaconConfig().SecondsPerSlot
|
||||||
|
msg.Block.Body.ExecutionPayload.GasUsed = 10
|
||||||
|
msg.Block.Body.ExecutionPayload.GasLimit = 11
|
||||||
|
msg.Block.Body.ExecutionPayload.BlockHash = bytesutil.PadTo([]byte("blockHash"), 32)
|
||||||
|
msg.Block.Body.ExecutionPayload.ParentHash = bytesutil.PadTo([]byte("parentHash"), 32)
|
||||||
|
|
||||||
|
blob := gethTypes.Blob{[32]byte{0x10, 0x11}}
|
||||||
|
commitment, ok := blob.ComputeCommitment()
|
||||||
|
require.Equal(t, ok, true)
|
||||||
|
sbt := gethTypes.SignedBlobTx{
|
||||||
|
Message: gethTypes.BlobTxMessage{
|
||||||
|
BlobVersionedHashes: []common.Hash{commitment.ComputeVersionedHash()},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
var txbuf bytes.Buffer
|
||||||
|
w := bufio.NewWriter(&txbuf)
|
||||||
|
encW := codec.NewEncodingWriter(w)
|
||||||
|
require.NoError(t, sbt.Serialize(encW))
|
||||||
|
require.NoError(t, w.Flush())
|
||||||
|
var tx []byte
|
||||||
|
tx = append(tx, gethTypes.BlobTxType)
|
||||||
|
tx = append(tx, txbuf.Bytes()...)
|
||||||
|
|
||||||
|
msg.Block.Body.ExecutionPayload.Transactions = append(msg.Block.Body.ExecutionPayload.Transactions, tx)
|
||||||
|
msg.Block.Body.BlobKzgs = [][]byte{commitment[:]}
|
||||||
|
msg.Signature, err = signing.ComputeDomainAndSign(beaconState, 0, msg.Block, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx])
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
stateGen := stategen.New(db)
|
||||||
|
chainService := &mock.ChainService{Genesis: time.Unix(presentTime-int64(params.BeaconConfig().SecondsPerSlot), 0),
|
||||||
|
DB: db,
|
||||||
|
FinalizedCheckPoint: ðpb.Checkpoint{
|
||||||
|
Epoch: 0,
|
||||||
|
Root: make([]byte, 32),
|
||||||
|
}}
|
||||||
|
r := &Service{
|
||||||
|
cfg: &config{
|
||||||
|
beaconDB: db,
|
||||||
|
p2p: p,
|
||||||
|
initialSync: &mockSync.Sync{IsSyncing: false},
|
||||||
|
chain: chainService,
|
||||||
|
blockNotifier: chainService.BlockNotifier(),
|
||||||
|
stateGen: stateGen,
|
||||||
|
},
|
||||||
|
seenBlockCache: lruwrpr.New(10),
|
||||||
|
badBlockCache: lruwrpr.New(10),
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
_, err = p.Encoding().EncodeGossip(buf, msg)
|
||||||
|
require.NoError(t, err)
|
||||||
|
topic := p2p.GossipTypeMapping[reflect.TypeOf(msg)]
|
||||||
|
genesisValidatorsRoot := r.cfg.chain.GenesisValidatorsRoot()
|
||||||
|
eip4844Digest, err := signing.ComputeForkDigest(params.BeaconConfig().Eip4844ForkVersion, genesisValidatorsRoot[:])
|
||||||
|
require.NoError(t, err)
|
||||||
|
topic = r.addDigestToTopic(topic, eip4844Digest)
|
||||||
|
m := &pubsub.Message{
|
||||||
|
Message: &pubsubpb.Message{
|
||||||
|
Data: buf.Bytes(),
|
||||||
|
Topic: &topic,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := r.validateBeaconBlockPubSub(ctx, "", m)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, pubsub.ValidationAccept, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidateBeaconBlockPubSub_InvalidBlobKzgs(t *testing.T) {
|
||||||
|
db := dbtest.SetupDB(t)
|
||||||
|
p := p2ptest.NewTestP2P(t)
|
||||||
|
ctx := context.Background()
|
||||||
|
beaconState, privKeys := util.DeterministicGenesisStateBellatrix(t, 100)
|
||||||
|
parentBlock := util.HydrateEIP4844SignedBeaconBlock(ðpb.SignedBeaconBlockWithBlobKZGs{})
|
||||||
|
signedParentBlock, err := blocks.NewSignedBeaconBlock(parentBlock)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NoError(t, db.SaveBlock(ctx, signedParentBlock))
|
||||||
|
bRoot, err := parentBlock.Block.HashTreeRoot()
|
||||||
|
require.NoError(t, err)
|
||||||
|
presentTime := time.Now().Unix()
|
||||||
|
require.NoError(t, beaconState.SetGenesisTime(uint64(presentTime)))
|
||||||
|
require.NoError(t, db.SaveState(ctx, beaconState, bRoot))
|
||||||
|
require.NoError(t, db.SaveStateSummary(ctx, ðpb.StateSummary{Root: bRoot[:]}))
|
||||||
|
copied := beaconState.Copy()
|
||||||
|
require.NoError(t, copied.SetSlot(1))
|
||||||
|
proposerIdx, err := helpers.BeaconProposerIndex(ctx, copied)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
msg := util.HydrateEIP4844SignedBeaconBlock(ðpb.SignedBeaconBlockWithBlobKZGs{})
|
||||||
|
msg.Block.ParentRoot = bRoot[:]
|
||||||
|
msg.Block.Slot = 1
|
||||||
|
msg.Block.ProposerIndex = proposerIdx
|
||||||
|
msg.Block.Body.ExecutionPayload.Timestamp = uint64(presentTime) + params.BeaconConfig().SecondsPerSlot
|
||||||
|
msg.Block.Body.ExecutionPayload.GasUsed = 10
|
||||||
|
msg.Block.Body.ExecutionPayload.GasLimit = 11
|
||||||
|
msg.Block.Body.ExecutionPayload.BlockHash = bytesutil.PadTo([]byte("blockHash"), 32)
|
||||||
|
msg.Block.Body.ExecutionPayload.ParentHash = bytesutil.PadTo([]byte("parentHash"), 32)
|
||||||
|
msg.Block.Body.ExecutionPayload.Transactions = append(msg.Block.Body.ExecutionPayload.Transactions, []byte("transaction 1"))
|
||||||
|
msg.Block.Body.ExecutionPayload.Transactions = append(msg.Block.Body.ExecutionPayload.Transactions, []byte("transaction 2"))
|
||||||
|
kzg := [48]byte{'a'}
|
||||||
|
msg.Block.Body.BlobKzgs = [][]byte{kzg[:]}
|
||||||
|
msg.Signature, err = signing.ComputeDomainAndSign(beaconState, 0, msg.Block, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx])
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
stateGen := stategen.New(db)
|
||||||
|
chainService := &mock.ChainService{Genesis: time.Unix(presentTime-int64(params.BeaconConfig().SecondsPerSlot), 0),
|
||||||
|
DB: db,
|
||||||
|
FinalizedCheckPoint: ðpb.Checkpoint{
|
||||||
|
Epoch: 0,
|
||||||
|
Root: make([]byte, 32),
|
||||||
|
}}
|
||||||
|
r := &Service{
|
||||||
|
cfg: &config{
|
||||||
|
beaconDB: db,
|
||||||
|
p2p: p,
|
||||||
|
initialSync: &mockSync.Sync{IsSyncing: false},
|
||||||
|
chain: chainService,
|
||||||
|
blockNotifier: chainService.BlockNotifier(),
|
||||||
|
stateGen: stateGen,
|
||||||
|
},
|
||||||
|
seenBlockCache: lruwrpr.New(10),
|
||||||
|
badBlockCache: lruwrpr.New(10),
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
_, err = p.Encoding().EncodeGossip(buf, msg)
|
||||||
|
require.NoError(t, err)
|
||||||
|
topic := p2p.GossipTypeMapping[reflect.TypeOf(msg)]
|
||||||
|
genesisValidatorsRoot := r.cfg.chain.GenesisValidatorsRoot()
|
||||||
|
eip4844Digest, err := signing.ComputeForkDigest(params.BeaconConfig().Eip4844ForkVersion, genesisValidatorsRoot[:])
|
||||||
|
require.NoError(t, err)
|
||||||
|
topic = r.addDigestToTopic(topic, eip4844Digest)
|
||||||
|
m := &pubsub.Message{
|
||||||
|
Message: &pubsubpb.Message{
|
||||||
|
Data: buf.Bytes(),
|
||||||
|
Topic: &topic,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := r.validateBeaconBlockPubSub(ctx, "", m)
|
||||||
|
assert.Equal(t, pubsub.ValidationReject, res, "block with invalid parent should be ignored")
|
||||||
|
require.ErrorContains(t, "invalid blob kzg encoding", err)
|
||||||
|
}
|
||||||
|
|||||||
238
beacon-chain/sync/validate_blobs_sidecar.go
Normal file
238
beacon-chain/sync/validate_blobs_sidecar.go
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
package sync
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
|
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
kbls "github.com/protolambda/go-kzg/bls"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/altair"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/signing"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
||||||
|
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/crypto/bls"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/monitoring/tracing"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/network/forks"
|
||||||
|
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||||
|
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/time/slots"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"go.opencensus.io/trace"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Gossip Validation Conditions:
|
||||||
|
// [IGNORE] the sidecar.beacon_block_slot is for the current slot (with a MAXIMUM_GOSSIP_CLOCK_DISPARITY allowance)
|
||||||
|
// -- i.e. blobs_sidecar.beacon_block_slot == current_slot.
|
||||||
|
// [REJECT] the sidecar.blobs are all well formatted, i.e. the BLSFieldElement in valid range (x < BLS_MODULUS).
|
||||||
|
// [REJECT] the beacon proposer signature, signed_blobs_sidecar.signature, is valid
|
||||||
|
// [IGNORE] The sidecar is the first sidecar with valid signature received for the (proposer_index, sidecar.beacon_block_slot)
|
||||||
|
// combination, where proposer_index is the validator index of the beacon block proposer of blobs_sidecar.beacon_block_slot
|
||||||
|
func (s *Service) validateBlobsSidecarPubSub(ctx context.Context, pid peer.ID, msg *pubsub.Message) (pubsub.ValidationResult, error) {
|
||||||
|
// Accept the sidecar if it came from itself.
|
||||||
|
if pid == s.cfg.p2p.PeerID() {
|
||||||
|
return pubsub.ValidationAccept, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, span := trace.StartSpan(ctx, "sync.validateBlobsSidecar")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
|
// Ignore the sidecar if the beacon node is syncing.
|
||||||
|
if s.cfg.initialSync.Syncing() {
|
||||||
|
return pubsub.ValidationIgnore, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
m, err := s.decodePubsubMessage(msg)
|
||||||
|
if err != nil {
|
||||||
|
tracing.AnnotateError(span, err)
|
||||||
|
return pubsub.ValidationReject, errors.Wrap(err, "Could not decode message")
|
||||||
|
}
|
||||||
|
|
||||||
|
signed, ok := m.(*ethpb.SignedBlobsSidecar)
|
||||||
|
if !ok {
|
||||||
|
return pubsub.ValidationReject, errWrongMessage
|
||||||
|
}
|
||||||
|
if signed.Message == nil {
|
||||||
|
return pubsub.ValidationReject, errors.New("nil sidecar message")
|
||||||
|
}
|
||||||
|
if signed.Signature == nil {
|
||||||
|
return pubsub.ValidationReject, errors.New("nil sidecar signature")
|
||||||
|
}
|
||||||
|
if signed.Message.BeaconBlockRoot == nil || signed.Message.Blobs == nil {
|
||||||
|
return pubsub.ValidationReject, errors.New("nil sidecar message data")
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.cfg.beaconDB.HasBlobsSidecar(ctx, bytesutil.ToBytes32(signed.Message.BeaconBlockRoot)) {
|
||||||
|
return pubsub.ValidationIgnore, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := altair.ValidateSyncMessageTime(signed.Message.BeaconBlockSlot, s.cfg.chain.GenesisTime(), params.BeaconNetworkConfig().MaximumGossipClockDisparity); err != nil {
|
||||||
|
tracing.AnnotateError(span, err)
|
||||||
|
return pubsub.ValidationIgnore, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that the sidecar isn't associated with an invalid block
|
||||||
|
if s.hasBadBlock(bytesutil.ToBytes32(signed.Message.BeaconBlockRoot)) {
|
||||||
|
return pubsub.ValidationReject, errors.New("sidecar references bad block root")
|
||||||
|
}
|
||||||
|
|
||||||
|
s.pendingQueueLock.RLock()
|
||||||
|
if s.seenPendingSidecars[bytesutil.ToBytes32(signed.Message.BeaconBlockRoot)] {
|
||||||
|
s.pendingQueueLock.RUnlock()
|
||||||
|
return pubsub.ValidationIgnore, nil
|
||||||
|
}
|
||||||
|
s.pendingQueueLock.RUnlock()
|
||||||
|
|
||||||
|
if err := validateBlobFr(signed.Message.Blobs); err != nil {
|
||||||
|
log.WithError(err).WithField("slot", signed.Message.BeaconBlockSlot).Debug("Sidecar contains invalid BLS field elements")
|
||||||
|
return pubsub.ValidationReject, err
|
||||||
|
}
|
||||||
|
|
||||||
|
blk, err := s.getPendingBlockForSidecar(signed.Message)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).WithField("slot", signed.Message.BeaconBlockSlot).Warn("Failed to lookup pending block in queue")
|
||||||
|
return pubsub.ValidationIgnore, err
|
||||||
|
}
|
||||||
|
if blk == nil || blk.IsNil() {
|
||||||
|
// We expect the block including this sidecar to follow shortly. Add the sidecar the queue so the pending block processor can readily retrieve it
|
||||||
|
s.pendingQueueLock.Lock()
|
||||||
|
s.insertSidecarToPendingQueue(&queuedBlobsSidecar{signed.Message, signed.Signature, false})
|
||||||
|
s.pendingQueueLock.Unlock()
|
||||||
|
return pubsub.ValidationIgnore, nil
|
||||||
|
}
|
||||||
|
if err := blocks.BeaconBlockIsNil(blk); err != nil {
|
||||||
|
log.WithError(err).WithField("slot", signed.Message.BeaconBlockSlot).Warn("Nil block found in pending queue")
|
||||||
|
return pubsub.ValidationIgnore, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
validationResult, err := s.validateBlobsSidecar(ctx, blk, signed)
|
||||||
|
if err != nil {
|
||||||
|
tracing.AnnotateError(span, err)
|
||||||
|
return validationResult, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.hasSeenBlobsSidecarIndexSlot(blk.Block().ProposerIndex(), signed.Message.BeaconBlockSlot) {
|
||||||
|
return pubsub.ValidationIgnore, nil
|
||||||
|
}
|
||||||
|
s.setSeenSidecarIndexSlot(blk.Block().ProposerIndex(), signed.Message.BeaconBlockSlot)
|
||||||
|
|
||||||
|
msg.ValidatorData = signed
|
||||||
|
|
||||||
|
span.AddAttributes(trace.Int64Attribute("numBlobs", int64(len(signed.Message.Blobs))))
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"blockSlot": signed.Message.BeaconBlockRoot,
|
||||||
|
"blockRoot": signed.Message.BeaconBlockRoot,
|
||||||
|
"numBlobs": len(signed.Message.Blobs),
|
||||||
|
}).Debug("Received sidecar")
|
||||||
|
return pubsub.ValidationAccept, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) validateBlobsSidecar(ctx context.Context, blk interfaces.SignedBeaconBlock, m *ethpb.SignedBlobsSidecar) (pubsub.ValidationResult, error) {
|
||||||
|
return s.validateBlobsSidecarSignature(ctx, blk, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) validateBlobsSidecarSignature(ctx context.Context, blk interfaces.SignedBeaconBlock, m *ethpb.SignedBlobsSidecar) (pubsub.ValidationResult, error) {
|
||||||
|
ctx, span := trace.StartSpan(ctx, "sync.validateBlobsSidecarSignature")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
|
currentEpoch := slots.ToEpoch(m.Message.BeaconBlockSlot)
|
||||||
|
fork, err := forks.Fork(currentEpoch)
|
||||||
|
if err != nil {
|
||||||
|
return pubsub.ValidationIgnore, err
|
||||||
|
}
|
||||||
|
state, err := s.cfg.stateGen.StateByRoot(ctx, bytesutil.ToBytes32(m.Message.BeaconBlockRoot))
|
||||||
|
if err != nil {
|
||||||
|
return pubsub.ValidationIgnore, err
|
||||||
|
}
|
||||||
|
proposer, err := state.ValidatorAtIndex(blk.Block().ProposerIndex())
|
||||||
|
if err != nil {
|
||||||
|
return pubsub.ValidationIgnore, err
|
||||||
|
}
|
||||||
|
proposerPubKey := proposer.PublicKey
|
||||||
|
blobSigning := ðpb.BlobsSidecar{
|
||||||
|
BeaconBlockRoot: m.Message.BeaconBlockRoot,
|
||||||
|
BeaconBlockSlot: m.Message.BeaconBlockSlot,
|
||||||
|
Blobs: m.Message.Blobs,
|
||||||
|
AggregatedProof: m.Message.AggregatedProof,
|
||||||
|
}
|
||||||
|
|
||||||
|
domain, err := signing.Domain(fork, currentEpoch, params.BeaconConfig().DomainBlobsSidecar, state.GenesisValidatorsRoot())
|
||||||
|
if err != nil {
|
||||||
|
return pubsub.ValidationReject, err
|
||||||
|
}
|
||||||
|
pKey, err := bls.PublicKeyFromBytes(proposerPubKey)
|
||||||
|
if err != nil {
|
||||||
|
return pubsub.ValidationReject, err
|
||||||
|
}
|
||||||
|
sigRoot, err := signing.ComputeSigningRoot(blobSigning, domain)
|
||||||
|
if err != nil {
|
||||||
|
return pubsub.ValidationReject, err
|
||||||
|
}
|
||||||
|
|
||||||
|
set := &bls.SignatureBatch{
|
||||||
|
Messages: [][32]byte{sigRoot},
|
||||||
|
PublicKeys: []bls.PublicKey{pKey},
|
||||||
|
Signatures: [][]byte{m.Signature},
|
||||||
|
}
|
||||||
|
return s.validateWithBatchVerifier(ctx, "blobs sidecar signature", set)
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateBlobFr(blobs []*enginev1.Blob) error {
|
||||||
|
for _, blob := range blobs {
|
||||||
|
for _, b := range blob.Blob {
|
||||||
|
if len(b) != 32 {
|
||||||
|
return errors.New("invalid blob field element size")
|
||||||
|
}
|
||||||
|
if !kbls.ValidFr(bytesutil.ToBytes32(b)) {
|
||||||
|
return errors.New("invalid blob field element")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) hasSeenBlobsSidecarIndexSlot(proposerIndex types.ValidatorIndex, slot types.Slot) bool {
|
||||||
|
s.seenBlobsSidecarLock.RLock()
|
||||||
|
defer s.seenBlobsSidecarLock.RUnlock()
|
||||||
|
|
||||||
|
b := append(bytesutil.Bytes32(uint64(proposerIndex)), bytesutil.Bytes32(uint64(slot))...)
|
||||||
|
_, seen := s.seenBlobsSidecarCache.Get(string(b))
|
||||||
|
return seen
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) setSeenSidecarIndexSlot(proposerIndex types.ValidatorIndex, slot types.Slot) {
|
||||||
|
s.seenBlobsSidecarLock.Lock()
|
||||||
|
defer s.seenBlobsSidecarLock.Unlock()
|
||||||
|
|
||||||
|
b := append(bytesutil.Bytes32(uint64(proposerIndex)), bytesutil.Bytes32(uint64(slot))...)
|
||||||
|
s.seenBlobsSidecarCache.Add(string(b), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) getPendingBlockForSidecar(sc *ethpb.BlobsSidecar) (interfaces.SignedBeaconBlock, error) {
|
||||||
|
blkRoot := bytesutil.ToBytes32(sc.BeaconBlockRoot)
|
||||||
|
s.pendingQueueLock.RLock()
|
||||||
|
if !s.seenPendingBlocks[blkRoot] {
|
||||||
|
s.pendingQueueLock.RUnlock()
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
blks := s.pendingBlocksInCache(sc.BeaconBlockSlot)
|
||||||
|
s.pendingQueueLock.RUnlock()
|
||||||
|
|
||||||
|
for _, b := range blks {
|
||||||
|
if b.Block().Slot() != sc.BeaconBlockSlot {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
r, err := b.Block().HashTreeRoot()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if r != bytesutil.ToBytes32(sc.BeaconBlockRoot) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
@@ -161,6 +161,18 @@ var (
|
|||||||
Usage: "The amount of blocks the local peer is bounded to request and respond to in a batch.",
|
Usage: "The amount of blocks the local peer is bounded to request and respond to in a batch.",
|
||||||
Value: 64,
|
Value: 64,
|
||||||
}
|
}
|
||||||
|
// BlobsTransferRate specifies the bytes/sec transfer rate of requested blobs.
|
||||||
|
BlobsTransferRate = &cli.IntFlag{
|
||||||
|
Name: "blobs-transfer-rate",
|
||||||
|
Usage: "The bytes/sec transfer rate of requested blobs.",
|
||||||
|
Value: 1 << 20, // 1 MiB
|
||||||
|
}
|
||||||
|
// BlobsTransferRateThresh specifies the maximum bytes per second that can be transferred.
|
||||||
|
BlobsTransferRateThresh = &cli.IntFlag{
|
||||||
|
Name: "blobs-transfer-rate-thresh",
|
||||||
|
Usage: "The maximum bytes per second that can be transferred.",
|
||||||
|
Value: 1 << 23, // 8 MiB
|
||||||
|
}
|
||||||
// BlockBatchLimitBurstFactor specifies the factor by which block batch size may increase.
|
// BlockBatchLimitBurstFactor specifies the factor by which block batch size may increase.
|
||||||
BlockBatchLimitBurstFactor = &cli.IntFlag{
|
BlockBatchLimitBurstFactor = &cli.IntFlag{
|
||||||
Name: "block-batch-limit-burst-factor",
|
Name: "block-batch-limit-burst-factor",
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ type GlobalFlags struct {
|
|||||||
MinimumPeersPerSubnet int
|
MinimumPeersPerSubnet int
|
||||||
BlockBatchLimit int
|
BlockBatchLimit int
|
||||||
BlockBatchLimitBurstFactor int
|
BlockBatchLimitBurstFactor int
|
||||||
|
BlobsTransferRate int
|
||||||
|
BlobsTransferRateThresh int
|
||||||
}
|
}
|
||||||
|
|
||||||
var globalConfig *GlobalFlags
|
var globalConfig *GlobalFlags
|
||||||
@@ -38,8 +40,11 @@ func ConfigureGlobalFlags(ctx *cli.Context) {
|
|||||||
log.Warn("Subscribing to All Attestation Subnets")
|
log.Warn("Subscribing to All Attestation Subnets")
|
||||||
cfg.SubscribeToAllSubnets = true
|
cfg.SubscribeToAllSubnets = true
|
||||||
}
|
}
|
||||||
|
// TODO(EIP-4844): assert BlockBatchLimit < MAX_REQUEST_BLOBS_SIDECARS (128) as initial-sync uses this same config for sidecar fetch
|
||||||
cfg.BlockBatchLimit = ctx.Int(BlockBatchLimit.Name)
|
cfg.BlockBatchLimit = ctx.Int(BlockBatchLimit.Name)
|
||||||
cfg.BlockBatchLimitBurstFactor = ctx.Int(BlockBatchLimitBurstFactor.Name)
|
cfg.BlockBatchLimitBurstFactor = ctx.Int(BlockBatchLimitBurstFactor.Name)
|
||||||
|
cfg.BlobsTransferRate = ctx.Int(BlobsTransferRate.Name)
|
||||||
|
cfg.BlobsTransferRateThresh = ctx.Int(BlobsTransferRateThresh.Name)
|
||||||
cfg.MinimumPeersPerSubnet = ctx.Int(MinPeersPerSubnet.Name)
|
cfg.MinimumPeersPerSubnet = ctx.Int(MinPeersPerSubnet.Name)
|
||||||
configureMinimumPeers(ctx, cfg)
|
configureMinimumPeers(ctx, cfg)
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,8 @@ var appFlags = []cli.Flag{
|
|||||||
flags.SetGCPercent,
|
flags.SetGCPercent,
|
||||||
flags.BlockBatchLimit,
|
flags.BlockBatchLimit,
|
||||||
flags.BlockBatchLimitBurstFactor,
|
flags.BlockBatchLimitBurstFactor,
|
||||||
|
flags.BlobsTransferRate,
|
||||||
|
flags.BlobsTransferRateThresh,
|
||||||
flags.InteropMockEth1DataVotesFlag,
|
flags.InteropMockEth1DataVotesFlag,
|
||||||
flags.InteropGenesisStateFlag,
|
flags.InteropGenesisStateFlag,
|
||||||
flags.InteropNumValidatorsFlag,
|
flags.InteropNumValidatorsFlag,
|
||||||
|
|||||||
@@ -114,6 +114,8 @@ var appHelpFlagGroups = []flagGroup{
|
|||||||
flags.SlotsPerArchivedPoint,
|
flags.SlotsPerArchivedPoint,
|
||||||
flags.BlockBatchLimit,
|
flags.BlockBatchLimit,
|
||||||
flags.BlockBatchLimitBurstFactor,
|
flags.BlockBatchLimitBurstFactor,
|
||||||
|
flags.BlobsTransferRate,
|
||||||
|
flags.BlobsTransferRateThresh,
|
||||||
flags.EnableDebugRPCEndpoints,
|
flags.EnableDebugRPCEndpoints,
|
||||||
flags.SubscribeToAllSubnets,
|
flags.SubscribeToAllSubnets,
|
||||||
flags.HistoricalSlasherNode,
|
flags.HistoricalSlasherNode,
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ var Commands = &cli.Command{
|
|||||||
features.PraterTestnet,
|
features.PraterTestnet,
|
||||||
features.RopstenTestnet,
|
features.RopstenTestnet,
|
||||||
features.SepoliaTestnet,
|
features.SepoliaTestnet,
|
||||||
|
features.EIP4844Testnet,
|
||||||
cmd.AcceptTosFlag,
|
cmd.AcceptTosFlag,
|
||||||
}),
|
}),
|
||||||
Before: func(cliCtx *cli.Context) error {
|
Before: func(cliCtx *cli.Context) error {
|
||||||
@@ -67,6 +68,7 @@ var Commands = &cli.Command{
|
|||||||
features.PraterTestnet,
|
features.PraterTestnet,
|
||||||
features.RopstenTestnet,
|
features.RopstenTestnet,
|
||||||
features.SepoliaTestnet,
|
features.SepoliaTestnet,
|
||||||
|
features.EIP4844Testnet,
|
||||||
cmd.AcceptTosFlag,
|
cmd.AcceptTosFlag,
|
||||||
}),
|
}),
|
||||||
Before: func(cliCtx *cli.Context) error {
|
Before: func(cliCtx *cli.Context) error {
|
||||||
@@ -101,6 +103,7 @@ var Commands = &cli.Command{
|
|||||||
features.PraterTestnet,
|
features.PraterTestnet,
|
||||||
features.RopstenTestnet,
|
features.RopstenTestnet,
|
||||||
features.SepoliaTestnet,
|
features.SepoliaTestnet,
|
||||||
|
features.EIP4844Testnet,
|
||||||
cmd.AcceptTosFlag,
|
cmd.AcceptTosFlag,
|
||||||
}),
|
}),
|
||||||
Before: func(cliCtx *cli.Context) error {
|
Before: func(cliCtx *cli.Context) error {
|
||||||
@@ -132,6 +135,7 @@ var Commands = &cli.Command{
|
|||||||
features.PraterTestnet,
|
features.PraterTestnet,
|
||||||
features.RopstenTestnet,
|
features.RopstenTestnet,
|
||||||
features.SepoliaTestnet,
|
features.SepoliaTestnet,
|
||||||
|
features.EIP4844Testnet,
|
||||||
cmd.AcceptTosFlag,
|
cmd.AcceptTosFlag,
|
||||||
}),
|
}),
|
||||||
Before: func(cliCtx *cli.Context) error {
|
Before: func(cliCtx *cli.Context) error {
|
||||||
@@ -169,6 +173,7 @@ var Commands = &cli.Command{
|
|||||||
features.PraterTestnet,
|
features.PraterTestnet,
|
||||||
features.RopstenTestnet,
|
features.RopstenTestnet,
|
||||||
features.SepoliaTestnet,
|
features.SepoliaTestnet,
|
||||||
|
features.EIP4844Testnet,
|
||||||
cmd.AcceptTosFlag,
|
cmd.AcceptTosFlag,
|
||||||
}),
|
}),
|
||||||
Before: func(cliCtx *cli.Context) error {
|
Before: func(cliCtx *cli.Context) error {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ var Commands = &cli.Command{
|
|||||||
features.PraterTestnet,
|
features.PraterTestnet,
|
||||||
features.RopstenTestnet,
|
features.RopstenTestnet,
|
||||||
features.SepoliaTestnet,
|
features.SepoliaTestnet,
|
||||||
|
features.EIP4844Testnet,
|
||||||
cmd.AcceptTosFlag,
|
cmd.AcceptTosFlag,
|
||||||
}),
|
}),
|
||||||
Before: func(cliCtx *cli.Context) error {
|
Before: func(cliCtx *cli.Context) error {
|
||||||
@@ -53,6 +54,7 @@ var Commands = &cli.Command{
|
|||||||
features.PraterTestnet,
|
features.PraterTestnet,
|
||||||
features.RopstenTestnet,
|
features.RopstenTestnet,
|
||||||
features.SepoliaTestnet,
|
features.SepoliaTestnet,
|
||||||
|
features.EIP4844Testnet,
|
||||||
cmd.AcceptTosFlag,
|
cmd.AcceptTosFlag,
|
||||||
}),
|
}),
|
||||||
Before: func(cliCtx *cli.Context) error {
|
Before: func(cliCtx *cli.Context) error {
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ var Commands = &cli.Command{
|
|||||||
features.PraterTestnet,
|
features.PraterTestnet,
|
||||||
features.RopstenTestnet,
|
features.RopstenTestnet,
|
||||||
features.SepoliaTestnet,
|
features.SepoliaTestnet,
|
||||||
|
features.EIP4844Testnet,
|
||||||
cmd.AcceptTosFlag,
|
cmd.AcceptTosFlag,
|
||||||
}),
|
}),
|
||||||
Before: func(cliCtx *cli.Context) error {
|
Before: func(cliCtx *cli.Context) error {
|
||||||
@@ -69,6 +70,7 @@ var Commands = &cli.Command{
|
|||||||
features.PraterTestnet,
|
features.PraterTestnet,
|
||||||
features.RopstenTestnet,
|
features.RopstenTestnet,
|
||||||
features.SepoliaTestnet,
|
features.SepoliaTestnet,
|
||||||
|
features.EIP4844Testnet,
|
||||||
cmd.AcceptTosFlag,
|
cmd.AcceptTosFlag,
|
||||||
}),
|
}),
|
||||||
Before: func(cliCtx *cli.Context) error {
|
Before: func(cliCtx *cli.Context) error {
|
||||||
@@ -101,6 +103,7 @@ var Commands = &cli.Command{
|
|||||||
features.PraterTestnet,
|
features.PraterTestnet,
|
||||||
features.RopstenTestnet,
|
features.RopstenTestnet,
|
||||||
features.SepoliaTestnet,
|
features.SepoliaTestnet,
|
||||||
|
features.EIP4844Testnet,
|
||||||
cmd.AcceptTosFlag,
|
cmd.AcceptTosFlag,
|
||||||
}),
|
}),
|
||||||
Before: func(cliCtx *cli.Context) error {
|
Before: func(cliCtx *cli.Context) error {
|
||||||
|
|||||||
@@ -135,6 +135,12 @@ func configureTestnet(ctx *cli.Context) error {
|
|||||||
}
|
}
|
||||||
applySepoliaFeatureFlags(ctx)
|
applySepoliaFeatureFlags(ctx)
|
||||||
params.UseSepoliaNetworkConfig()
|
params.UseSepoliaNetworkConfig()
|
||||||
|
} else if ctx.Bool(EIP4844Testnet.Name) {
|
||||||
|
log.Warn("Running on the EIP-4844 Beacon Chain Testnet")
|
||||||
|
if err := params.SetActive(params.EIP4844Config().Copy()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
params.UseEIP4844NetworkConfig()
|
||||||
} else {
|
} else {
|
||||||
if ctx.IsSet(cmd.ChainConfigFileFlag.Name) {
|
if ctx.IsSet(cmd.ChainConfigFileFlag.Name) {
|
||||||
log.Warn("Running on custom Ethereum network specified in a chain configuration yaml file")
|
log.Warn("Running on custom Ethereum network specified in a chain configuration yaml file")
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ var (
|
|||||||
Name: "sepolia",
|
Name: "sepolia",
|
||||||
Usage: "Run Prysm configured for the Sepolia beacon chain test network",
|
Usage: "Run Prysm configured for the Sepolia beacon chain test network",
|
||||||
}
|
}
|
||||||
|
EIP4844Testnet = &cli.BoolFlag{
|
||||||
|
Name: "eip4844",
|
||||||
|
Usage: "Run Prysm configured for the EIP-4844 (proto-danksharding) beacon chain test network",
|
||||||
|
}
|
||||||
// Mainnet flag for easier tooling, no-op
|
// Mainnet flag for easier tooling, no-op
|
||||||
Mainnet = &cli.BoolFlag{
|
Mainnet = &cli.BoolFlag{
|
||||||
Value: true,
|
Value: true,
|
||||||
@@ -136,6 +140,7 @@ var ValidatorFlags = append(deprecatedFlags, []cli.Flag{
|
|||||||
PraterTestnet,
|
PraterTestnet,
|
||||||
RopstenTestnet,
|
RopstenTestnet,
|
||||||
SepoliaTestnet,
|
SepoliaTestnet,
|
||||||
|
EIP4844Testnet,
|
||||||
Mainnet,
|
Mainnet,
|
||||||
dynamicKeyReloadDebounceInterval,
|
dynamicKeyReloadDebounceInterval,
|
||||||
attestTimely,
|
attestTimely,
|
||||||
@@ -156,6 +161,7 @@ var BeaconChainFlags = append(deprecatedBeaconFlags, append(deprecatedFlags, []c
|
|||||||
PraterTestnet,
|
PraterTestnet,
|
||||||
RopstenTestnet,
|
RopstenTestnet,
|
||||||
SepoliaTestnet,
|
SepoliaTestnet,
|
||||||
|
EIP4844Testnet,
|
||||||
Mainnet,
|
Mainnet,
|
||||||
disablePeerScorer,
|
disablePeerScorer,
|
||||||
disableBroadcastSlashingFlag,
|
disableBroadcastSlashingFlag,
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ go_library(
|
|||||||
"minimal_config.go",
|
"minimal_config.go",
|
||||||
"network_config.go",
|
"network_config.go",
|
||||||
"testnet_e2e_config.go",
|
"testnet_e2e_config.go",
|
||||||
|
"testnet_eip4844_config.go",
|
||||||
"testnet_prater_config.go",
|
"testnet_prater_config.go",
|
||||||
"testnet_ropsten_config.go",
|
"testnet_ropsten_config.go",
|
||||||
"testnet_sepolia_config.go",
|
"testnet_sepolia_config.go",
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ type BeaconChainConfig struct {
|
|||||||
DomainSyncCommittee [4]byte `yaml:"DOMAIN_SYNC_COMMITTEE" spec:"true"` // DomainVoluntaryExit defines the BLS signature domain for sync committee.
|
DomainSyncCommittee [4]byte `yaml:"DOMAIN_SYNC_COMMITTEE" spec:"true"` // DomainVoluntaryExit defines the BLS signature domain for sync committee.
|
||||||
DomainSyncCommitteeSelectionProof [4]byte `yaml:"DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF" spec:"true"` // DomainSelectionProof defines the BLS signature domain for sync committee selection proof.
|
DomainSyncCommitteeSelectionProof [4]byte `yaml:"DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF" spec:"true"` // DomainSelectionProof defines the BLS signature domain for sync committee selection proof.
|
||||||
DomainContributionAndProof [4]byte `yaml:"DOMAIN_CONTRIBUTION_AND_PROOF" spec:"true"` // DomainAggregateAndProof defines the BLS signature domain for contribution and proof.
|
DomainContributionAndProof [4]byte `yaml:"DOMAIN_CONTRIBUTION_AND_PROOF" spec:"true"` // DomainAggregateAndProof defines the BLS signature domain for contribution and proof.
|
||||||
|
DomainBlobsSidecar [4]byte `yaml:"DOMAIN_BLOBS_SIDECAR" spec:"true"` // DomainBlobsSidecar defines the BLS signature domain.
|
||||||
DomainApplicationMask [4]byte `yaml:"DOMAIN_APPLICATION_MASK" spec:"true"` // DomainApplicationMask defines the BLS signature domain for application mask.
|
DomainApplicationMask [4]byte `yaml:"DOMAIN_APPLICATION_MASK" spec:"true"` // DomainApplicationMask defines the BLS signature domain for application mask.
|
||||||
DomainApplicationBuilder [4]byte // DomainApplicationBuilder defines the BLS signature domain for application builder.
|
DomainApplicationBuilder [4]byte // DomainApplicationBuilder defines the BLS signature domain for application builder.
|
||||||
DomainBLSToExecutionChange [4]byte // DomainBLSToExecutionChange defines the BLS signature domain to change withdrawal addresses to ETH1 prefix
|
DomainBLSToExecutionChange [4]byte // DomainBLSToExecutionChange defines the BLS signature domain to change withdrawal addresses to ETH1 prefix
|
||||||
@@ -147,6 +148,8 @@ type BeaconChainConfig struct {
|
|||||||
BellatrixForkEpoch types.Epoch `yaml:"BELLATRIX_FORK_EPOCH" spec:"true"` // BellatrixForkEpoch is used to represent the assigned fork epoch for bellatrix.
|
BellatrixForkEpoch types.Epoch `yaml:"BELLATRIX_FORK_EPOCH" spec:"true"` // BellatrixForkEpoch is used to represent the assigned fork epoch for bellatrix.
|
||||||
ShardingForkVersion []byte `yaml:"SHARDING_FORK_VERSION" spec:"true"` // ShardingForkVersion is used to represent the fork version for sharding.
|
ShardingForkVersion []byte `yaml:"SHARDING_FORK_VERSION" spec:"true"` // ShardingForkVersion is used to represent the fork version for sharding.
|
||||||
ShardingForkEpoch types.Epoch `yaml:"SHARDING_FORK_EPOCH" spec:"true"` // ShardingForkEpoch is used to represent the assigned fork epoch for sharding.
|
ShardingForkEpoch types.Epoch `yaml:"SHARDING_FORK_EPOCH" spec:"true"` // ShardingForkEpoch is used to represent the assigned fork epoch for sharding.
|
||||||
|
Eip4844ForkVersion []byte `yaml:"EIP4844_FORK_VERSION" spec:"true"` // Eip4844ForkVersion is used to represent the fork version for Eip4844.
|
||||||
|
Eip4844ForkEpoch types.Epoch `yaml:"EIP4844_FORK_EPOCH" spec:"true"` // Eip4844ForkEpoch is used to represent the assigned fork epoch for Eip4844.
|
||||||
CapellaForkVersion []byte `yaml:"CAPELLA_FORK_VERSION" spec:"true"` // CapellaForkVersion is used to represent the fork version for capella.
|
CapellaForkVersion []byte `yaml:"CAPELLA_FORK_VERSION" spec:"true"` // CapellaForkVersion is used to represent the fork version for capella.
|
||||||
CapellaForkEpoch types.Epoch `yaml:"CAPELLA_FORK_EPOCH" spec:"true"` // CapellaForkEpoch is used to represent the assigned fork epoch for capella.
|
CapellaForkEpoch types.Epoch `yaml:"CAPELLA_FORK_EPOCH" spec:"true"` // CapellaForkEpoch is used to represent the assigned fork epoch for capella.
|
||||||
|
|
||||||
@@ -220,6 +223,8 @@ func configForkSchedule(b *BeaconChainConfig) map[[fieldparams.VersionLength]byt
|
|||||||
fvs[bytesutil.ToBytes4(b.AltairForkVersion)] = b.AltairForkEpoch
|
fvs[bytesutil.ToBytes4(b.AltairForkVersion)] = b.AltairForkEpoch
|
||||||
// Set Bellatrix fork data.
|
// Set Bellatrix fork data.
|
||||||
fvs[bytesutil.ToBytes4(b.BellatrixForkVersion)] = b.BellatrixForkEpoch
|
fvs[bytesutil.ToBytes4(b.BellatrixForkVersion)] = b.BellatrixForkEpoch
|
||||||
|
// Set EIP4844 fork data.
|
||||||
|
fvs[bytesutil.ToBytes4(b.Eip4844ForkVersion)] = b.Eip4844ForkEpoch
|
||||||
return fvs
|
return fvs
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,5 +236,7 @@ func configForkNames(b *BeaconChainConfig) map[[fieldparams.VersionLength]byte]s
|
|||||||
fvn[bytesutil.ToBytes4(b.AltairForkVersion)] = "altair"
|
fvn[bytesutil.ToBytes4(b.AltairForkVersion)] = "altair"
|
||||||
// Set Bellatrix fork data.
|
// Set Bellatrix fork data.
|
||||||
fvn[bytesutil.ToBytes4(b.BellatrixForkVersion)] = "bellatrix"
|
fvn[bytesutil.ToBytes4(b.BellatrixForkVersion)] = "bellatrix"
|
||||||
|
// Set EIP4844 fork data.
|
||||||
|
fvn[bytesutil.ToBytes4(b.Eip4844ForkVersion)] = "eip4844"
|
||||||
return fvn
|
return fvn
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ func init() {
|
|||||||
E2EMainnetTestConfig(),
|
E2EMainnetTestConfig(),
|
||||||
InteropConfig(),
|
InteropConfig(),
|
||||||
RopstenConfig(),
|
RopstenConfig(),
|
||||||
|
EIP4844Config(),
|
||||||
}
|
}
|
||||||
configs = newConfigset(defaults...)
|
configs = newConfigset(defaults...)
|
||||||
// ensure that main net is always present and active by default
|
// ensure that main net is always present and active by default
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ func InteropConfig() *BeaconChainConfig {
|
|||||||
c.GenesisForkVersion = []byte{0, 0, 0, 235}
|
c.GenesisForkVersion = []byte{0, 0, 0, 235}
|
||||||
c.AltairForkVersion = []byte{1, 0, 0, 235}
|
c.AltairForkVersion = []byte{1, 0, 0, 235}
|
||||||
c.BellatrixForkVersion = []byte{2, 0, 0, 235}
|
c.BellatrixForkVersion = []byte{2, 0, 0, 235}
|
||||||
c.ShardingForkVersion = []byte{3, 0, 0, 235}
|
c.Eip4844ForkVersion = []byte{3, 0, 0, 235}
|
||||||
|
c.ShardingForkVersion = []byte{4, 0, 0, 235}
|
||||||
|
|
||||||
c.InitializeForkSchedule()
|
c.InitializeForkSchedule()
|
||||||
return c
|
return c
|
||||||
|
|||||||
@@ -194,6 +194,8 @@ func ConfigToYaml(cfg *BeaconChainConfig) []byte {
|
|||||||
fmt.Sprintf("ALTAIR_FORK_VERSION: %#x", cfg.AltairForkVersion),
|
fmt.Sprintf("ALTAIR_FORK_VERSION: %#x", cfg.AltairForkVersion),
|
||||||
fmt.Sprintf("BELLATRIX_FORK_EPOCH: %d", cfg.BellatrixForkEpoch),
|
fmt.Sprintf("BELLATRIX_FORK_EPOCH: %d", cfg.BellatrixForkEpoch),
|
||||||
fmt.Sprintf("BELLATRIX_FORK_VERSION: %#x", cfg.BellatrixForkVersion),
|
fmt.Sprintf("BELLATRIX_FORK_VERSION: %#x", cfg.BellatrixForkVersion),
|
||||||
|
fmt.Sprintf("EIP4844_FORK_EPOCH: %d", cfg.Eip4844ForkEpoch),
|
||||||
|
fmt.Sprintf("EIP4844_FORK_VERSION: %#x", cfg.Eip4844ForkVersion),
|
||||||
fmt.Sprintf("SHARDING_FORK_EPOCH: %d", cfg.ShardingForkEpoch),
|
fmt.Sprintf("SHARDING_FORK_EPOCH: %d", cfg.ShardingForkEpoch),
|
||||||
fmt.Sprintf("SHARDING_FORK_VERSION: %#x", cfg.ShardingForkVersion),
|
fmt.Sprintf("SHARDING_FORK_VERSION: %#x", cfg.ShardingForkVersion),
|
||||||
fmt.Sprintf("INACTIVITY_SCORE_BIAS: %d", cfg.InactivityScoreBias),
|
fmt.Sprintf("INACTIVITY_SCORE_BIAS: %d", cfg.InactivityScoreBias),
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
||||||
|
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -21,28 +22,31 @@ const (
|
|||||||
genesisForkEpoch = 0
|
genesisForkEpoch = 0
|
||||||
// Altair Fork Epoch for mainnet config.
|
// Altair Fork Epoch for mainnet config.
|
||||||
mainnetAltairForkEpoch = 74240 // Oct 27, 2021, 10:56:23am UTC
|
mainnetAltairForkEpoch = 74240 // Oct 27, 2021, 10:56:23am UTC
|
||||||
// Bellatrix Fork Epoch for mainnet config.
|
// Bellatrix Fork Epoch for mainnet config.q
|
||||||
mainnetBellatrixForkEpoch = 144896 // Sept 6, 2022, 11:34:47am UTC
|
mainnetBellatrixForkEpoch = 144896 // Sept 6, 2022, 11:34:47am UTC
|
||||||
|
mainnetEip4844ForkEpoch = math.MaxUint64
|
||||||
)
|
)
|
||||||
|
|
||||||
var mainnetNetworkConfig = &NetworkConfig{
|
var mainnetNetworkConfig = &NetworkConfig{
|
||||||
GossipMaxSize: 1 << 20, // 1 MiB
|
GossipMaxSize: 1 << 20, // 1 MiB
|
||||||
GossipMaxSizeBellatrix: 10 * 1 << 20, // 10 MiB
|
GossipMaxSizeBellatrix: 10 * 1 << 20, // 10 MiB
|
||||||
MaxChunkSize: 1 << 20, // 1 MiB
|
MaxChunkSize: 1 << 20, // 1 MiB
|
||||||
MaxChunkSizeBellatrix: 10 * 1 << 20, // 10 MiB
|
MaxChunkSizeBellatrix: 10 * 1 << 20, // 10 MiB
|
||||||
AttestationSubnetCount: 64,
|
AttestationSubnetCount: 64,
|
||||||
AttestationPropagationSlotRange: 32,
|
AttestationPropagationSlotRange: 32,
|
||||||
MaxRequestBlocks: 1 << 10, // 1024
|
MaxRequestBlocks: 1 << 10, // 1024
|
||||||
TtfbTimeout: 5 * time.Second,
|
MaxRequestBlobsSidecars: 2 << 7, // 128
|
||||||
RespTimeout: 10 * time.Second,
|
MinEpochsForBlobsSidecarsRequest: types.Epoch(2 << 13), // 8192, 1.2 months
|
||||||
MaximumGossipClockDisparity: 500 * time.Millisecond,
|
TtfbTimeout: 5 * time.Second,
|
||||||
MessageDomainInvalidSnappy: [4]byte{00, 00, 00, 00},
|
RespTimeout: 10 * time.Second,
|
||||||
MessageDomainValidSnappy: [4]byte{01, 00, 00, 00},
|
MaximumGossipClockDisparity: 500 * time.Millisecond,
|
||||||
ETH2Key: "eth2",
|
MessageDomainInvalidSnappy: [4]byte{00, 00, 00, 00},
|
||||||
AttSubnetKey: "attnets",
|
MessageDomainValidSnappy: [4]byte{01, 00, 00, 00},
|
||||||
SyncCommsSubnetKey: "syncnets",
|
ETH2Key: "eth2",
|
||||||
MinimumPeersInSubnetSearch: 20,
|
AttSubnetKey: "attnets",
|
||||||
ContractDeploymentBlock: 11184524, // Note: contract was deployed in block 11052984 but no transactions were sent until 11184524.
|
SyncCommsSubnetKey: "syncnets",
|
||||||
|
MinimumPeersInSubnetSearch: 20,
|
||||||
|
ContractDeploymentBlock: 11184524, // Note: contract was deployed in block 11052984 but no transactions were sent until 11184524.
|
||||||
BootstrapNodes: []string{
|
BootstrapNodes: []string{
|
||||||
// Teku team's bootnode
|
// Teku team's bootnode
|
||||||
"enr:-KG4QOtcP9X1FbIMOe17QNMKqDxCpm14jcX5tiOE4_TyMrFqbmhPZHK_ZPG2Gxb1GE2xdtodOfx9-cgvNtxnRyHEmC0ghGV0aDKQ9aX9QgAAAAD__________4JpZIJ2NIJpcIQDE8KdiXNlY3AyNTZrMaEDhpehBDbZjM_L9ek699Y7vhUJ-eAdMyQW_Fil522Y0fODdGNwgiMog3VkcIIjKA",
|
"enr:-KG4QOtcP9X1FbIMOe17QNMKqDxCpm14jcX5tiOE4_TyMrFqbmhPZHK_ZPG2Gxb1GE2xdtodOfx9-cgvNtxnRyHEmC0ghGV0aDKQ9aX9QgAAAAD__________4JpZIJ2NIJpcIQDE8KdiXNlY3AyNTZrMaEDhpehBDbZjM_L9ek699Y7vhUJ-eAdMyQW_Fil522Y0fODdGNwgiMog3VkcIIjKA",
|
||||||
@@ -166,6 +170,7 @@ var mainnetBeaconConfig = &BeaconChainConfig{
|
|||||||
DomainSyncCommittee: bytesutil.Uint32ToBytes4(0x07000000),
|
DomainSyncCommittee: bytesutil.Uint32ToBytes4(0x07000000),
|
||||||
DomainSyncCommitteeSelectionProof: bytesutil.Uint32ToBytes4(0x08000000),
|
DomainSyncCommitteeSelectionProof: bytesutil.Uint32ToBytes4(0x08000000),
|
||||||
DomainContributionAndProof: bytesutil.Uint32ToBytes4(0x09000000),
|
DomainContributionAndProof: bytesutil.Uint32ToBytes4(0x09000000),
|
||||||
|
DomainBlobsSidecar: bytesutil.Uint32ToBytes4(0x10000000),
|
||||||
DomainApplicationMask: bytesutil.Uint32ToBytes4(0x00000001),
|
DomainApplicationMask: bytesutil.Uint32ToBytes4(0x00000001),
|
||||||
DomainApplicationBuilder: bytesutil.Uint32ToBytes4(0x00000001),
|
DomainApplicationBuilder: bytesutil.Uint32ToBytes4(0x00000001),
|
||||||
DomainBLSToExecutionChange: bytesutil.Uint32ToBytes4(0x0A000000),
|
DomainBLSToExecutionChange: bytesutil.Uint32ToBytes4(0x0A000000),
|
||||||
@@ -206,7 +211,9 @@ var mainnetBeaconConfig = &BeaconChainConfig{
|
|||||||
BellatrixForkEpoch: mainnetBellatrixForkEpoch,
|
BellatrixForkEpoch: mainnetBellatrixForkEpoch,
|
||||||
CapellaForkVersion: []byte{3, 0, 0, 0},
|
CapellaForkVersion: []byte{3, 0, 0, 0},
|
||||||
CapellaForkEpoch: math.MaxUint64,
|
CapellaForkEpoch: math.MaxUint64,
|
||||||
ShardingForkVersion: []byte{4, 0, 0, 0},
|
Eip4844ForkVersion: []byte{4, 0, 0, 0},
|
||||||
|
Eip4844ForkEpoch: math.MaxUint64,
|
||||||
|
ShardingForkVersion: []byte{8, 0, 0, 0},
|
||||||
ShardingForkEpoch: math.MaxUint64,
|
ShardingForkEpoch: math.MaxUint64,
|
||||||
|
|
||||||
// New values introduced in Altair hard fork 1.
|
// New values introduced in Altair hard fork 1.
|
||||||
@@ -272,15 +279,18 @@ func FillTestVersions(c *BeaconChainConfig, b byte) {
|
|||||||
c.GenesisForkVersion = make([]byte, fieldparams.VersionLength)
|
c.GenesisForkVersion = make([]byte, fieldparams.VersionLength)
|
||||||
c.AltairForkVersion = make([]byte, fieldparams.VersionLength)
|
c.AltairForkVersion = make([]byte, fieldparams.VersionLength)
|
||||||
c.BellatrixForkVersion = make([]byte, fieldparams.VersionLength)
|
c.BellatrixForkVersion = make([]byte, fieldparams.VersionLength)
|
||||||
|
c.Eip4844ForkVersion = make([]byte, fieldparams.VersionLength)
|
||||||
c.ShardingForkVersion = make([]byte, fieldparams.VersionLength)
|
c.ShardingForkVersion = make([]byte, fieldparams.VersionLength)
|
||||||
|
|
||||||
c.GenesisForkVersion[fieldparams.VersionLength-1] = b
|
c.GenesisForkVersion[fieldparams.VersionLength-1] = b
|
||||||
c.AltairForkVersion[fieldparams.VersionLength-1] = b
|
c.AltairForkVersion[fieldparams.VersionLength-1] = b
|
||||||
c.BellatrixForkVersion[fieldparams.VersionLength-1] = b
|
c.BellatrixForkVersion[fieldparams.VersionLength-1] = b
|
||||||
|
c.Eip4844ForkVersion[fieldparams.VersionLength-1] = b
|
||||||
c.ShardingForkVersion[fieldparams.VersionLength-1] = b
|
c.ShardingForkVersion[fieldparams.VersionLength-1] = b
|
||||||
|
|
||||||
c.GenesisForkVersion[0] = 0
|
c.GenesisForkVersion[0] = 0
|
||||||
c.AltairForkVersion[0] = 1
|
c.AltairForkVersion[0] = 1
|
||||||
c.BellatrixForkVersion[0] = 2
|
c.BellatrixForkVersion[0] = 2
|
||||||
c.ShardingForkVersion[0] = 3
|
c.Eip4844ForkVersion[0] = 3
|
||||||
|
c.ShardingForkVersion[0] = 4
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,7 +87,9 @@ func MinimalSpecConfig() *BeaconChainConfig {
|
|||||||
minimalConfig.BellatrixForkEpoch = math.MaxUint64
|
minimalConfig.BellatrixForkEpoch = math.MaxUint64
|
||||||
minimalConfig.CapellaForkVersion = []byte{3, 0, 0, 1}
|
minimalConfig.CapellaForkVersion = []byte{3, 0, 0, 1}
|
||||||
minimalConfig.CapellaForkEpoch = math.MaxUint64
|
minimalConfig.CapellaForkEpoch = math.MaxUint64
|
||||||
minimalConfig.ShardingForkVersion = []byte{4, 0, 0, 1}
|
minimalConfig.Eip4844ForkVersion = []byte{4, 0, 0, 1}
|
||||||
|
minimalConfig.Eip4844ForkEpoch = math.MaxUint64
|
||||||
|
minimalConfig.ShardingForkVersion = []byte{8, 0, 0, 1}
|
||||||
minimalConfig.ShardingForkEpoch = math.MaxUint64
|
minimalConfig.ShardingForkEpoch = math.MaxUint64
|
||||||
|
|
||||||
minimalConfig.SyncCommitteeSize = 32
|
minimalConfig.SyncCommitteeSize = 32
|
||||||
|
|||||||
@@ -9,18 +9,20 @@ import (
|
|||||||
|
|
||||||
// NetworkConfig defines the spec based network parameters.
|
// NetworkConfig defines the spec based network parameters.
|
||||||
type NetworkConfig struct {
|
type NetworkConfig struct {
|
||||||
GossipMaxSize uint64 `yaml:"GOSSIP_MAX_SIZE"` // GossipMaxSize is the maximum allowed size of uncompressed gossip messages.
|
GossipMaxSize uint64 `yaml:"GOSSIP_MAX_SIZE"` // GossipMaxSize is the maximum allowed size of uncompressed gossip messages.
|
||||||
GossipMaxSizeBellatrix uint64 `yaml:"GOSSIP_MAX_SIZE_BELLATRIX"` // GossipMaxSizeBellatrix is the maximum allowed size of uncompressed gossip messages after the bellatrix epoch.
|
GossipMaxSizeBellatrix uint64 `yaml:"GOSSIP_MAX_SIZE_BELLATRIX"` // GossipMaxSizeBellatrix is the maximum allowed size of uncompressed gossip messages after the bellatrix epoch.
|
||||||
MaxChunkSize uint64 `yaml:"MAX_CHUNK_SIZE"` // MaxChunkSize is the maximum allowed size of uncompressed req/resp chunked responses.
|
MaxChunkSize uint64 `yaml:"MAX_CHUNK_SIZE"` // MaxChunkSize is the maximum allowed size of uncompressed req/resp chunked responses.
|
||||||
MaxChunkSizeBellatrix uint64 `yaml:"MAX_CHUNK_SIZE_BELLATRIX"` // MaxChunkSizeBellatrix is the maximum allowed size of uncompressed req/resp chunked responses after the bellatrix epoch.
|
MaxChunkSizeBellatrix uint64 `yaml:"MAX_CHUNK_SIZE_BELLATRIX"` // MaxChunkSizeBellatrix is the maximum allowed size of uncompressed req/resp chunked responses after the bellatrix epoch.
|
||||||
AttestationSubnetCount uint64 `yaml:"ATTESTATION_SUBNET_COUNT"` // AttestationSubnetCount is the number of attestation subnets used in the gossipsub protocol.
|
AttestationSubnetCount uint64 `yaml:"ATTESTATION_SUBNET_COUNT"` // AttestationSubnetCount is the number of attestation subnets used in the gossipsub protocol.
|
||||||
AttestationPropagationSlotRange types.Slot `yaml:"ATTESTATION_PROPAGATION_SLOT_RANGE"` // AttestationPropagationSlotRange is the maximum number of slots during which an attestation can be propagated.
|
AttestationPropagationSlotRange types.Slot `yaml:"ATTESTATION_PROPAGATION_SLOT_RANGE"` // AttestationPropagationSlotRange is the maximum number of slots during which an attestation can be propagated.
|
||||||
MaxRequestBlocks uint64 `yaml:"MAX_REQUEST_BLOCKS"` // MaxRequestBlocks is the maximum number of blocks in a single request.
|
MaxRequestBlocks uint64 `yaml:"MAX_REQUEST_BLOCKS"` // MaxRequestBlocks is the maximum number of blocks in a single request.
|
||||||
TtfbTimeout time.Duration `yaml:"TTFB_TIMEOUT"` // TtfbTimeout is the maximum time to wait for first byte of request response (time-to-first-byte).
|
MaxRequestBlobsSidecars uint64 `yaml:"MAX_REQUEST_BLOBS_SIDECARS"` // MaxRequestBlobsSidecars is the maximum number of blobs sidecars in a single request.
|
||||||
RespTimeout time.Duration `yaml:"RESP_TIMEOUT"` // RespTimeout is the maximum time for complete response transfer.
|
MinEpochsForBlobsSidecarsRequest types.Epoch `yaml:"MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS"` // MinEpochsForBlobsSidecarsRequest is the minimum epoch range over which a node must serve blobs sidecars.
|
||||||
MaximumGossipClockDisparity time.Duration `yaml:"MAXIMUM_GOSSIP_CLOCK_DISPARITY"` // MaximumGossipClockDisparity is the maximum milliseconds of clock disparity assumed between honest nodes.
|
TtfbTimeout time.Duration `yaml:"TTFB_TIMEOUT"` // TtfbTimeout is the maximum time to wait for first byte of request response (time-to-first-byte).
|
||||||
MessageDomainInvalidSnappy [4]byte `yaml:"MESSAGE_DOMAIN_INVALID_SNAPPY"` // MessageDomainInvalidSnappy is the 4-byte domain for gossip message-id isolation of invalid snappy messages.
|
RespTimeout time.Duration `yaml:"RESP_TIMEOUT"` // RespTimeout is the maximum time for complete response transfer.
|
||||||
MessageDomainValidSnappy [4]byte `yaml:"MESSAGE_DOMAIN_VALID_SNAPPY"` // MessageDomainValidSnappy is the 4-byte domain for gossip message-id isolation of valid snappy messages.
|
MaximumGossipClockDisparity time.Duration `yaml:"MAXIMUM_GOSSIP_CLOCK_DISPARITY"` // MaximumGossipClockDisparity is the maximum milliseconds of clock disparity assumed between honest nodes.
|
||||||
|
MessageDomainInvalidSnappy [4]byte `yaml:"MESSAGE_DOMAIN_INVALID_SNAPPY"` // MessageDomainInvalidSnappy is the 4-byte domain for gossip message-id isolation of invalid snappy messages.
|
||||||
|
MessageDomainValidSnappy [4]byte `yaml:"MESSAGE_DOMAIN_VALID_SNAPPY"` // MessageDomainValidSnappy is the 4-byte domain for gossip message-id isolation of valid snappy messages.
|
||||||
|
|
||||||
// DiscoveryV5 Config
|
// DiscoveryV5 Config
|
||||||
ETH2Key string // ETH2Key is the ENR key of the Ethereum consensus object in an enr.
|
ETH2Key string // ETH2Key is the ENR key of the Ethereum consensus object in an enr.
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package params
|
|||||||
const (
|
const (
|
||||||
altairE2EForkEpoch = 6
|
altairE2EForkEpoch = 6
|
||||||
bellatrixE2EForkEpoch = 8
|
bellatrixE2EForkEpoch = 8
|
||||||
|
eip4844E2EForkEpoch = 10
|
||||||
)
|
)
|
||||||
|
|
||||||
// E2ETestConfig retrieves the configurations made specifically for E2E testing.
|
// E2ETestConfig retrieves the configurations made specifically for E2E testing.
|
||||||
@@ -33,6 +34,7 @@ func E2ETestConfig() *BeaconChainConfig {
|
|||||||
// Fork Parameters.
|
// Fork Parameters.
|
||||||
e2eConfig.AltairForkEpoch = altairE2EForkEpoch
|
e2eConfig.AltairForkEpoch = altairE2EForkEpoch
|
||||||
e2eConfig.BellatrixForkEpoch = bellatrixE2EForkEpoch
|
e2eConfig.BellatrixForkEpoch = bellatrixE2EForkEpoch
|
||||||
|
e2eConfig.Eip4844ForkEpoch = eip4844E2EForkEpoch
|
||||||
|
|
||||||
// Terminal Total Difficulty.
|
// Terminal Total Difficulty.
|
||||||
e2eConfig.TerminalTotalDifficulty = "616"
|
e2eConfig.TerminalTotalDifficulty = "616"
|
||||||
@@ -42,7 +44,8 @@ func E2ETestConfig() *BeaconChainConfig {
|
|||||||
e2eConfig.GenesisForkVersion = []byte{0, 0, 0, 253}
|
e2eConfig.GenesisForkVersion = []byte{0, 0, 0, 253}
|
||||||
e2eConfig.AltairForkVersion = []byte{1, 0, 0, 253}
|
e2eConfig.AltairForkVersion = []byte{1, 0, 0, 253}
|
||||||
e2eConfig.BellatrixForkVersion = []byte{2, 0, 0, 253}
|
e2eConfig.BellatrixForkVersion = []byte{2, 0, 0, 253}
|
||||||
e2eConfig.ShardingForkVersion = []byte{3, 0, 0, 253}
|
e2eConfig.Eip4844ForkVersion = []byte{3, 0, 0, 253}
|
||||||
|
e2eConfig.ShardingForkVersion = []byte{4, 0, 0, 253}
|
||||||
|
|
||||||
e2eConfig.InitializeForkSchedule()
|
e2eConfig.InitializeForkSchedule()
|
||||||
return e2eConfig
|
return e2eConfig
|
||||||
@@ -70,6 +73,7 @@ func E2EMainnetTestConfig() *BeaconChainConfig {
|
|||||||
// Altair Fork Parameters.
|
// Altair Fork Parameters.
|
||||||
e2eConfig.AltairForkEpoch = altairE2EForkEpoch
|
e2eConfig.AltairForkEpoch = altairE2EForkEpoch
|
||||||
e2eConfig.BellatrixForkEpoch = bellatrixE2EForkEpoch
|
e2eConfig.BellatrixForkEpoch = bellatrixE2EForkEpoch
|
||||||
|
e2eConfig.Eip4844ForkEpoch = eip4844E2EForkEpoch
|
||||||
|
|
||||||
// Terminal Total Difficulty.
|
// Terminal Total Difficulty.
|
||||||
e2eConfig.TerminalTotalDifficulty = "616"
|
e2eConfig.TerminalTotalDifficulty = "616"
|
||||||
@@ -79,7 +83,8 @@ func E2EMainnetTestConfig() *BeaconChainConfig {
|
|||||||
e2eConfig.GenesisForkVersion = []byte{0, 0, 0, 254}
|
e2eConfig.GenesisForkVersion = []byte{0, 0, 0, 254}
|
||||||
e2eConfig.AltairForkVersion = []byte{1, 0, 0, 254}
|
e2eConfig.AltairForkVersion = []byte{1, 0, 0, 254}
|
||||||
e2eConfig.BellatrixForkVersion = []byte{2, 0, 0, 254}
|
e2eConfig.BellatrixForkVersion = []byte{2, 0, 0, 254}
|
||||||
e2eConfig.ShardingForkVersion = []byte{3, 0, 0, 254}
|
e2eConfig.Eip4844ForkVersion = []byte{3, 0, 0, 254}
|
||||||
|
e2eConfig.ShardingForkVersion = []byte{4, 0, 0, 254}
|
||||||
|
|
||||||
e2eConfig.InitializeForkSchedule()
|
e2eConfig.InitializeForkSchedule()
|
||||||
return e2eConfig
|
return e2eConfig
|
||||||
|
|||||||
38
config/params/testnet_eip4844_config.go
Normal file
38
config/params/testnet_eip4844_config.go
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package params
|
||||||
|
|
||||||
|
// UseEIP4844NetworkConfig uses the EIP4844 beacon chain specific network config.
|
||||||
|
func UseEIP4844NetworkConfig() {
|
||||||
|
cfg := BeaconNetworkConfig().Copy()
|
||||||
|
cfg.MinEpochsForBlobsSidecarsRequest = 1200 // 1 day
|
||||||
|
cfg.ContractDeploymentBlock = 0 // deposit contract is a predeploy
|
||||||
|
cfg.BootstrapNodes = []string{
|
||||||
|
"enr:-JG4QFKX3vHhpsIZ5gwHaStj8k9Z4OudBunL8srykq4yTfL-cwX03zyOCGRXVgefXep3wUb3liC26grESiHK6Wn-7zqGAYI-FNCugmlkgnY0gmlwhCJ7uEyJc2VjcDI1NmsxoQJpeftU6RbmIhcFllICznlAMJXL3EwHEGhn73_Gk0wrCYN0Y3CCMsiDdWRwgi7g",
|
||||||
|
// TODO(EIP-4844): Coinbase boot node
|
||||||
|
}
|
||||||
|
OverrideBeaconNetworkConfig(cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EIP4844Config defines the config for the EIP4844 beacon chain testnet.
|
||||||
|
func EIP4844Config() *BeaconChainConfig {
|
||||||
|
cfg := MainnetConfig().Copy()
|
||||||
|
cfg.MinGenesisTime = 1653318000
|
||||||
|
cfg.MinGenesisActiveValidatorCount = 2
|
||||||
|
cfg.Eth1FollowDistance = 15
|
||||||
|
cfg.ConfigName = EIP4844Name
|
||||||
|
cfg.GenesisForkVersion = []byte{0x00, 0x00, 0x0f, 0xfd}
|
||||||
|
cfg.SecondsPerETH1Block = 14
|
||||||
|
cfg.DepositChainID = 1331
|
||||||
|
cfg.DepositNetworkID = 69
|
||||||
|
cfg.AltairForkEpoch = 1
|
||||||
|
cfg.AltairForkVersion = []byte{0x01, 0x00, 0x0f, 0xfd}
|
||||||
|
cfg.BellatrixForkEpoch = 2
|
||||||
|
cfg.BellatrixForkVersion = []byte{0x02, 0x00, 0x0f, 0xfd}
|
||||||
|
cfg.Eip4844ForkEpoch = 3
|
||||||
|
cfg.SlotsPerEpoch = 8 // 96 secs; reduced from 32 (6.4 mins) for testing
|
||||||
|
cfg.Eip4844ForkVersion = []byte{0x83, 0x00, 0x0f, 0xfd}
|
||||||
|
cfg.TerminalTotalDifficulty = "40"
|
||||||
|
cfg.DepositContractAddress = "0x8A04d14125D0FDCDc742F4A05C051De07232EDa4"
|
||||||
|
cfg.DomainBlobsSidecar = [4]byte{0x0a, 0x00, 0x00, 0x00}
|
||||||
|
cfg.InitializeForkSchedule()
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user