mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-02-01 16:45:04 -05:00
Compare commits
188 Commits
e2e-debugg
...
test100
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1bc9c58da1 | ||
|
|
7fa97b2952 | ||
|
|
4b9e23e55a | ||
|
|
9ee7d6f7da | ||
|
|
41eaa96396 | ||
|
|
d24ee89e57 | ||
|
|
788af59823 | ||
|
|
38cf0e9e94 | ||
|
|
d4563827d7 | ||
|
|
be14c4c3d1 | ||
|
|
0a0c1b24f1 | ||
|
|
44ef29d33a | ||
|
|
e2461912f0 | ||
|
|
7a619cff36 | ||
|
|
144e28def4 | ||
|
|
9269895f6a | ||
|
|
028b115b8c | ||
|
|
81aff9fc58 | ||
|
|
abb8eb373d | ||
|
|
f72d59b004 | ||
|
|
e25497be3e | ||
|
|
8897a26f84 | ||
|
|
b2a26f2b62 | ||
|
|
09659010f8 | ||
|
|
589042df20 | ||
|
|
312b93e9b1 | ||
|
|
f86f76e447 | ||
|
|
c311e652eb | ||
|
|
6a5d78a331 | ||
|
|
a2fd30497e | ||
|
|
a94561f8dc | ||
|
|
af875b78c9 | ||
|
|
61207bd3ac | ||
|
|
0b6fcd7d17 | ||
|
|
fe2766e716 | ||
|
|
9135d765e1 | ||
|
|
eca87f29d1 | ||
|
|
00821c8f55 | ||
|
|
4b9e92bcd7 | ||
|
|
b01d9005b8 | ||
|
|
8d812d5f0e | ||
|
|
24a3cb2a8b | ||
|
|
66d1d3e248 | ||
|
|
99933678ea | ||
|
|
34f8e1e92b | ||
|
|
a6a41a8755 | ||
|
|
f110b94fac | ||
|
|
33023aa282 | ||
|
|
eeb3cdc99e | ||
|
|
1e7147f060 | ||
|
|
8936beaff3 | ||
|
|
c00283f247 | ||
|
|
a4269cf308 | ||
|
|
91f3c8a4d0 | ||
|
|
30c7ee9c7b | ||
|
|
456d8b9eb9 | ||
|
|
4fe3e6d31a | ||
|
|
01ee1c80b4 | ||
|
|
c14fe47a81 | ||
|
|
b9deabbf0a | ||
|
|
5d66a98e78 | ||
|
|
2d46d6ffae | ||
|
|
57107e50a7 | ||
|
|
47271254f6 | ||
|
|
f304028874 | ||
|
|
8abc5e159a | ||
|
|
b1ac53c4dd | ||
|
|
27ab68c856 | ||
|
|
ddf5a3953b | ||
|
|
92d2fc101d | ||
|
|
8996000d2b | ||
|
|
a2fcba2349 | ||
|
|
abe8638991 | ||
|
|
0b5064b474 | ||
|
|
da9d4cf5b9 | ||
|
|
a62cca15dd | ||
|
|
ac04246a2a | ||
|
|
0923145bd7 | ||
|
|
a216cb4105 | ||
|
|
01705d1f3d | ||
|
|
14f93b4e9d | ||
|
|
ad11036c36 | ||
|
|
632a06076b | ||
|
|
242c2b0268 | ||
|
|
19662da905 | ||
|
|
7faee5af35 | ||
|
|
805ee1bf31 | ||
|
|
bea46fdfa1 | ||
|
|
f6b1fb1c88 | ||
|
|
6fb349ea76 | ||
|
|
e5a425f5c7 | ||
|
|
f157d37e4c | ||
|
|
5f08559bef | ||
|
|
a082d2aecd | ||
|
|
bcfaff8504 | ||
|
|
d8e09c346f | ||
|
|
876519731b | ||
|
|
de05b83aca | ||
|
|
56c73e7193 | ||
|
|
859ac008a8 | ||
|
|
f882bd27c8 | ||
|
|
361e5759c1 | ||
|
|
34ef0da896 | ||
|
|
726e8b962f | ||
|
|
453ea01deb | ||
|
|
6537f8011e | ||
|
|
5f17317c1c | ||
|
|
3432ffa4a3 | ||
|
|
9dac67635b | ||
|
|
9be69fbd07 | ||
|
|
e21261e893 | ||
|
|
da53a8fc48 | ||
|
|
a14634e656 | ||
|
|
43761a8066 | ||
|
|
01dbc337c0 | ||
|
|
92f9b55fcb | ||
|
|
f65f12f58b | ||
|
|
f2b61a3dcf | ||
|
|
77a6d29a2e | ||
|
|
31d16da3a0 | ||
|
|
19221b77bd | ||
|
|
83df293647 | ||
|
|
c20c09ce36 | ||
|
|
2191faaa3f | ||
|
|
2de1e6f3e4 | ||
|
|
db44df3964 | ||
|
|
f92eb44c89 | ||
|
|
a26980b64d | ||
|
|
f58cf7e626 | ||
|
|
68da7dabe2 | ||
|
|
d1e43a2c02 | ||
|
|
3652bec2f8 | ||
|
|
81b7a1725f | ||
|
|
0c917079c4 | ||
|
|
a732fe7021 | ||
|
|
d75a7aae6a | ||
|
|
e788a46e82 | ||
|
|
199543125a | ||
|
|
ca63efa770 | ||
|
|
345e6edd9c | ||
|
|
6403064126 | ||
|
|
0517d76631 | ||
|
|
000d480f77 | ||
|
|
b40a8ed37e | ||
|
|
d21c2bd63e | ||
|
|
7a256e93f7 | ||
|
|
07fe76c2da | ||
|
|
54affa897f | ||
|
|
ac4c5fae3c | ||
|
|
2845d87077 | ||
|
|
dc2c90b8ed | ||
|
|
b469157e1f | ||
|
|
2697794e58 | ||
|
|
48cf24edb4 | ||
|
|
78f90db90b | ||
|
|
d0a3b9bc1d | ||
|
|
bfdb6dab86 | ||
|
|
7dd2fd52af | ||
|
|
b6bad9331b | ||
|
|
6e2122085d | ||
|
|
7a847292aa | ||
|
|
81f4db0afa | ||
|
|
a7dc2e6c8b | ||
|
|
0a010b5088 | ||
|
|
1e335e2cf2 | ||
|
|
42f4c0f14e | ||
|
|
d3c12abe25 | ||
|
|
b0ba05b4f4 | ||
|
|
e206506489 | ||
|
|
013cb28663 | ||
|
|
496914cb39 | ||
|
|
c032e78888 | ||
|
|
5e4deff6fd | ||
|
|
6daa91c465 | ||
|
|
32ce6423eb | ||
|
|
b0ea450df5 | ||
|
|
8bd10df423 | ||
|
|
dcbb543be2 | ||
|
|
be0580e1a9 | ||
|
|
1355178115 | ||
|
|
b78c3485b9 | ||
|
|
f503efc6ed | ||
|
|
1bfbd3980e | ||
|
|
3e722ea1bc | ||
|
|
d844026433 | ||
|
|
9ffc19d5ef | ||
|
|
3e23f6e879 | ||
|
|
c688c84393 |
@@ -16,7 +16,6 @@ go_library(
|
|||||||
"//api/server/structs:go_default_library",
|
"//api/server/structs:go_default_library",
|
||||||
"//consensus-types/primitives:go_default_library",
|
"//consensus-types/primitives:go_default_library",
|
||||||
"//encoding/bytesutil:go_default_library",
|
"//encoding/bytesutil:go_default_library",
|
||||||
"//network/forks:go_default_library",
|
|
||||||
"//proto/prysm/v1alpha1:go_default_library",
|
"//proto/prysm/v1alpha1:go_default_library",
|
||||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||||
"@com_github_pkg_errors//:go_default_library",
|
"@com_github_pkg_errors//:go_default_library",
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/OffchainLabs/prysm/v6/api/client"
|
"github.com/OffchainLabs/prysm/v6/api/client"
|
||||||
@@ -17,7 +16,6 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/api/server/structs"
|
"github.com/OffchainLabs/prysm/v6/api/server/structs"
|
||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
||||||
"github.com/OffchainLabs/prysm/v6/network/forks"
|
|
||||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@@ -137,24 +135,6 @@ func (c *Client) GetFork(ctx context.Context, stateId StateOrBlockId) (*ethpb.Fo
|
|||||||
return fr.ToConsensus()
|
return fr.ToConsensus()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetForkSchedule retrieve all forks, past present and future, of which this node is aware.
|
|
||||||
func (c *Client) GetForkSchedule(ctx context.Context) (forks.OrderedSchedule, error) {
|
|
||||||
body, err := c.Get(ctx, getForkSchedulePath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "error requesting fork schedule")
|
|
||||||
}
|
|
||||||
fsr := &forkScheduleResponse{}
|
|
||||||
err = json.Unmarshal(body, fsr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ofs, err := fsr.OrderedForkSchedule()
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, fmt.Sprintf("problem unmarshaling %s response", getForkSchedulePath))
|
|
||||||
}
|
|
||||||
return ofs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetConfigSpec retrieve the current configs of the network used by the beacon node.
|
// GetConfigSpec retrieve the current configs of the network used by the beacon node.
|
||||||
func (c *Client) GetConfigSpec(ctx context.Context) (*structs.GetSpecResponse, error) {
|
func (c *Client) GetConfigSpec(ctx context.Context) (*structs.GetSpecResponse, error) {
|
||||||
body, err := c.Get(ctx, getConfigSpecPath)
|
body, err := c.Get(ctx, getConfigSpecPath)
|
||||||
@@ -334,31 +314,3 @@ func (c *Client) GetBLStoExecutionChanges(ctx context.Context) (*structs.BLSToEx
|
|||||||
}
|
}
|
||||||
return poolResponse, nil
|
return poolResponse, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type forkScheduleResponse struct {
|
|
||||||
Data []structs.Fork
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fsr *forkScheduleResponse) OrderedForkSchedule() (forks.OrderedSchedule, error) {
|
|
||||||
ofs := make(forks.OrderedSchedule, 0)
|
|
||||||
for _, d := range fsr.Data {
|
|
||||||
epoch, err := strconv.ParseUint(d.Epoch, 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "error parsing epoch %s", d.Epoch)
|
|
||||||
}
|
|
||||||
vSlice, err := hexutil.Decode(d.CurrentVersion)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(vSlice) != 4 {
|
|
||||||
return nil, fmt.Errorf("got %d byte version, expected 4 bytes. version hex=%s", len(vSlice), d.CurrentVersion)
|
|
||||||
}
|
|
||||||
version := bytesutil.ToBytes4(vSlice)
|
|
||||||
ofs = append(ofs, forks.ForkScheduleEntry{
|
|
||||||
Version: version,
|
|
||||||
Epoch: primitives.Epoch(epoch),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
sort.Sort(ofs)
|
|
||||||
return ofs, nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -12,16 +12,12 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/helpers"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/helpers"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/time"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/time"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/transition"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/transition"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/execution"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
|
||||||
"github.com/OffchainLabs/prysm/v6/config/features"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
consensusblocks "github.com/OffchainLabs/prysm/v6/consensus-types/blocks"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/interfaces"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/interfaces"
|
||||||
payloadattribute "github.com/OffchainLabs/prysm/v6/consensus-types/payload-attribute"
|
payloadattribute "github.com/OffchainLabs/prysm/v6/consensus-types/payload-attribute"
|
||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
||||||
"github.com/OffchainLabs/prysm/v6/monitoring/tracing/trace"
|
|
||||||
enginev1 "github.com/OffchainLabs/prysm/v6/proto/engine/v1"
|
enginev1 "github.com/OffchainLabs/prysm/v6/proto/engine/v1"
|
||||||
"github.com/OffchainLabs/prysm/v6/runtime/version"
|
"github.com/OffchainLabs/prysm/v6/runtime/version"
|
||||||
"github.com/OffchainLabs/prysm/v6/time/slots"
|
"github.com/OffchainLabs/prysm/v6/time/slots"
|
||||||
@@ -36,152 +32,7 @@ var defaultLatestValidHash = bytesutil.PadTo([]byte{0xff}, 32)
|
|||||||
// 1. Re-organizes the execution payload chain and corresponding state to make head_block_hash the head.
|
// 1. Re-organizes the execution payload chain and corresponding state to make head_block_hash the head.
|
||||||
// 2. Applies finality to the execution state: it irreversibly persists the chain of all execution payloads and corresponding state, up to and including finalized_block_hash.
|
// 2. Applies finality to the execution state: it irreversibly persists the chain of all execution payloads and corresponding state, up to and including finalized_block_hash.
|
||||||
func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *fcuConfig) (*enginev1.PayloadIDBytes, error) {
|
func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *fcuConfig) (*enginev1.PayloadIDBytes, error) {
|
||||||
ctx, span := trace.StartSpan(ctx, "blockChain.notifyForkchoiceUpdate")
|
return nil, nil
|
||||||
defer span.End()
|
|
||||||
|
|
||||||
if arg.headBlock == nil || arg.headBlock.IsNil() {
|
|
||||||
log.Error("Head block is nil")
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
headBlk := arg.headBlock.Block()
|
|
||||||
if headBlk == nil || headBlk.IsNil() || headBlk.Body().IsNil() {
|
|
||||||
log.Error("Head block is nil")
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
// Must not call fork choice updated until the transition conditions are met on the Pow network.
|
|
||||||
isExecutionBlk, err := blocks.IsExecutionBlock(headBlk.Body())
|
|
||||||
if err != nil {
|
|
||||||
log.WithError(err).Error("Could not determine if head block is execution block")
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
if !isExecutionBlk {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
headPayload, err := headBlk.Body().Execution()
|
|
||||||
if err != nil {
|
|
||||||
log.WithError(err).Error("Could not get execution payload for head block")
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
finalizedHash := s.cfg.ForkChoiceStore.FinalizedPayloadBlockHash()
|
|
||||||
justifiedHash := s.cfg.ForkChoiceStore.UnrealizedJustifiedPayloadBlockHash()
|
|
||||||
fcs := &enginev1.ForkchoiceState{
|
|
||||||
HeadBlockHash: headPayload.BlockHash(),
|
|
||||||
SafeBlockHash: justifiedHash[:],
|
|
||||||
FinalizedBlockHash: finalizedHash[:],
|
|
||||||
}
|
|
||||||
if len(fcs.HeadBlockHash) != 32 || [32]byte(fcs.HeadBlockHash) == [32]byte{} {
|
|
||||||
// check if we are sending FCU at genesis
|
|
||||||
hash, err := s.hashForGenesisBlock(ctx, arg.headRoot)
|
|
||||||
if errors.Is(err, errNotGenesisRoot) {
|
|
||||||
log.Error("Sending nil head block hash to execution engine")
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "could not get head block hash")
|
|
||||||
}
|
|
||||||
fcs.HeadBlockHash = hash
|
|
||||||
}
|
|
||||||
if arg.attributes == nil {
|
|
||||||
arg.attributes = payloadattribute.EmptyWithVersion(headBlk.Version())
|
|
||||||
}
|
|
||||||
payloadID, lastValidHash, err := s.cfg.ExecutionEngineCaller.ForkchoiceUpdated(ctx, fcs, arg.attributes)
|
|
||||||
if err != nil {
|
|
||||||
switch {
|
|
||||||
case errors.Is(err, execution.ErrAcceptedSyncingPayloadStatus):
|
|
||||||
forkchoiceUpdatedOptimisticNodeCount.Inc()
|
|
||||||
log.WithFields(logrus.Fields{
|
|
||||||
"headSlot": headBlk.Slot(),
|
|
||||||
"headPayloadBlockHash": fmt.Sprintf("%#x", bytesutil.Trunc(headPayload.BlockHash())),
|
|
||||||
"finalizedPayloadBlockHash": fmt.Sprintf("%#x", bytesutil.Trunc(finalizedHash[:])),
|
|
||||||
}).Info("Called fork choice updated with optimistic block")
|
|
||||||
return payloadID, nil
|
|
||||||
case errors.Is(err, execution.ErrInvalidPayloadStatus):
|
|
||||||
forkchoiceUpdatedInvalidNodeCount.Inc()
|
|
||||||
headRoot := arg.headRoot
|
|
||||||
if len(lastValidHash) == 0 {
|
|
||||||
lastValidHash = defaultLatestValidHash
|
|
||||||
}
|
|
||||||
invalidRoots, err := s.cfg.ForkChoiceStore.SetOptimisticToInvalid(ctx, headRoot, headBlk.ParentRoot(), bytesutil.ToBytes32(lastValidHash))
|
|
||||||
if err != nil {
|
|
||||||
log.WithError(err).Error("Could not set head root to invalid")
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
if err := s.removeInvalidBlockAndState(ctx, invalidRoots); err != nil {
|
|
||||||
log.WithError(err).Error("Could not remove invalid block and state")
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
r, err := s.cfg.ForkChoiceStore.Head(ctx)
|
|
||||||
if err != nil {
|
|
||||||
log.WithFields(logrus.Fields{
|
|
||||||
"slot": headBlk.Slot(),
|
|
||||||
"blockRoot": fmt.Sprintf("%#x", bytesutil.Trunc(headRoot[:])),
|
|
||||||
"invalidChildrenCount": len(invalidRoots),
|
|
||||||
}).Warn("Pruned invalid blocks, could not update head root")
|
|
||||||
return nil, invalidBlock{error: ErrInvalidPayload, root: arg.headRoot, invalidAncestorRoots: invalidRoots}
|
|
||||||
}
|
|
||||||
b, err := s.getBlock(ctx, r)
|
|
||||||
if err != nil {
|
|
||||||
log.WithError(err).Error("Could not get head block")
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
st, err := s.cfg.StateGen.StateByRoot(ctx, r)
|
|
||||||
if err != nil {
|
|
||||||
log.WithError(err).Error("Could not get head state")
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
pid, err := s.notifyForkchoiceUpdate(ctx, &fcuConfig{
|
|
||||||
headState: st,
|
|
||||||
headRoot: r,
|
|
||||||
headBlock: b,
|
|
||||||
attributes: arg.attributes,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err // Returning err because it's recursive here.
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := s.saveHead(ctx, r, b, st); err != nil {
|
|
||||||
log.WithError(err).Error("could not save head after pruning invalid blocks")
|
|
||||||
}
|
|
||||||
|
|
||||||
log.WithFields(logrus.Fields{
|
|
||||||
"slot": headBlk.Slot(),
|
|
||||||
"blockRoot": fmt.Sprintf("%#x", bytesutil.Trunc(headRoot[:])),
|
|
||||||
"invalidChildrenCount": len(invalidRoots),
|
|
||||||
"newHeadRoot": fmt.Sprintf("%#x", bytesutil.Trunc(r[:])),
|
|
||||||
}).Warn("Pruned invalid blocks")
|
|
||||||
return pid, invalidBlock{error: ErrInvalidPayload, root: arg.headRoot, invalidAncestorRoots: invalidRoots}
|
|
||||||
default:
|
|
||||||
log.WithError(err).Error(ErrUndefinedExecutionEngineError)
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
forkchoiceUpdatedValidNodeCount.Inc()
|
|
||||||
if err := s.cfg.ForkChoiceStore.SetOptimisticToValid(ctx, arg.headRoot); err != nil {
|
|
||||||
log.WithError(err).Error("Could not set head root to valid")
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
// If the forkchoice update call has an attribute, update the payload ID cache.
|
|
||||||
hasAttr := arg.attributes != nil && !arg.attributes.IsEmpty()
|
|
||||||
nextSlot := s.CurrentSlot() + 1
|
|
||||||
if hasAttr && payloadID != nil {
|
|
||||||
var pId [8]byte
|
|
||||||
copy(pId[:], payloadID[:])
|
|
||||||
log.WithFields(logrus.Fields{
|
|
||||||
"blockRoot": fmt.Sprintf("%#x", bytesutil.Trunc(arg.headRoot[:])),
|
|
||||||
"headSlot": headBlk.Slot(),
|
|
||||||
"nextSlot": nextSlot,
|
|
||||||
"payloadID": fmt.Sprintf("%#x", bytesutil.Trunc(payloadID[:])),
|
|
||||||
}).Info("Forkchoice updated with payload attributes for proposal")
|
|
||||||
s.cfg.PayloadIDCache.Set(nextSlot, arg.headRoot, pId)
|
|
||||||
} else if hasAttr && payloadID == nil && !features.Get().PrepareAllPayloads {
|
|
||||||
log.WithFields(logrus.Fields{
|
|
||||||
"blockHash": fmt.Sprintf("%#x", headPayload.BlockHash()),
|
|
||||||
"slot": headBlk.Slot(),
|
|
||||||
"nextSlot": nextSlot,
|
|
||||||
}).Error("Received nil payload ID on VALID engine response")
|
|
||||||
}
|
|
||||||
return payloadID, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) firePayloadAttributesEvent(f event.SubscriberSender, block interfaces.ReadOnlySignedBeaconBlock, root [32]byte, nextSlot primitives.Slot) {
|
func (s *Service) firePayloadAttributesEvent(f event.SubscriberSender, block interfaces.ReadOnlySignedBeaconBlock, root [32]byte, nextSlot primitives.Slot) {
|
||||||
@@ -219,76 +70,7 @@ func (s *Service) getPayloadHash(ctx context.Context, root []byte) ([32]byte, er
|
|||||||
// It returns true if the EL has returned VALID for the block
|
// It returns true if the EL has returned VALID for the block
|
||||||
func (s *Service) notifyNewPayload(ctx context.Context, preStateVersion int,
|
func (s *Service) notifyNewPayload(ctx context.Context, preStateVersion int,
|
||||||
preStateHeader interfaces.ExecutionData, blk interfaces.ReadOnlySignedBeaconBlock) (bool, error) {
|
preStateHeader interfaces.ExecutionData, blk interfaces.ReadOnlySignedBeaconBlock) (bool, error) {
|
||||||
ctx, span := trace.StartSpan(ctx, "blockChain.notifyNewPayload")
|
return true, nil
|
||||||
defer span.End()
|
|
||||||
|
|
||||||
// Execution payload is only supported in Bellatrix and beyond. Pre
|
|
||||||
// merge blocks are never optimistic
|
|
||||||
if blk == nil {
|
|
||||||
return false, errors.New("signed beacon block can't be nil")
|
|
||||||
}
|
|
||||||
if preStateVersion < version.Bellatrix {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
if err := consensusblocks.BeaconBlockIsNil(blk); err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
body := blk.Block().Body()
|
|
||||||
enabled, err := blocks.IsExecutionEnabledUsingHeader(preStateHeader, body)
|
|
||||||
if err != nil {
|
|
||||||
return false, errors.Wrap(invalidBlock{error: err}, "could not determine if execution is enabled")
|
|
||||||
}
|
|
||||||
if !enabled {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
payload, err := body.Execution()
|
|
||||||
if err != nil {
|
|
||||||
return false, errors.Wrap(invalidBlock{error: err}, "could not get execution payload")
|
|
||||||
}
|
|
||||||
|
|
||||||
var lastValidHash []byte
|
|
||||||
var parentRoot *common.Hash
|
|
||||||
var versionedHashes []common.Hash
|
|
||||||
var requests *enginev1.ExecutionRequests
|
|
||||||
if blk.Version() >= version.Deneb {
|
|
||||||
versionedHashes, err = kzgCommitmentsToVersionedHashes(blk.Block().Body())
|
|
||||||
if err != nil {
|
|
||||||
return false, errors.Wrap(err, "could not get versioned hashes to feed the engine")
|
|
||||||
}
|
|
||||||
prh := common.Hash(blk.Block().ParentRoot())
|
|
||||||
parentRoot = &prh
|
|
||||||
}
|
|
||||||
if blk.Version() >= version.Electra {
|
|
||||||
requests, err = blk.Block().Body().ExecutionRequests()
|
|
||||||
if err != nil {
|
|
||||||
return false, errors.Wrap(err, "could not get execution requests")
|
|
||||||
}
|
|
||||||
if requests == nil {
|
|
||||||
return false, errors.New("nil execution requests")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lastValidHash, err = s.cfg.ExecutionEngineCaller.NewPayload(ctx, payload, versionedHashes, parentRoot, requests)
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case err == nil:
|
|
||||||
newPayloadValidNodeCount.Inc()
|
|
||||||
return true, nil
|
|
||||||
case errors.Is(err, execution.ErrAcceptedSyncingPayloadStatus):
|
|
||||||
newPayloadOptimisticNodeCount.Inc()
|
|
||||||
log.WithFields(logrus.Fields{
|
|
||||||
"slot": blk.Block().Slot(),
|
|
||||||
"payloadBlockHash": fmt.Sprintf("%#x", bytesutil.Trunc(payload.BlockHash())),
|
|
||||||
}).Info("Called new payload with optimistic block")
|
|
||||||
return false, nil
|
|
||||||
case errors.Is(err, execution.ErrInvalidPayloadStatus):
|
|
||||||
lvh := bytesutil.ToBytes32(lastValidHash)
|
|
||||||
return false, invalidBlock{
|
|
||||||
error: ErrInvalidPayload,
|
|
||||||
lastValidHash: lvh,
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return false, errors.WithMessage(ErrUndefinedExecutionEngineError, err.Error())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// reportInvalidBlock deals with the event that an invalid block was detected by the execution layer
|
// reportInvalidBlock deals with the event that an invalid block was detected by the execution layer
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/startup"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/startup"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/state/stategen"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/state/stategen"
|
||||||
|
fieldparams "github.com/OffchainLabs/prysm/v6/config/fieldparams"
|
||||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/blocks"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/blocks"
|
||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/interfaces"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/interfaces"
|
||||||
@@ -110,22 +111,26 @@ var ErrMissingClockSetter = errors.New("blockchain Service initialized without a
|
|||||||
type blobNotifierMap struct {
|
type blobNotifierMap struct {
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
notifiers map[[32]byte]chan uint64
|
notifiers map[[32]byte]chan uint64
|
||||||
seenIndex map[[32]byte][]bool
|
// TODO: Separate blobs from data columns
|
||||||
|
// seenIndex map[[32]byte][]bool
|
||||||
|
seenIndex map[[32]byte][fieldparams.NumberOfColumns]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// notifyIndex notifies a blob by its index for a given root.
|
// notifyIndex notifies a blob by its index for a given root.
|
||||||
// It uses internal maps to keep track of seen indices and notifier channels.
|
// It uses internal maps to keep track of seen indices and notifier channels.
|
||||||
func (bn *blobNotifierMap) notifyIndex(root [32]byte, idx uint64, slot primitives.Slot) {
|
func (bn *blobNotifierMap) notifyIndex(root [32]byte, idx uint64, slot primitives.Slot) {
|
||||||
maxBlobsPerBlock := params.BeaconConfig().MaxBlobsPerBlock(slot)
|
// TODO: Separate blobs from data columns
|
||||||
if idx >= uint64(maxBlobsPerBlock) {
|
// maxBlobsPerBlock := params.BeaconConfig().MaxBlobsPerBlock(slot)
|
||||||
return
|
// if idx >= uint64(maxBlobsPerBlock) {
|
||||||
}
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
bn.Lock()
|
bn.Lock()
|
||||||
seen := bn.seenIndex[root]
|
seen := bn.seenIndex[root]
|
||||||
if seen == nil {
|
// TODO: Separate blobs from data columns
|
||||||
seen = make([]bool, maxBlobsPerBlock)
|
// if seen == nil {
|
||||||
}
|
// seen = make([]bool, maxBlobsPerBlock)
|
||||||
|
// }
|
||||||
if seen[idx] {
|
if seen[idx] {
|
||||||
bn.Unlock()
|
bn.Unlock()
|
||||||
return
|
return
|
||||||
@@ -136,7 +141,9 @@ func (bn *blobNotifierMap) notifyIndex(root [32]byte, idx uint64, slot primitive
|
|||||||
// Retrieve or create the notifier channel for the given root.
|
// Retrieve or create the notifier channel for the given root.
|
||||||
c, ok := bn.notifiers[root]
|
c, ok := bn.notifiers[root]
|
||||||
if !ok {
|
if !ok {
|
||||||
c = make(chan uint64, maxBlobsPerBlock)
|
// TODO: Separate blobs from data columns
|
||||||
|
// c = make(chan uint64, maxBlobsPerBlock)
|
||||||
|
c = make(chan uint64, fieldparams.NumberOfColumns)
|
||||||
bn.notifiers[root] = c
|
bn.notifiers[root] = c
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,12 +153,15 @@ func (bn *blobNotifierMap) notifyIndex(root [32]byte, idx uint64, slot primitive
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (bn *blobNotifierMap) forRoot(root [32]byte, slot primitives.Slot) chan uint64 {
|
func (bn *blobNotifierMap) forRoot(root [32]byte, slot primitives.Slot) chan uint64 {
|
||||||
maxBlobsPerBlock := params.BeaconConfig().MaxBlobsPerBlock(slot)
|
// TODO: Separate blobs from data columns
|
||||||
|
// maxBlobsPerBlock := params.BeaconConfig().MaxBlobsPerBlock(slot)
|
||||||
bn.Lock()
|
bn.Lock()
|
||||||
defer bn.Unlock()
|
defer bn.Unlock()
|
||||||
c, ok := bn.notifiers[root]
|
c, ok := bn.notifiers[root]
|
||||||
if !ok {
|
if !ok {
|
||||||
c = make(chan uint64, maxBlobsPerBlock)
|
// TODO: Separate blobs from data columns
|
||||||
|
// c = make(chan uint64, maxBlobsPerBlock)
|
||||||
|
c = make(chan uint64, fieldparams.NumberOfColumns)
|
||||||
bn.notifiers[root] = c
|
bn.notifiers[root] = c
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
@@ -177,7 +187,9 @@ func NewService(ctx context.Context, opts ...Option) (*Service, error) {
|
|||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
bn := &blobNotifierMap{
|
bn := &blobNotifierMap{
|
||||||
notifiers: make(map[[32]byte]chan uint64),
|
notifiers: make(map[[32]byte]chan uint64),
|
||||||
seenIndex: make(map[[32]byte][]bool),
|
// TODO: Separate blobs from data columns
|
||||||
|
// seenIndex: make(map[[32]byte][]bool),
|
||||||
|
seenIndex: make(map[[32]byte][fieldparams.NumberOfColumns]bool),
|
||||||
}
|
}
|
||||||
srv := &Service{
|
srv := &Service{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
|
|||||||
@@ -587,7 +587,9 @@ func (s *MockClockSetter) SetClock(g *startup.Clock) error {
|
|||||||
func TestNotifyIndex(t *testing.T) {
|
func TestNotifyIndex(t *testing.T) {
|
||||||
// Initialize a blobNotifierMap
|
// Initialize a blobNotifierMap
|
||||||
bn := &blobNotifierMap{
|
bn := &blobNotifierMap{
|
||||||
seenIndex: make(map[[32]byte][]bool),
|
// TODO: Separate blobs from data columns
|
||||||
|
// seenIndex: make(map[[32]byte][]bool),
|
||||||
|
seenIndex: make(map[[32]byte][fieldparams.NumberOfColumns]bool),
|
||||||
notifiers: make(map[[32]byte]chan uint64),
|
notifiers: make(map[[32]byte]chan uint64),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ go_library(
|
|||||||
"//encoding/ssz:go_default_library",
|
"//encoding/ssz:go_default_library",
|
||||||
"//math:go_default_library",
|
"//math:go_default_library",
|
||||||
"//monitoring/tracing/trace:go_default_library",
|
"//monitoring/tracing/trace:go_default_library",
|
||||||
"//network/forks:go_default_library",
|
|
||||||
"//proto/engine/v1: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",
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/interfaces"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/interfaces"
|
||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
||||||
"github.com/OffchainLabs/prysm/v6/crypto/bls"
|
"github.com/OffchainLabs/prysm/v6/crypto/bls"
|
||||||
"github.com/OffchainLabs/prysm/v6/network/forks"
|
|
||||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||||
"github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1/attestation"
|
"github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1/attestation"
|
||||||
"github.com/OffchainLabs/prysm/v6/time/slots"
|
"github.com/OffchainLabs/prysm/v6/time/slots"
|
||||||
@@ -96,12 +95,30 @@ func VerifyBlockHeaderSignature(beaconState state.BeaconState, header *ethpb.Sig
|
|||||||
return signing.VerifyBlockHeaderSigningRoot(header.Header, proposerPubKey, header.Signature, domain)
|
return signing.VerifyBlockHeaderSigningRoot(header.Header, proposerPubKey, header.Signature, domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func VerifyBlockHeaderSignatureUsingCurrentFork(beaconState state.BeaconState, header *ethpb.SignedBeaconBlockHeader) error {
|
||||||
|
currentEpoch := slots.ToEpoch(header.Header.Slot)
|
||||||
|
fork, err := params.Fork(currentEpoch)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
domain, err := signing.Domain(fork, currentEpoch, params.BeaconConfig().DomainBeaconProposer, beaconState.GenesisValidatorsRoot())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
proposer, err := beaconState.ValidatorAtIndex(header.Header.ProposerIndex)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
proposerPubKey := proposer.PublicKey
|
||||||
|
return signing.VerifyBlockHeaderSigningRoot(header.Header, proposerPubKey, header.Signature, domain)
|
||||||
|
}
|
||||||
|
|
||||||
// VerifyBlockSignatureUsingCurrentFork verifies the proposer signature of a beacon block. This differs
|
// VerifyBlockSignatureUsingCurrentFork verifies the proposer signature of a beacon block. This differs
|
||||||
// from the above method by not using fork data from the state and instead retrieving it
|
// from the above method by not using fork data from the state and instead retrieving it
|
||||||
// via the respective epoch.
|
// via the respective epoch.
|
||||||
func VerifyBlockSignatureUsingCurrentFork(beaconState state.ReadOnlyBeaconState, blk interfaces.ReadOnlySignedBeaconBlock, blkRoot [32]byte) error {
|
func VerifyBlockSignatureUsingCurrentFork(beaconState state.ReadOnlyBeaconState, blk interfaces.ReadOnlySignedBeaconBlock, blkRoot [32]byte) error {
|
||||||
currentEpoch := slots.ToEpoch(blk.Block().Slot())
|
currentEpoch := slots.ToEpoch(blk.Block().Slot())
|
||||||
fork, err := forks.Fork(currentEpoch)
|
fork, err := params.Fork(currentEpoch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,11 +38,14 @@ const (
|
|||||||
// SingleAttReceived is sent after a single attestation object is received from gossip or rpc
|
// SingleAttReceived is sent after a single attestation object is received from gossip or rpc
|
||||||
SingleAttReceived = 9
|
SingleAttReceived = 9
|
||||||
|
|
||||||
|
// DataColumnSidecarReceived is sent after a data column sidecar is received from gossip or rpc.
|
||||||
|
DataColumnSidecarReceived = 10
|
||||||
|
|
||||||
// BlockGossipReceived is sent after a block has been received from gossip or API that passes validation rules.
|
// BlockGossipReceived is sent after a block has been received from gossip or API that passes validation rules.
|
||||||
BlockGossipReceived = 10
|
BlockGossipReceived = 11
|
||||||
|
|
||||||
// DataColumnReceived is sent after a data column has been seen after gossip validation rules.
|
// DataColumnReceived is sent after a data column has been seen after gossip validation rules.
|
||||||
DataColumnReceived = 11
|
DataColumnReceived = 12
|
||||||
)
|
)
|
||||||
|
|
||||||
// UnAggregatedAttReceivedData is the data sent with UnaggregatedAttReceived events.
|
// UnAggregatedAttReceivedData is the data sent with UnaggregatedAttReceived events.
|
||||||
@@ -94,6 +97,11 @@ type SingleAttReceivedData struct {
|
|||||||
Attestation ethpb.Att
|
Attestation ethpb.Att
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DataColumnSidecarReceivedData is the data sent with DataColumnSidecarReceived events.
|
||||||
|
type DataColumnSidecarReceivedData struct {
|
||||||
|
DataColumn *blocks.VerifiedRODataColumn
|
||||||
|
}
|
||||||
|
|
||||||
// BlockGossipReceivedData is the data sent with BlockGossipReceived events.
|
// BlockGossipReceivedData is the data sent with BlockGossipReceived events.
|
||||||
type BlockGossipReceivedData struct {
|
type BlockGossipReceivedData struct {
|
||||||
// SignedBlock is the block that was received.
|
// SignedBlock is the block that was received.
|
||||||
|
|||||||
@@ -669,11 +669,11 @@ func ComputeCommittee(
|
|||||||
// InitializeProposerLookahead computes the list of the proposer indices for the next MIN_SEED_LOOKAHEAD + 1 epochs.
|
// InitializeProposerLookahead computes the list of the proposer indices for the next MIN_SEED_LOOKAHEAD + 1 epochs.
|
||||||
func InitializeProposerLookahead(ctx context.Context, state state.ReadOnlyBeaconState, epoch primitives.Epoch) ([]uint64, error) {
|
func InitializeProposerLookahead(ctx context.Context, state state.ReadOnlyBeaconState, epoch primitives.Epoch) ([]uint64, error) {
|
||||||
lookAhead := make([]uint64, 0, uint64(params.BeaconConfig().MinSeedLookahead+1)*uint64(params.BeaconConfig().SlotsPerEpoch))
|
lookAhead := make([]uint64, 0, uint64(params.BeaconConfig().MinSeedLookahead+1)*uint64(params.BeaconConfig().SlotsPerEpoch))
|
||||||
indices, err := ActiveValidatorIndices(ctx, state, epoch)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "could not get active indices")
|
|
||||||
}
|
|
||||||
for i := range params.BeaconConfig().MinSeedLookahead + 1 {
|
for i := range params.BeaconConfig().MinSeedLookahead + 1 {
|
||||||
|
indices, err := ActiveValidatorIndices(ctx, state, epoch+i)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not get active indices")
|
||||||
|
}
|
||||||
proposerIndices, err := PrecomputeProposerIndices(state, indices, epoch+i)
|
proposerIndices, err := PrecomputeProposerIndices(state, indices, epoch+i)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "could not compute proposer indices")
|
return nil, errors.Wrap(err, "could not compute proposer indices")
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ func TestIsCurrentEpochSyncCommittee_UsingCommittee(t *testing.T) {
|
|||||||
|
|
||||||
func TestIsCurrentEpochSyncCommittee_DoesNotExist(t *testing.T) {
|
func TestIsCurrentEpochSyncCommittee_DoesNotExist(t *testing.T) {
|
||||||
helpers.ClearCache()
|
helpers.ClearCache()
|
||||||
|
params.SetupTestConfigCleanup(t)
|
||||||
|
|
||||||
validators := make([]*ethpb.Validator, params.BeaconConfig().SyncCommitteeSize)
|
validators := make([]*ethpb.Validator, params.BeaconConfig().SyncCommitteeSize)
|
||||||
syncCommittee := ðpb.SyncCommittee{
|
syncCommittee := ðpb.SyncCommittee{
|
||||||
@@ -264,6 +265,7 @@ func TestCurrentEpochSyncSubcommitteeIndices_UsingCommittee(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCurrentEpochSyncSubcommitteeIndices_DoesNotExist(t *testing.T) {
|
func TestCurrentEpochSyncSubcommitteeIndices_DoesNotExist(t *testing.T) {
|
||||||
|
params.SetupTestConfigCleanup(t)
|
||||||
helpers.ClearCache()
|
helpers.ClearCache()
|
||||||
|
|
||||||
validators := make([]*ethpb.Validator, params.BeaconConfig().SyncCommitteeSize)
|
validators := make([]*ethpb.Validator, params.BeaconConfig().SyncCommitteeSize)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ go_library(
|
|||||||
"info.go",
|
"info.go",
|
||||||
"metrics.go",
|
"metrics.go",
|
||||||
"p2p_interface.go",
|
"p2p_interface.go",
|
||||||
|
"peer_sampling.go",
|
||||||
"reconstruction.go",
|
"reconstruction.go",
|
||||||
"validator.go",
|
"validator.go",
|
||||||
"verification.go",
|
"verification.go",
|
||||||
@@ -44,6 +45,7 @@ go_test(
|
|||||||
"das_core_test.go",
|
"das_core_test.go",
|
||||||
"info_test.go",
|
"info_test.go",
|
||||||
"p2p_interface_test.go",
|
"p2p_interface_test.go",
|
||||||
|
"peer_sampling_test.go",
|
||||||
"reconstruction_test.go",
|
"reconstruction_test.go",
|
||||||
"utils_test.go",
|
"utils_test.go",
|
||||||
"validator_test.go",
|
"validator_test.go",
|
||||||
|
|||||||
@@ -10,10 +10,7 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const kzgPosition = 11 // The index of the KZG commitment list in the Body
|
||||||
CustodyGroupCountEnrKey = "cgc"
|
|
||||||
kzgPosition = 11 // The index of the KZG commitment list in the Body
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrIndexTooLarge = errors.New("column index is larger than the specified columns count")
|
ErrIndexTooLarge = errors.New("column index is larger than the specified columns count")
|
||||||
@@ -30,7 +27,7 @@ var (
|
|||||||
// https://github.com/ethereum/consensus-specs/blob/v1.5.0-beta.5/specs/fulu/p2p-interface.md#custody-group-count
|
// https://github.com/ethereum/consensus-specs/blob/v1.5.0-beta.5/specs/fulu/p2p-interface.md#custody-group-count
|
||||||
type Cgc uint64
|
type Cgc uint64
|
||||||
|
|
||||||
func (Cgc) ENRKey() string { return CustodyGroupCountEnrKey }
|
func (Cgc) ENRKey() string { return params.BeaconNetworkConfig().CustodyGroupCountKey }
|
||||||
|
|
||||||
// VerifyDataColumnSidecar verifies if the data column sidecar is valid.
|
// VerifyDataColumnSidecar verifies if the data column sidecar is valid.
|
||||||
// https://github.com/ethereum/consensus-specs/blob/v1.5.0-beta.5/specs/fulu/p2p-interface.md#verify_data_column_sidecar
|
// https://github.com/ethereum/consensus-specs/blob/v1.5.0-beta.5/specs/fulu/p2p-interface.md#verify_data_column_sidecar
|
||||||
|
|||||||
56
beacon-chain/core/peerdas/peer_sampling.go
Normal file
56
beacon-chain/core/peerdas/peer_sampling.go
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
package peerdas
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ExtendedSampleCount computes, for a given number of samples per slot and allowed failures the
|
||||||
|
// number of samples we should actually query from peers.
|
||||||
|
// https://github.com/ethereum/consensus-specs/blob/v1.5.0-beta.5/specs/fulu/peer-sampling.md#get_extended_sample_count
|
||||||
|
func ExtendedSampleCount(samplesPerSlot, allowedFailures uint64) uint64 {
|
||||||
|
// Retrieve the columns count
|
||||||
|
columnsCount := params.BeaconConfig().NumberOfColumns
|
||||||
|
|
||||||
|
// If half of the columns are missing, we are able to reconstruct the data.
|
||||||
|
// If half of the columns + 1 are missing, we are not able to reconstruct the data.
|
||||||
|
// This is the smallest worst case.
|
||||||
|
worstCaseMissing := columnsCount/2 + 1
|
||||||
|
|
||||||
|
// Compute the false positive threshold.
|
||||||
|
falsePositiveThreshold := HypergeomCDF(0, columnsCount, worstCaseMissing, samplesPerSlot)
|
||||||
|
|
||||||
|
var sampleCount uint64
|
||||||
|
|
||||||
|
// Finally, compute the extended sample count.
|
||||||
|
for sampleCount = samplesPerSlot; sampleCount < columnsCount+1; sampleCount++ {
|
||||||
|
if HypergeomCDF(allowedFailures, columnsCount, worstCaseMissing, sampleCount) <= falsePositiveThreshold {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sampleCount
|
||||||
|
}
|
||||||
|
|
||||||
|
// HypergeomCDF computes the hypergeometric cumulative distribution function.
|
||||||
|
// https://en.wikipedia.org/wiki/Hypergeometric_distribution
|
||||||
|
func HypergeomCDF(k, M, n, N uint64) float64 {
|
||||||
|
denominatorInt := new(big.Int).Binomial(int64(M), int64(N)) // lint:ignore uintcast
|
||||||
|
denominator := new(big.Float).SetInt(denominatorInt)
|
||||||
|
|
||||||
|
rBig := big.NewFloat(0)
|
||||||
|
|
||||||
|
for i := uint64(0); i < k+1; i++ {
|
||||||
|
a := new(big.Int).Binomial(int64(n), int64(i)) // lint:ignore uintcast
|
||||||
|
b := new(big.Int).Binomial(int64(M-n), int64(N-i))
|
||||||
|
numeratorInt := new(big.Int).Mul(a, b)
|
||||||
|
numerator := new(big.Float).SetInt(numeratorInt)
|
||||||
|
item := new(big.Float).Quo(numerator, denominator)
|
||||||
|
rBig.Add(rBig, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
r, _ := rBig.Float64()
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
60
beacon-chain/core/peerdas/peer_sampling_test.go
Normal file
60
beacon-chain/core/peerdas/peer_sampling_test.go
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
package peerdas_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/peerdas"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestExtendedSampleCount(t *testing.T) {
|
||||||
|
const samplesPerSlot = 16
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
allowedMissings uint64
|
||||||
|
extendedSampleCount uint64
|
||||||
|
}{
|
||||||
|
{name: "allowedMissings=0", allowedMissings: 0, extendedSampleCount: 16},
|
||||||
|
{name: "allowedMissings=1", allowedMissings: 1, extendedSampleCount: 20},
|
||||||
|
{name: "allowedMissings=2", allowedMissings: 2, extendedSampleCount: 24},
|
||||||
|
{name: "allowedMissings=3", allowedMissings: 3, extendedSampleCount: 27},
|
||||||
|
{name: "allowedMissings=4", allowedMissings: 4, extendedSampleCount: 29},
|
||||||
|
{name: "allowedMissings=5", allowedMissings: 5, extendedSampleCount: 32},
|
||||||
|
{name: "allowedMissings=6", allowedMissings: 6, extendedSampleCount: 35},
|
||||||
|
{name: "allowedMissings=7", allowedMissings: 7, extendedSampleCount: 37},
|
||||||
|
{name: "allowedMissings=8", allowedMissings: 8, extendedSampleCount: 40},
|
||||||
|
{name: "allowedMissings=9", allowedMissings: 9, extendedSampleCount: 42},
|
||||||
|
{name: "allowedMissings=10", allowedMissings: 10, extendedSampleCount: 44},
|
||||||
|
{name: "allowedMissings=11", allowedMissings: 11, extendedSampleCount: 47},
|
||||||
|
{name: "allowedMissings=12", allowedMissings: 12, extendedSampleCount: 49},
|
||||||
|
{name: "allowedMissings=13", allowedMissings: 13, extendedSampleCount: 51},
|
||||||
|
{name: "allowedMissings=14", allowedMissings: 14, extendedSampleCount: 53},
|
||||||
|
{name: "allowedMissings=15", allowedMissings: 15, extendedSampleCount: 55},
|
||||||
|
{name: "allowedMissings=16", allowedMissings: 16, extendedSampleCount: 57},
|
||||||
|
{name: "allowedMissings=17", allowedMissings: 17, extendedSampleCount: 59},
|
||||||
|
{name: "allowedMissings=18", allowedMissings: 18, extendedSampleCount: 61},
|
||||||
|
{name: "allowedMissings=19", allowedMissings: 19, extendedSampleCount: 63},
|
||||||
|
{name: "allowedMissings=20", allowedMissings: 20, extendedSampleCount: 65},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
result := peerdas.ExtendedSampleCount(samplesPerSlot, tc.allowedMissings)
|
||||||
|
require.Equal(t, tc.extendedSampleCount, result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHypergeomCDF(t *testing.T) {
|
||||||
|
// Test case from https://en.wikipedia.org/wiki/Hypergeometric_distribution
|
||||||
|
// Population size: 1000, number of successes in population: 500, sample size: 10, number of successes in sample: 5
|
||||||
|
// Expected result: 0.072
|
||||||
|
const (
|
||||||
|
expected = 0.0796665913283742
|
||||||
|
margin = 0.000001
|
||||||
|
)
|
||||||
|
|
||||||
|
actual := peerdas.HypergeomCDF(5, 128, 65, 16)
|
||||||
|
require.Equal(t, true, expected-margin <= actual && actual <= expected+margin)
|
||||||
|
}
|
||||||
@@ -4,7 +4,6 @@ go_library(
|
|||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = [
|
srcs = [
|
||||||
"domain.go",
|
"domain.go",
|
||||||
"signature.go",
|
|
||||||
"signing_root.go",
|
"signing_root.go",
|
||||||
],
|
],
|
||||||
importpath = "github.com/OffchainLabs/prysm/v6/beacon-chain/core/signing",
|
importpath = "github.com/OffchainLabs/prysm/v6/beacon-chain/core/signing",
|
||||||
@@ -25,7 +24,6 @@ go_test(
|
|||||||
name = "go_default_test",
|
name = "go_default_test",
|
||||||
srcs = [
|
srcs = [
|
||||||
"domain_test.go",
|
"domain_test.go",
|
||||||
"signature_test.go",
|
|
||||||
"signing_root_test.go",
|
"signing_root_test.go",
|
||||||
],
|
],
|
||||||
embed = [":go_default_library"],
|
embed = [":go_default_library"],
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
package signing
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
|
||||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
var ErrNilRegistration = errors.New("nil signed registration")
|
|
||||||
|
|
||||||
// VerifyRegistrationSignature verifies the signature of a validator's registration.
|
|
||||||
func VerifyRegistrationSignature(
|
|
||||||
sr *ethpb.SignedValidatorRegistrationV1,
|
|
||||||
) error {
|
|
||||||
if sr == nil || sr.Message == nil {
|
|
||||||
return ErrNilRegistration
|
|
||||||
}
|
|
||||||
|
|
||||||
d := params.BeaconConfig().DomainApplicationBuilder
|
|
||||||
// Per spec, we want the fork version and genesis validator to be nil.
|
|
||||||
// Which is genesis value and zero by default.
|
|
||||||
sd, err := ComputeDomain(
|
|
||||||
d,
|
|
||||||
nil, /* fork version */
|
|
||||||
nil /* genesis val root */)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := VerifySigningRoot(sr.Message, sr.Message.Pubkey, sr.Signature, sd); err != nil {
|
|
||||||
return ErrSigFailedToVerify
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
package signing_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/signing"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/crypto/bls"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
|
||||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestVerifyRegistrationSignature(t *testing.T) {
|
|
||||||
sk, err := bls.RandKey()
|
|
||||||
require.NoError(t, err)
|
|
||||||
reg := ðpb.ValidatorRegistrationV1{
|
|
||||||
FeeRecipient: bytesutil.PadTo([]byte("fee"), 20),
|
|
||||||
GasLimit: 123456,
|
|
||||||
Timestamp: uint64(time.Now().Unix()),
|
|
||||||
Pubkey: sk.PublicKey().Marshal(),
|
|
||||||
}
|
|
||||||
d := params.BeaconConfig().DomainApplicationBuilder
|
|
||||||
domain, err := signing.ComputeDomain(d, nil, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
sr, err := signing.ComputeSigningRoot(reg, domain)
|
|
||||||
require.NoError(t, err)
|
|
||||||
sk.Sign(sr[:]).Marshal()
|
|
||||||
|
|
||||||
sReg := ðpb.SignedValidatorRegistrationV1{
|
|
||||||
Message: reg,
|
|
||||||
Signature: sk.Sign(sr[:]).Marshal(),
|
|
||||||
}
|
|
||||||
require.NoError(t, signing.VerifyRegistrationSignature(sReg))
|
|
||||||
|
|
||||||
sReg.Signature = []byte("bad")
|
|
||||||
require.ErrorIs(t, signing.VerifyRegistrationSignature(sReg), signing.ErrSigFailedToVerify)
|
|
||||||
|
|
||||||
sReg.Message = nil
|
|
||||||
require.ErrorIs(t, signing.VerifyRegistrationSignature(sReg), signing.ErrNilRegistration)
|
|
||||||
}
|
|
||||||
@@ -53,6 +53,11 @@ func HigherEqualThanAltairVersionAndEpoch(s state.BeaconState, e primitives.Epoc
|
|||||||
return s.Version() >= version.Altair && e >= params.BeaconConfig().AltairForkEpoch
|
return s.Version() >= version.Altair && e >= params.BeaconConfig().AltairForkEpoch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PeerDASIsActive checks whether peerDAS is active at the provided slot.
|
||||||
|
func PeerDASIsActive(slot primitives.Slot) bool {
|
||||||
|
return params.FuluEnabled() && slots.ToEpoch(slot) >= params.BeaconConfig().FuluForkEpoch
|
||||||
|
}
|
||||||
|
|
||||||
// CanUpgradeToAltair returns true if the input `slot` can upgrade to Altair.
|
// CanUpgradeToAltair returns true if the input `slot` can upgrade to Altair.
|
||||||
// Spec code:
|
// Spec code:
|
||||||
// If state.slot % SLOTS_PER_EPOCH == 0 and compute_epoch_at_slot(state.slot) == ALTAIR_FORK_EPOCH
|
// If state.slot % SLOTS_PER_EPOCH == 0 and compute_epoch_at_slot(state.slot) == ALTAIR_FORK_EPOCH
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ go_library(
|
|||||||
visibility = [
|
visibility = [
|
||||||
"//beacon-chain:__subpackages__",
|
"//beacon-chain:__subpackages__",
|
||||||
"//cmd/beacon-chain:__subpackages__",
|
"//cmd/beacon-chain:__subpackages__",
|
||||||
|
"//genesis:__subpackages__",
|
||||||
"//testing/slasher/simulator:__pkg__",
|
"//testing/slasher/simulator:__pkg__",
|
||||||
"//tools:__subpackages__",
|
"//tools:__subpackages__",
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ go_library(
|
|||||||
"//beacon-chain/db/filters:go_default_library",
|
"//beacon-chain/db/filters:go_default_library",
|
||||||
"//beacon-chain/db/iface:go_default_library",
|
"//beacon-chain/db/iface:go_default_library",
|
||||||
"//beacon-chain/state:go_default_library",
|
"//beacon-chain/state:go_default_library",
|
||||||
"//beacon-chain/state/genesis:go_default_library",
|
|
||||||
"//beacon-chain/state/state-native:go_default_library",
|
"//beacon-chain/state/state-native:go_default_library",
|
||||||
"//config/features:go_default_library",
|
"//config/features:go_default_library",
|
||||||
"//config/fieldparams:go_default_library",
|
"//config/fieldparams:go_default_library",
|
||||||
@@ -50,6 +49,7 @@ go_library(
|
|||||||
"//container/slice:go_default_library",
|
"//container/slice:go_default_library",
|
||||||
"//encoding/bytesutil:go_default_library",
|
"//encoding/bytesutil:go_default_library",
|
||||||
"//encoding/ssz/detect:go_default_library",
|
"//encoding/ssz/detect:go_default_library",
|
||||||
|
"//genesis:go_default_library",
|
||||||
"//io/file:go_default_library",
|
"//io/file:go_default_library",
|
||||||
"//monitoring/progress:go_default_library",
|
"//monitoring/progress:go_default_library",
|
||||||
"//monitoring/tracing:go_default_library",
|
"//monitoring/tracing:go_default_library",
|
||||||
@@ -106,7 +106,6 @@ go_test(
|
|||||||
"//beacon-chain/db/filters:go_default_library",
|
"//beacon-chain/db/filters:go_default_library",
|
||||||
"//beacon-chain/db/iface:go_default_library",
|
"//beacon-chain/db/iface:go_default_library",
|
||||||
"//beacon-chain/state:go_default_library",
|
"//beacon-chain/state:go_default_library",
|
||||||
"//beacon-chain/state/genesis:go_default_library",
|
|
||||||
"//beacon-chain/state/state-native:go_default_library",
|
"//beacon-chain/state/state-native:go_default_library",
|
||||||
"//config/features:go_default_library",
|
"//config/features:go_default_library",
|
||||||
"//config/fieldparams:go_default_library",
|
"//config/fieldparams:go_default_library",
|
||||||
@@ -116,6 +115,7 @@ go_test(
|
|||||||
"//consensus-types/light-client:go_default_library",
|
"//consensus-types/light-client:go_default_library",
|
||||||
"//consensus-types/primitives:go_default_library",
|
"//consensus-types/primitives:go_default_library",
|
||||||
"//encoding/bytesutil:go_default_library",
|
"//encoding/bytesutil:go_default_library",
|
||||||
|
"//genesis/embedded:go_default_library",
|
||||||
"//proto/dbval:go_default_library",
|
"//proto/dbval:go_default_library",
|
||||||
"//proto/engine/v1:go_default_library",
|
"//proto/engine/v1:go_default_library",
|
||||||
"//proto/prysm/v1alpha1:go_default_library",
|
"//proto/prysm/v1alpha1:go_default_library",
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
dbIface "github.com/OffchainLabs/prysm/v6/beacon-chain/db/iface"
|
dbIface "github.com/OffchainLabs/prysm/v6/beacon-chain/db/iface"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/ssz/detect"
|
"github.com/OffchainLabs/prysm/v6/encoding/ssz/detect"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/genesis"
|
||||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
@@ -97,8 +98,22 @@ func (s *Store) EnsureEmbeddedGenesis(ctx context.Context) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if gs != nil && !gs.IsNil() {
|
if !state.IsNil(gs) {
|
||||||
return s.SaveGenesisData(ctx, gs)
|
return s.SaveGenesisData(ctx, gs)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LegacyGenesisProvider struct {
|
||||||
|
store *Store
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLegacyGenesisProvider(store *Store) *LegacyGenesisProvider {
|
||||||
|
return &LegacyGenesisProvider{store: store}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ genesis.Provider = &LegacyGenesisProvider{}
|
||||||
|
|
||||||
|
func (p *LegacyGenesisProvider) Genesis(ctx context.Context) (state.BeaconState, error) {
|
||||||
|
return p.store.LegacyGenesisState(ctx)
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,14 +6,12 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/state/genesis"
|
|
||||||
statenative "github.com/OffchainLabs/prysm/v6/beacon-chain/state/state-native"
|
statenative "github.com/OffchainLabs/prysm/v6/beacon-chain/state/state-native"
|
||||||
"github.com/OffchainLabs/prysm/v6/config/features"
|
"github.com/OffchainLabs/prysm/v6/config/features"
|
||||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/blocks"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/blocks"
|
||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
||||||
"github.com/OffchainLabs/prysm/v6/monitoring/tracing"
|
"github.com/OffchainLabs/prysm/v6/genesis"
|
||||||
"github.com/OffchainLabs/prysm/v6/monitoring/tracing/trace"
|
"github.com/OffchainLabs/prysm/v6/monitoring/tracing/trace"
|
||||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||||
"github.com/OffchainLabs/prysm/v6/runtime/version"
|
"github.com/OffchainLabs/prysm/v6/runtime/version"
|
||||||
@@ -65,21 +63,16 @@ func (s *Store) StateOrError(ctx context.Context, blockRoot [32]byte) (state.Bea
|
|||||||
return st, nil
|
return st, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenesisState returns the genesis state in beacon chain.
|
|
||||||
func (s *Store) GenesisState(ctx context.Context) (state.BeaconState, error) {
|
func (s *Store) GenesisState(ctx context.Context) (state.BeaconState, error) {
|
||||||
ctx, span := trace.StartSpan(ctx, "BeaconDB.GenesisState")
|
return genesis.State()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenesisState returns the genesis state in beacon chain.
|
||||||
|
func (s *Store) LegacyGenesisState(ctx context.Context) (state.BeaconState, error) {
|
||||||
|
ctx, span := trace.StartSpan(ctx, "BeaconDB.LegacyGenesisState")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
cached, err := genesis.State(params.BeaconConfig().ConfigName)
|
var err error
|
||||||
if err != nil {
|
|
||||||
tracing.AnnotateError(span, err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
span.SetAttributes(trace.BoolAttribute("cache_hit", cached != nil))
|
|
||||||
if cached != nil {
|
|
||||||
return cached, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var st state.BeaconState
|
var st state.BeaconState
|
||||||
err = s.db.View(func(tx *bolt.Tx) error {
|
err = s.db.View(func(tx *bolt.Tx) error {
|
||||||
// Retrieve genesis block's signing root from blocks bucket,
|
// Retrieve genesis block's signing root from blocks bucket,
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ package kv
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/state/genesis"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/blocks"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/blocks"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/genesis/embedded"
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/util"
|
"github.com/OffchainLabs/prysm/v6/testing/util"
|
||||||
)
|
)
|
||||||
@@ -18,7 +18,7 @@ func TestSaveOrigin(t *testing.T) {
|
|||||||
ctx := t.Context()
|
ctx := t.Context()
|
||||||
db := setupDB(t)
|
db := setupDB(t)
|
||||||
|
|
||||||
st, err := genesis.State(params.MainnetName)
|
st, err := embedded.ByName(params.MainnetName)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
sb, err := st.MarshalSSZ()
|
sb, err := st.MarshalSSZ()
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ go_library(
|
|||||||
"//beacon-chain/core/feed:go_default_library",
|
"//beacon-chain/core/feed:go_default_library",
|
||||||
"//beacon-chain/core/feed/state:go_default_library",
|
"//beacon-chain/core/feed/state:go_default_library",
|
||||||
"//beacon-chain/core/helpers:go_default_library",
|
"//beacon-chain/core/helpers:go_default_library",
|
||||||
|
"//beacon-chain/core/peerdas:go_default_library",
|
||||||
"//beacon-chain/core/transition:go_default_library",
|
"//beacon-chain/core/transition:go_default_library",
|
||||||
"//beacon-chain/db:go_default_library",
|
"//beacon-chain/db:go_default_library",
|
||||||
"//beacon-chain/execution/types:go_default_library",
|
"//beacon-chain/execution/types:go_default_library",
|
||||||
@@ -97,6 +98,7 @@ go_test(
|
|||||||
embed = [":go_default_library"],
|
embed = [":go_default_library"],
|
||||||
deps = [
|
deps = [
|
||||||
"//async/event:go_default_library",
|
"//async/event:go_default_library",
|
||||||
|
"//beacon-chain/blockchain/kzg:go_default_library",
|
||||||
"//beacon-chain/cache/depositsnapshot:go_default_library",
|
"//beacon-chain/cache/depositsnapshot:go_default_library",
|
||||||
"//beacon-chain/core/feed:go_default_library",
|
"//beacon-chain/core/feed:go_default_library",
|
||||||
"//beacon-chain/core/feed/state:go_default_library",
|
"//beacon-chain/core/feed/state:go_default_library",
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/peerdas"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/execution/types"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/execution/types"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/verification"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/verification"
|
||||||
fieldparams "github.com/OffchainLabs/prysm/v6/config/fieldparams"
|
fieldparams "github.com/OffchainLabs/prysm/v6/config/fieldparams"
|
||||||
@@ -44,11 +45,16 @@ var (
|
|||||||
GetPayloadMethodV3,
|
GetPayloadMethodV3,
|
||||||
GetPayloadBodiesByHashV1,
|
GetPayloadBodiesByHashV1,
|
||||||
GetPayloadBodiesByRangeV1,
|
GetPayloadBodiesByRangeV1,
|
||||||
|
GetBlobsV1,
|
||||||
}
|
}
|
||||||
electraEngineEndpoints = []string{
|
electraEngineEndpoints = []string{
|
||||||
NewPayloadMethodV4,
|
NewPayloadMethodV4,
|
||||||
GetPayloadMethodV4,
|
GetPayloadMethodV4,
|
||||||
}
|
}
|
||||||
|
fuluEngineEndpoints = []string{
|
||||||
|
GetPayloadMethodV5,
|
||||||
|
GetBlobsV2,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -73,6 +79,8 @@ const (
|
|||||||
GetPayloadMethodV3 = "engine_getPayloadV3"
|
GetPayloadMethodV3 = "engine_getPayloadV3"
|
||||||
// GetPayloadMethodV4 is the get payload method added for electra
|
// GetPayloadMethodV4 is the get payload method added for electra
|
||||||
GetPayloadMethodV4 = "engine_getPayloadV4"
|
GetPayloadMethodV4 = "engine_getPayloadV4"
|
||||||
|
// GetPayloadMethodV5 is the get payload method added for fulu
|
||||||
|
GetPayloadMethodV5 = "engine_getPayloadV5"
|
||||||
// BlockByHashMethod request string for JSON-RPC.
|
// BlockByHashMethod request string for JSON-RPC.
|
||||||
BlockByHashMethod = "eth_getBlockByHash"
|
BlockByHashMethod = "eth_getBlockByHash"
|
||||||
// BlockByNumberMethod request string for JSON-RPC.
|
// BlockByNumberMethod request string for JSON-RPC.
|
||||||
@@ -85,11 +93,21 @@ const (
|
|||||||
ExchangeCapabilities = "engine_exchangeCapabilities"
|
ExchangeCapabilities = "engine_exchangeCapabilities"
|
||||||
// GetBlobsV1 request string for JSON-RPC.
|
// GetBlobsV1 request string for JSON-RPC.
|
||||||
GetBlobsV1 = "engine_getBlobsV1"
|
GetBlobsV1 = "engine_getBlobsV1"
|
||||||
|
// GetBlobsV2 request string for JSON-RPC.
|
||||||
|
GetBlobsV2 = "engine_getBlobsV2"
|
||||||
// Defines the seconds before timing out engine endpoints with non-block execution semantics.
|
// Defines the seconds before timing out engine endpoints with non-block execution semantics.
|
||||||
defaultEngineTimeout = time.Second
|
// TODO: Remove temporarily needed hack since geth takes an input blobs txs with blobs proofs, and
|
||||||
|
// does the heavy lifting of building cells proofs, while normally this is done by the tx sender.
|
||||||
|
// This is a cool hack because it lets the CL to act as if the tx sender actually computed the cells proofs.
|
||||||
|
// The only counter part is the `engine_getPayloadv<x>` takes a lot of time.
|
||||||
|
// defaultEngineTimeout = time.Second
|
||||||
|
defaultEngineTimeout = 2 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
var errInvalidPayloadBodyResponse = errors.New("engine api payload body response is invalid")
|
var (
|
||||||
|
errInvalidPayloadBodyResponse = errors.New("engine api payload body response is invalid")
|
||||||
|
errMissingBlobsAndProofsFromEL = errors.New("engine api payload body response is missing blobs and proofs")
|
||||||
|
)
|
||||||
|
|
||||||
// ForkchoiceUpdatedResponse is the response kind received by the
|
// ForkchoiceUpdatedResponse is the response kind received by the
|
||||||
// engine_forkchoiceUpdatedV1 endpoint.
|
// engine_forkchoiceUpdatedV1 endpoint.
|
||||||
@@ -108,6 +126,7 @@ type Reconstructor interface {
|
|||||||
ctx context.Context, blindedBlocks []interfaces.ReadOnlySignedBeaconBlock,
|
ctx context.Context, blindedBlocks []interfaces.ReadOnlySignedBeaconBlock,
|
||||||
) ([]interfaces.SignedBeaconBlock, error)
|
) ([]interfaces.SignedBeaconBlock, error)
|
||||||
ReconstructBlobSidecars(ctx context.Context, block interfaces.ReadOnlySignedBeaconBlock, blockRoot [32]byte, hi func(uint64) bool) ([]blocks.VerifiedROBlob, error)
|
ReconstructBlobSidecars(ctx context.Context, block interfaces.ReadOnlySignedBeaconBlock, blockRoot [32]byte, hi func(uint64) bool) ([]blocks.VerifiedROBlob, error)
|
||||||
|
ReconstructDataColumnSidecars(ctx context.Context, block interfaces.ReadOnlySignedBeaconBlock, blockRoot [32]byte) ([]blocks.VerifiedRODataColumn, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EngineCaller defines a client that can interact with an Ethereum
|
// EngineCaller defines a client that can interact with an Ethereum
|
||||||
@@ -257,6 +276,9 @@ func (s *Service) ForkchoiceUpdated(
|
|||||||
|
|
||||||
func getPayloadMethodAndMessage(slot primitives.Slot) (string, proto.Message) {
|
func getPayloadMethodAndMessage(slot primitives.Slot) (string, proto.Message) {
|
||||||
pe := slots.ToEpoch(slot)
|
pe := slots.ToEpoch(slot)
|
||||||
|
if pe >= params.BeaconConfig().FuluForkEpoch {
|
||||||
|
return GetPayloadMethodV5, &pb.ExecutionBundleFulu{}
|
||||||
|
}
|
||||||
if pe >= params.BeaconConfig().ElectraForkEpoch {
|
if pe >= params.BeaconConfig().ElectraForkEpoch {
|
||||||
return GetPayloadMethodV4, &pb.ExecutionBundleElectra{}
|
return GetPayloadMethodV4, &pb.ExecutionBundleElectra{}
|
||||||
}
|
}
|
||||||
@@ -289,7 +311,7 @@ func (s *Service) GetPayload(ctx context.Context, payloadId [8]byte, slot primit
|
|||||||
}
|
}
|
||||||
res, err := blocks.NewGetPayloadResponse(result)
|
res, err := blocks.NewGetPayloadResponse(result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, errors.Wrap(err, "new get payload response")
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
@@ -298,33 +320,36 @@ func (s *Service) ExchangeCapabilities(ctx context.Context) ([]string, error) {
|
|||||||
ctx, span := trace.StartSpan(ctx, "powchain.engine-api-client.ExchangeCapabilities")
|
ctx, span := trace.StartSpan(ctx, "powchain.engine-api-client.ExchangeCapabilities")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
// Only check for electra related engine methods if it has been activated.
|
|
||||||
if params.ElectraEnabled() {
|
if params.ElectraEnabled() {
|
||||||
supportedEngineEndpoints = append(supportedEngineEndpoints, electraEngineEndpoints...)
|
supportedEngineEndpoints = append(supportedEngineEndpoints, electraEngineEndpoints...)
|
||||||
}
|
}
|
||||||
var result []string
|
|
||||||
err := s.rpcClient.CallContext(ctx, &result, ExchangeCapabilities, supportedEngineEndpoints)
|
if params.FuluEnabled() {
|
||||||
if err != nil {
|
supportedEngineEndpoints = append(supportedEngineEndpoints, fuluEngineEndpoints...)
|
||||||
|
}
|
||||||
|
|
||||||
|
elSupportedEndpointsSlice := make([]string, len(supportedEngineEndpoints))
|
||||||
|
if err := s.rpcClient.CallContext(ctx, &elSupportedEndpointsSlice, ExchangeCapabilities, supportedEngineEndpoints); err != nil {
|
||||||
return nil, handleRPCError(err)
|
return nil, handleRPCError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var unsupported []string
|
elSupportedEndpoints := make(map[string]bool, len(elSupportedEndpointsSlice))
|
||||||
for _, s1 := range supportedEngineEndpoints {
|
for _, method := range elSupportedEndpointsSlice {
|
||||||
supported := false
|
elSupportedEndpoints[method] = true
|
||||||
for _, s2 := range result {
|
}
|
||||||
if s1 == s2 {
|
|
||||||
supported = true
|
unsupported := make([]string, 0, len(supportedEngineEndpoints))
|
||||||
break
|
for _, method := range supportedEngineEndpoints {
|
||||||
}
|
if !elSupportedEndpoints[method] {
|
||||||
}
|
unsupported = append(unsupported, method)
|
||||||
if !supported {
|
|
||||||
unsupported = append(unsupported, s1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(unsupported) != 0 {
|
if len(unsupported) != 0 {
|
||||||
log.Warnf("Please update client, detected the following unsupported engine methods: %s", unsupported)
|
log.WithField("methods", unsupported).Warning("Connected execution client does not support some requested engine methods")
|
||||||
}
|
}
|
||||||
return result, handleRPCError(err)
|
|
||||||
|
return elSupportedEndpointsSlice, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTerminalBlockHash returns the valid terminal block hash based on total difficulty.
|
// GetTerminalBlockHash returns the valid terminal block hash based on total difficulty.
|
||||||
@@ -495,9 +520,10 @@ func (s *Service) HeaderByNumber(ctx context.Context, number *big.Int) (*types.H
|
|||||||
func (s *Service) GetBlobs(ctx context.Context, versionedHashes []common.Hash) ([]*pb.BlobAndProof, error) {
|
func (s *Service) GetBlobs(ctx context.Context, versionedHashes []common.Hash) ([]*pb.BlobAndProof, error) {
|
||||||
ctx, span := trace.StartSpan(ctx, "powchain.engine-api-client.GetBlobs")
|
ctx, span := trace.StartSpan(ctx, "powchain.engine-api-client.GetBlobs")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
// If the execution engine does not support `GetBlobsV1`, return early to prevent encountering an error later.
|
// If the execution engine does not support `GetBlobsV1`, return early to prevent encountering an error later.
|
||||||
if !s.capabilityCache.has(GetBlobsV1) {
|
if !s.capabilityCache.has(GetBlobsV1) {
|
||||||
return nil, nil
|
return nil, errors.New(fmt.Sprintf("%s is not supported", GetBlobsV1))
|
||||||
}
|
}
|
||||||
|
|
||||||
result := make([]*pb.BlobAndProof, len(versionedHashes))
|
result := make([]*pb.BlobAndProof, len(versionedHashes))
|
||||||
@@ -505,6 +531,19 @@ func (s *Service) GetBlobs(ctx context.Context, versionedHashes []common.Hash) (
|
|||||||
return result, handleRPCError(err)
|
return result, handleRPCError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetBlobsV2(ctx context.Context, versionedHashes []common.Hash) ([]*pb.BlobAndProofV2, error) {
|
||||||
|
ctx, span := trace.StartSpan(ctx, "powchain.engine-api-client.GetBlobsV2")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
|
if !s.capabilityCache.has(GetBlobsV2) {
|
||||||
|
return nil, errors.New(fmt.Sprintf("%s is not supported", GetBlobsV2))
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make([]*pb.BlobAndProofV2, len(versionedHashes))
|
||||||
|
err := s.rpcClient.CallContext(ctx, &result, GetBlobsV2, versionedHashes)
|
||||||
|
return result, handleRPCError(err)
|
||||||
|
}
|
||||||
|
|
||||||
// ReconstructFullBlock takes in a blinded beacon block and reconstructs
|
// ReconstructFullBlock takes in a blinded beacon block and reconstructs
|
||||||
// a beacon block with a full execution payload via the engine API.
|
// a beacon block with a full execution payload via the engine API.
|
||||||
func (s *Service) ReconstructFullBlock(
|
func (s *Service) ReconstructFullBlock(
|
||||||
@@ -615,6 +654,73 @@ func (s *Service) ReconstructBlobSidecars(ctx context.Context, block interfaces.
|
|||||||
return verifiedBlobs, nil
|
return verifiedBlobs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReconstructDataColumnSidecars reconstructs the verified data column sidecars for a given beacon block.
|
||||||
|
// It retrieves the KZG commitments from the block body, fetches the associated blobs and cell proofs from the EL,
|
||||||
|
// and constructs the corresponding verified read-only data column sidecars.
|
||||||
|
func (s *Service) ReconstructDataColumnSidecars(ctx context.Context, signedROBlock interfaces.ReadOnlySignedBeaconBlock, blockRoot [fieldparams.RootLength]byte) ([]blocks.VerifiedRODataColumn, error) {
|
||||||
|
block := signedROBlock.Block()
|
||||||
|
|
||||||
|
log := log.WithFields(logrus.Fields{
|
||||||
|
"root": fmt.Sprintf("%#x", blockRoot),
|
||||||
|
"slot": block.Slot(),
|
||||||
|
})
|
||||||
|
|
||||||
|
kzgCommitments, err := block.Body().BlobKzgCommitments()
|
||||||
|
if err != nil {
|
||||||
|
return nil, wrapWithBlockRoot(err, blockRoot, "blob KZG commitments")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect KZG hashes for all blobs
|
||||||
|
var kzgHashes []common.Hash
|
||||||
|
for _, commitment := range kzgCommitments {
|
||||||
|
kzgHashes = append(kzgHashes, primitives.ConvertKzgCommitmentToVersionedHash(commitment))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch all blobsAndCellsProofs from EL
|
||||||
|
blobAndProofV2s, err := s.GetBlobsV2(ctx, kzgHashes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, wrapWithBlockRoot(err, blockRoot, "get blobs V2")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return early if nothing is returned from the EL.
|
||||||
|
if len(blobAndProofV2s) == 0 {
|
||||||
|
log.Debug("No blobs returned from EL")
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the blobs and proofs from the blobAndProofV2s.
|
||||||
|
blobs := make([][]byte, 0, len(blobAndProofV2s))
|
||||||
|
cellProofs := make([][]byte, 0, len(blobAndProofV2s))
|
||||||
|
for _, blobsAndProofs := range blobAndProofV2s {
|
||||||
|
if blobsAndProofs == nil {
|
||||||
|
return nil, wrapWithBlockRoot(errMissingBlobsAndProofsFromEL, blockRoot, "")
|
||||||
|
}
|
||||||
|
blobs = append(blobs, blobsAndProofs.Blob)
|
||||||
|
cellProofs = append(cellProofs, blobsAndProofs.KzgProofs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
dataColumnSidecars, err := peerdas.ConstructDataColumnSidecars(signedROBlock, blobs, cellProofs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, wrapWithBlockRoot(err, blockRoot, "construct data column sidecars")
|
||||||
|
}
|
||||||
|
|
||||||
|
verifiedRODataColumns := make([]blocks.VerifiedRODataColumn, 0, len(dataColumnSidecars))
|
||||||
|
for _, dataColumnSidecar := range dataColumnSidecars {
|
||||||
|
roDataColumn, err := blocks.NewRODataColumnWithRoot(dataColumnSidecar, blockRoot)
|
||||||
|
if err != nil {
|
||||||
|
return nil, wrapWithBlockRoot(err, blockRoot, "new read-only data column with root")
|
||||||
|
}
|
||||||
|
|
||||||
|
// We trust the execution layer we are connected to, so we can upgrade the read only data column sidecar into a verified one.
|
||||||
|
verifiedRODataColumn := blocks.NewVerifiedRODataColumn(roDataColumn)
|
||||||
|
verifiedRODataColumns = append(verifiedRODataColumns, verifiedRODataColumn)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug("Data columns successfully reconstructed from EL")
|
||||||
|
|
||||||
|
return verifiedRODataColumns, nil
|
||||||
|
}
|
||||||
|
|
||||||
func fullPayloadFromPayloadBody(
|
func fullPayloadFromPayloadBody(
|
||||||
header interfaces.ExecutionData, body *pb.ExecutionPayloadBody, bVersion int,
|
header interfaces.ExecutionData, body *pb.ExecutionPayloadBody, bVersion int,
|
||||||
) (interfaces.ExecutionData, error) {
|
) (interfaces.ExecutionData, error) {
|
||||||
@@ -902,3 +1008,8 @@ func toBlockNumArg(number *big.Int) string {
|
|||||||
}
|
}
|
||||||
return hexutil.EncodeBig(number)
|
return hexutil.EncodeBig(number)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// wrapWithBlockRoot returns a new error with the given block root.
|
||||||
|
func wrapWithBlockRoot(err error, blockRoot [32]byte, message string) error {
|
||||||
|
return errors.Wrap(err, fmt.Sprintf("%s for block %#x", message, blockRoot))
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/blockchain/kzg"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/db/filesystem"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/db/filesystem"
|
||||||
mocks "github.com/OffchainLabs/prysm/v6/beacon-chain/execution/testing"
|
mocks "github.com/OffchainLabs/prysm/v6/beacon-chain/execution/testing"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/verification"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/verification"
|
||||||
@@ -167,6 +168,7 @@ func TestClient_HTTP(t *testing.T) {
|
|||||||
cfg.CapellaForkEpoch = 1
|
cfg.CapellaForkEpoch = 1
|
||||||
cfg.DenebForkEpoch = 2
|
cfg.DenebForkEpoch = 2
|
||||||
cfg.ElectraForkEpoch = 3
|
cfg.ElectraForkEpoch = 3
|
||||||
|
cfg.FuluForkEpoch = 4
|
||||||
params.OverrideBeaconConfig(cfg)
|
params.OverrideBeaconConfig(cfg)
|
||||||
|
|
||||||
t.Run(GetPayloadMethod, func(t *testing.T) {
|
t.Run(GetPayloadMethod, func(t *testing.T) {
|
||||||
@@ -317,11 +319,11 @@ func TestClient_HTTP(t *testing.T) {
|
|||||||
require.DeepEqual(t, uint64(2), g)
|
require.DeepEqual(t, uint64(2), g)
|
||||||
|
|
||||||
commitments := [][]byte{bytesutil.PadTo([]byte("commitment1"), fieldparams.BLSPubkeyLength), bytesutil.PadTo([]byte("commitment2"), fieldparams.BLSPubkeyLength)}
|
commitments := [][]byte{bytesutil.PadTo([]byte("commitment1"), fieldparams.BLSPubkeyLength), bytesutil.PadTo([]byte("commitment2"), fieldparams.BLSPubkeyLength)}
|
||||||
require.DeepEqual(t, commitments, resp.BlobsBundle.KzgCommitments)
|
require.DeepEqual(t, commitments, resp.BlobsBundler.GetKzgCommitments())
|
||||||
proofs := [][]byte{bytesutil.PadTo([]byte("proof1"), fieldparams.BLSPubkeyLength), bytesutil.PadTo([]byte("proof2"), fieldparams.BLSPubkeyLength)}
|
proofs := [][]byte{bytesutil.PadTo([]byte("proof1"), fieldparams.BLSPubkeyLength), bytesutil.PadTo([]byte("proof2"), fieldparams.BLSPubkeyLength)}
|
||||||
require.DeepEqual(t, proofs, resp.BlobsBundle.Proofs)
|
require.DeepEqual(t, proofs, resp.BlobsBundler.GetProofs())
|
||||||
blobs := [][]byte{bytesutil.PadTo([]byte("a"), fieldparams.BlobLength), bytesutil.PadTo([]byte("b"), fieldparams.BlobLength)}
|
blobs := [][]byte{bytesutil.PadTo([]byte("a"), fieldparams.BlobLength), bytesutil.PadTo([]byte("b"), fieldparams.BlobLength)}
|
||||||
require.DeepEqual(t, blobs, resp.BlobsBundle.Blobs)
|
require.DeepEqual(t, blobs, resp.BlobsBundler.GetBlobs())
|
||||||
})
|
})
|
||||||
t.Run(GetPayloadMethodV4, func(t *testing.T) {
|
t.Run(GetPayloadMethodV4, func(t *testing.T) {
|
||||||
payloadId := [8]byte{1}
|
payloadId := [8]byte{1}
|
||||||
@@ -372,11 +374,11 @@ func TestClient_HTTP(t *testing.T) {
|
|||||||
require.DeepEqual(t, uint64(2), g)
|
require.DeepEqual(t, uint64(2), g)
|
||||||
|
|
||||||
commitments := [][]byte{bytesutil.PadTo([]byte("commitment1"), fieldparams.BLSPubkeyLength), bytesutil.PadTo([]byte("commitment2"), fieldparams.BLSPubkeyLength)}
|
commitments := [][]byte{bytesutil.PadTo([]byte("commitment1"), fieldparams.BLSPubkeyLength), bytesutil.PadTo([]byte("commitment2"), fieldparams.BLSPubkeyLength)}
|
||||||
require.DeepEqual(t, commitments, resp.BlobsBundle.KzgCommitments)
|
require.DeepEqual(t, commitments, resp.BlobsBundler.GetKzgCommitments())
|
||||||
proofs := [][]byte{bytesutil.PadTo([]byte("proof1"), fieldparams.BLSPubkeyLength), bytesutil.PadTo([]byte("proof2"), fieldparams.BLSPubkeyLength)}
|
proofs := [][]byte{bytesutil.PadTo([]byte("proof1"), fieldparams.BLSPubkeyLength), bytesutil.PadTo([]byte("proof2"), fieldparams.BLSPubkeyLength)}
|
||||||
require.DeepEqual(t, proofs, resp.BlobsBundle.Proofs)
|
require.DeepEqual(t, proofs, resp.BlobsBundler.GetProofs())
|
||||||
blobs := [][]byte{bytesutil.PadTo([]byte("a"), fieldparams.BlobLength), bytesutil.PadTo([]byte("b"), fieldparams.BlobLength)}
|
blobs := [][]byte{bytesutil.PadTo([]byte("a"), fieldparams.BlobLength), bytesutil.PadTo([]byte("b"), fieldparams.BlobLength)}
|
||||||
require.DeepEqual(t, blobs, resp.BlobsBundle.Blobs)
|
require.DeepEqual(t, blobs, resp.BlobsBundler.GetBlobs())
|
||||||
requests := &pb.ExecutionRequests{
|
requests := &pb.ExecutionRequests{
|
||||||
Deposits: []*pb.DepositRequest{
|
Deposits: []*pb.DepositRequest{
|
||||||
{
|
{
|
||||||
@@ -405,7 +407,52 @@ func TestClient_HTTP(t *testing.T) {
|
|||||||
|
|
||||||
require.DeepEqual(t, requests, resp.ExecutionRequests)
|
require.DeepEqual(t, requests, resp.ExecutionRequests)
|
||||||
})
|
})
|
||||||
|
t.Run(GetPayloadMethodV5, func(t *testing.T) {
|
||||||
|
payloadId := [8]byte{1}
|
||||||
|
want, ok := fix["ExecutionBundleFulu"].(*pb.GetPayloadV5ResponseJson)
|
||||||
|
require.Equal(t, true, ok)
|
||||||
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
defer func() {
|
||||||
|
require.NoError(t, r.Body.Close())
|
||||||
|
}()
|
||||||
|
enc, err := io.ReadAll(r.Body)
|
||||||
|
require.NoError(t, err)
|
||||||
|
jsonRequestString := string(enc)
|
||||||
|
|
||||||
|
reqArg, err := json.Marshal(pb.PayloadIDBytes(payloadId))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// We expect the JSON string RPC request contains the right arguments.
|
||||||
|
require.Equal(t, true, strings.Contains(
|
||||||
|
jsonRequestString, string(reqArg),
|
||||||
|
))
|
||||||
|
resp := map[string]interface{}{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 1,
|
||||||
|
"result": want,
|
||||||
|
}
|
||||||
|
err = json.NewEncoder(w).Encode(resp)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}))
|
||||||
|
defer srv.Close()
|
||||||
|
|
||||||
|
rpcClient, err := rpc.DialHTTP(srv.URL)
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer rpcClient.Close()
|
||||||
|
|
||||||
|
client := &Service{}
|
||||||
|
client.rpcClient = rpcClient
|
||||||
|
|
||||||
|
// We call the RPC method via HTTP and expect a proper result.
|
||||||
|
resp, err := client.GetPayload(ctx, payloadId, 4*params.BeaconConfig().SlotsPerEpoch)
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, ok = resp.BlobsBundler.(*pb.BlobsBundleV2)
|
||||||
|
if !ok {
|
||||||
|
t.Logf("resp.BlobsBundler has unexpected type: %T", resp.BlobsBundler)
|
||||||
|
}
|
||||||
|
require.Equal(t, ok, true)
|
||||||
|
})
|
||||||
t.Run(ForkchoiceUpdatedMethod+" VALID status", func(t *testing.T) {
|
t.Run(ForkchoiceUpdatedMethod+" VALID status", func(t *testing.T) {
|
||||||
forkChoiceState := &pb.ForkchoiceState{
|
forkChoiceState := &pb.ForkchoiceState{
|
||||||
HeadBlockHash: []byte("head"),
|
HeadBlockHash: []byte("head"),
|
||||||
@@ -1539,6 +1586,7 @@ func fixtures() map[string]interface{} {
|
|||||||
"ExecutionPayloadCapellaWithValue": s.ExecutionPayloadWithValueCapella,
|
"ExecutionPayloadCapellaWithValue": s.ExecutionPayloadWithValueCapella,
|
||||||
"ExecutionPayloadDenebWithValue": s.ExecutionPayloadWithValueDeneb,
|
"ExecutionPayloadDenebWithValue": s.ExecutionPayloadWithValueDeneb,
|
||||||
"ExecutionBundleElectra": s.ExecutionBundleElectra,
|
"ExecutionBundleElectra": s.ExecutionBundleElectra,
|
||||||
|
"ExecutionBundleFulu": s.ExecutionBundleFulu,
|
||||||
"ValidPayloadStatus": s.ValidPayloadStatus,
|
"ValidPayloadStatus": s.ValidPayloadStatus,
|
||||||
"InvalidBlockHashStatus": s.InvalidBlockHashStatus,
|
"InvalidBlockHashStatus": s.InvalidBlockHashStatus,
|
||||||
"AcceptedStatus": s.AcceptedStatus,
|
"AcceptedStatus": s.AcceptedStatus,
|
||||||
@@ -1774,6 +1822,36 @@ func fixturesStruct() *payloadFixtures {
|
|||||||
append([]byte{pb.WithdrawalRequestType}, withdrawalRequestBytes...),
|
append([]byte{pb.WithdrawalRequestType}, withdrawalRequestBytes...),
|
||||||
append([]byte{pb.ConsolidationRequestType}, consolidationRequestBytes...)},
|
append([]byte{pb.ConsolidationRequestType}, consolidationRequestBytes...)},
|
||||||
}
|
}
|
||||||
|
executionBundleFixtureFulu := &pb.GetPayloadV5ResponseJson{
|
||||||
|
ShouldOverrideBuilder: true,
|
||||||
|
ExecutionPayload: &pb.ExecutionPayloadDenebJSON{
|
||||||
|
ParentHash: &common.Hash{'a'},
|
||||||
|
FeeRecipient: &common.Address{'b'},
|
||||||
|
StateRoot: &common.Hash{'c'},
|
||||||
|
ReceiptsRoot: &common.Hash{'d'},
|
||||||
|
LogsBloom: &hexutil.Bytes{'e'},
|
||||||
|
PrevRandao: &common.Hash{'f'},
|
||||||
|
BaseFeePerGas: "0x123",
|
||||||
|
BlockHash: &common.Hash{'g'},
|
||||||
|
Transactions: []hexutil.Bytes{{'h'}},
|
||||||
|
Withdrawals: []*pb.Withdrawal{},
|
||||||
|
BlockNumber: &hexUint,
|
||||||
|
GasLimit: &hexUint,
|
||||||
|
GasUsed: &hexUint,
|
||||||
|
Timestamp: &hexUint,
|
||||||
|
BlobGasUsed: &bgu,
|
||||||
|
ExcessBlobGas: &ebg,
|
||||||
|
},
|
||||||
|
BlockValue: "0x11fffffffff",
|
||||||
|
BlobsBundle: &pb.BlobBundleV2JSON{
|
||||||
|
Commitments: []hexutil.Bytes{[]byte("commitment1"), []byte("commitment2")},
|
||||||
|
Proofs: []hexutil.Bytes{[]byte("proof1"), []byte("proof2")},
|
||||||
|
Blobs: []hexutil.Bytes{{'a'}, {'b'}},
|
||||||
|
},
|
||||||
|
ExecutionRequests: []hexutil.Bytes{append([]byte{pb.DepositRequestType}, depositRequestBytes...),
|
||||||
|
append([]byte{pb.WithdrawalRequestType}, withdrawalRequestBytes...),
|
||||||
|
append([]byte{pb.ConsolidationRequestType}, consolidationRequestBytes...)},
|
||||||
|
}
|
||||||
parent := bytesutil.PadTo([]byte("parentHash"), fieldparams.RootLength)
|
parent := bytesutil.PadTo([]byte("parentHash"), fieldparams.RootLength)
|
||||||
sha3Uncles := bytesutil.PadTo([]byte("sha3Uncles"), fieldparams.RootLength)
|
sha3Uncles := bytesutil.PadTo([]byte("sha3Uncles"), fieldparams.RootLength)
|
||||||
miner := bytesutil.PadTo([]byte("miner"), fieldparams.FeeRecipientLength)
|
miner := bytesutil.PadTo([]byte("miner"), fieldparams.FeeRecipientLength)
|
||||||
@@ -1868,6 +1946,7 @@ func fixturesStruct() *payloadFixtures {
|
|||||||
ExecutionPayloadWithValueCapella: executionPayloadWithValueFixtureCapella,
|
ExecutionPayloadWithValueCapella: executionPayloadWithValueFixtureCapella,
|
||||||
ExecutionPayloadWithValueDeneb: executionPayloadWithValueFixtureDeneb,
|
ExecutionPayloadWithValueDeneb: executionPayloadWithValueFixtureDeneb,
|
||||||
ExecutionBundleElectra: executionBundleFixtureElectra,
|
ExecutionBundleElectra: executionBundleFixtureElectra,
|
||||||
|
ExecutionBundleFulu: executionBundleFixtureFulu,
|
||||||
ValidPayloadStatus: validStatus,
|
ValidPayloadStatus: validStatus,
|
||||||
InvalidBlockHashStatus: inValidBlockHashStatus,
|
InvalidBlockHashStatus: inValidBlockHashStatus,
|
||||||
AcceptedStatus: acceptedStatus,
|
AcceptedStatus: acceptedStatus,
|
||||||
@@ -1892,6 +1971,7 @@ type payloadFixtures struct {
|
|||||||
ExecutionPayloadWithValueCapella *pb.GetPayloadV2ResponseJson
|
ExecutionPayloadWithValueCapella *pb.GetPayloadV2ResponseJson
|
||||||
ExecutionPayloadWithValueDeneb *pb.GetPayloadV3ResponseJson
|
ExecutionPayloadWithValueDeneb *pb.GetPayloadV3ResponseJson
|
||||||
ExecutionBundleElectra *pb.GetPayloadV4ResponseJson
|
ExecutionBundleElectra *pb.GetPayloadV4ResponseJson
|
||||||
|
ExecutionBundleFulu *pb.GetPayloadV5ResponseJson
|
||||||
ValidPayloadStatus *pb.PayloadStatus
|
ValidPayloadStatus *pb.PayloadStatus
|
||||||
InvalidBlockHashStatus *pb.PayloadStatus
|
InvalidBlockHashStatus *pb.PayloadStatus
|
||||||
AcceptedStatus *pb.PayloadStatus
|
AcceptedStatus *pb.PayloadStatus
|
||||||
@@ -2361,7 +2441,7 @@ func Test_ExchangeCapabilities(t *testing.T) {
|
|||||||
for _, item := range results {
|
for _, item := range results {
|
||||||
require.NotNil(t, item)
|
require.NotNil(t, item)
|
||||||
}
|
}
|
||||||
assert.LogsContain(t, logHook, "Please update client, detected the following unsupported engine methods:")
|
assert.LogsContain(t, logHook, "Connected execution client does not support some requested engine methods")
|
||||||
})
|
})
|
||||||
t.Run("list of items", func(t *testing.T) {
|
t.Run("list of items", func(t *testing.T) {
|
||||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -2424,7 +2504,7 @@ func TestReconstructBlobSidecars(t *testing.T) {
|
|||||||
t.Run("get-blobs end point is not supported", func(t *testing.T) {
|
t.Run("get-blobs end point is not supported", func(t *testing.T) {
|
||||||
hi := mockSummary(t, []bool{true, true, true, true, true, false})
|
hi := mockSummary(t, []bool{true, true, true, true, true, false})
|
||||||
verifiedBlobs, err := client.ReconstructBlobSidecars(ctx, sb, r, hi)
|
verifiedBlobs, err := client.ReconstructBlobSidecars(ctx, sb, r, hi)
|
||||||
require.NoError(t, err)
|
require.ErrorContains(t, "engine_getBlobsV1 is not supported", err)
|
||||||
require.Equal(t, 0, len(verifiedBlobs))
|
require.Equal(t, 0, len(verifiedBlobs))
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -2476,6 +2556,76 @@ func TestReconstructBlobSidecars(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestReconstructDataColumnSidecars(t *testing.T) {
|
||||||
|
// Start the trusted setup.
|
||||||
|
err := kzg.Start()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Setup right fork epoch
|
||||||
|
params.SetupTestConfigCleanup(t)
|
||||||
|
cfg := params.BeaconConfig().Copy()
|
||||||
|
cfg.CapellaForkEpoch = 1
|
||||||
|
cfg.DenebForkEpoch = 2
|
||||||
|
cfg.ElectraForkEpoch = 3
|
||||||
|
cfg.FuluForkEpoch = 4
|
||||||
|
params.OverrideBeaconConfig(cfg)
|
||||||
|
|
||||||
|
client := &Service{capabilityCache: &capabilityCache{}}
|
||||||
|
b := util.NewBeaconBlockFulu()
|
||||||
|
b.Block.Slot = 4 * params.BeaconConfig().SlotsPerEpoch
|
||||||
|
kzgCommitments := createRandomKzgCommitments(t, 6)
|
||||||
|
b.Block.Body.BlobKzgCommitments = kzgCommitments
|
||||||
|
r, err := b.Block.HashTreeRoot()
|
||||||
|
require.NoError(t, err)
|
||||||
|
sb, err := blocks.NewSignedBeaconBlock(b)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
t.Run("GetBlobsV2 is not supported", func(t *testing.T) {
|
||||||
|
_, err := client.ReconstructDataColumnSidecars(ctx, sb, r)
|
||||||
|
require.ErrorContains(t, "get blobs V2 for block", err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("nothing received", func(t *testing.T) {
|
||||||
|
srv := createBlobServerV2(t, 0, []bool{})
|
||||||
|
defer srv.Close()
|
||||||
|
|
||||||
|
rpcClient, client := setupRpcClientV2(t, srv.URL, client)
|
||||||
|
defer rpcClient.Close()
|
||||||
|
|
||||||
|
dataColumns, err := client.ReconstructDataColumnSidecars(ctx, sb, r)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 0, len(dataColumns))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("receiving all blobs", func(t *testing.T) {
|
||||||
|
blobMasks := []bool{true, true, true, true, true, true}
|
||||||
|
srv := createBlobServerV2(t, 6, blobMasks)
|
||||||
|
defer srv.Close()
|
||||||
|
|
||||||
|
rpcClient, client := setupRpcClientV2(t, srv.URL, client)
|
||||||
|
defer rpcClient.Close()
|
||||||
|
|
||||||
|
dataColumns, err := client.ReconstructDataColumnSidecars(ctx, sb, r)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 128, len(dataColumns))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("missing some blobs", func(t *testing.T) {
|
||||||
|
blobMasks := []bool{false, true, true, true, true, true}
|
||||||
|
srv := createBlobServerV2(t, 6, blobMasks)
|
||||||
|
defer srv.Close()
|
||||||
|
|
||||||
|
rpcClient, client := setupRpcClientV2(t, srv.URL, client)
|
||||||
|
defer rpcClient.Close()
|
||||||
|
|
||||||
|
dataColumns, err := client.ReconstructDataColumnSidecars(ctx, sb, r)
|
||||||
|
require.ErrorContains(t, errMissingBlobsAndProofsFromEL.Error(), err)
|
||||||
|
require.Equal(t, 0, len(dataColumns))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func createRandomKzgCommitments(t *testing.T, num int) [][]byte {
|
func createRandomKzgCommitments(t *testing.T, num int) [][]byte {
|
||||||
kzgCommitments := make([][]byte, num)
|
kzgCommitments := make([][]byte, num)
|
||||||
for i := range kzgCommitments {
|
for i := range kzgCommitments {
|
||||||
@@ -2511,6 +2661,42 @@ func createBlobServer(t *testing.T, numBlobs int, callbackFuncs ...func()) *http
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createBlobServerV2(t *testing.T, numBlobs int, blobMasks []bool) *httptest.Server {
|
||||||
|
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
defer func() {
|
||||||
|
require.NoError(t, r.Body.Close())
|
||||||
|
}()
|
||||||
|
|
||||||
|
require.Equal(t, len(blobMasks), numBlobs)
|
||||||
|
|
||||||
|
blobAndCellProofs := make([]*pb.BlobAndProofV2Json, numBlobs)
|
||||||
|
for i := range blobAndCellProofs {
|
||||||
|
if !blobMasks[i] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
blobAndCellProofs[i] = &pb.BlobAndProofV2Json{
|
||||||
|
Blob: []byte("0xblob"),
|
||||||
|
KzgProofs: []hexutil.Bytes{},
|
||||||
|
}
|
||||||
|
for j := 0; j < int(params.BeaconConfig().NumberOfColumns); j++ {
|
||||||
|
cellProof := make([]byte, 48)
|
||||||
|
blobAndCellProofs[i].KzgProofs = append(blobAndCellProofs[i].KzgProofs, cellProof)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
respJSON := map[string]interface{}{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 1,
|
||||||
|
"result": blobAndCellProofs,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := json.NewEncoder(w).Encode(respJSON)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
func setupRpcClient(t *testing.T, url string, client *Service) (*rpc.Client, *Service) {
|
func setupRpcClient(t *testing.T, url string, client *Service) (*rpc.Client, *Service) {
|
||||||
rpcClient, err := rpc.DialHTTP(url)
|
rpcClient, err := rpc.DialHTTP(url)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -2522,6 +2708,12 @@ func setupRpcClient(t *testing.T, url string, client *Service) (*rpc.Client, *Se
|
|||||||
return rpcClient, client
|
return rpcClient, client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setupRpcClientV2(t *testing.T, url string, client *Service) (*rpc.Client, *Service) {
|
||||||
|
rpcClient, client := setupRpcClient(t, url, client)
|
||||||
|
client.capabilityCache = &capabilityCache{capabilities: map[string]interface{}{GetBlobsV2: nil}}
|
||||||
|
return rpcClient, client
|
||||||
|
}
|
||||||
|
|
||||||
func testNewBlobVerifier() verification.NewBlobVerifier {
|
func testNewBlobVerifier() verification.NewBlobVerifier {
|
||||||
return func(b blocks.ROBlob, reqs []verification.Requirement) verification.BlobVerifier {
|
return func(b blocks.ROBlob, reqs []verification.Requirement) verification.BlobVerifier {
|
||||||
return &verification.MockBlobVerifier{
|
return &verification.MockBlobVerifier{
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ type EngineClient struct {
|
|||||||
ErrGetPayload error
|
ErrGetPayload error
|
||||||
BlobSidecars []blocks.VerifiedROBlob
|
BlobSidecars []blocks.VerifiedROBlob
|
||||||
ErrorBlobSidecars error
|
ErrorBlobSidecars error
|
||||||
|
DataColumnSidecars []blocks.VerifiedRODataColumn
|
||||||
|
ErrorDataColumnSidecars error
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPayload --
|
// NewPayload --
|
||||||
@@ -113,6 +115,10 @@ func (e *EngineClient) ReconstructBlobSidecars(context.Context, interfaces.ReadO
|
|||||||
return e.BlobSidecars, e.ErrorBlobSidecars
|
return e.BlobSidecars, e.ErrorBlobSidecars
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *EngineClient) ReconstructDataColumnSidecars(ctx context.Context, block interfaces.ReadOnlySignedBeaconBlock, blockRoot [32]byte) ([]blocks.VerifiedRODataColumn, error) {
|
||||||
|
return e.DataColumnSidecars, e.ErrorDataColumnSidecars
|
||||||
|
}
|
||||||
|
|
||||||
// GetTerminalBlockHash --
|
// GetTerminalBlockHash --
|
||||||
func (e *EngineClient) GetTerminalBlockHash(ctx context.Context, transitionTime uint64) ([]byte, bool, error) {
|
func (e *EngineClient) GetTerminalBlockHash(ctx context.Context, transitionTime uint64) ([]byte, bool, error) {
|
||||||
ttd := new(big.Int)
|
ttd := new(big.Int)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
|||||||
go_library(
|
go_library(
|
||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = [
|
srcs = [
|
||||||
|
"clear_db.go",
|
||||||
"config.go",
|
"config.go",
|
||||||
"log.go",
|
"log.go",
|
||||||
"node.go",
|
"node.go",
|
||||||
@@ -50,7 +51,6 @@ go_library(
|
|||||||
"//beacon-chain/sync/backfill:go_default_library",
|
"//beacon-chain/sync/backfill:go_default_library",
|
||||||
"//beacon-chain/sync/backfill/coverage:go_default_library",
|
"//beacon-chain/sync/backfill/coverage:go_default_library",
|
||||||
"//beacon-chain/sync/checkpoint:go_default_library",
|
"//beacon-chain/sync/checkpoint:go_default_library",
|
||||||
"//beacon-chain/sync/genesis:go_default_library",
|
|
||||||
"//beacon-chain/sync/initial-sync:go_default_library",
|
"//beacon-chain/sync/initial-sync:go_default_library",
|
||||||
"//beacon-chain/verification:go_default_library",
|
"//beacon-chain/verification:go_default_library",
|
||||||
"//cmd:go_default_library",
|
"//cmd:go_default_library",
|
||||||
@@ -60,6 +60,7 @@ go_library(
|
|||||||
"//consensus-types/primitives:go_default_library",
|
"//consensus-types/primitives:go_default_library",
|
||||||
"//container/slice:go_default_library",
|
"//container/slice:go_default_library",
|
||||||
"//encoding/bytesutil:go_default_library",
|
"//encoding/bytesutil:go_default_library",
|
||||||
|
"//genesis:go_default_library",
|
||||||
"//monitoring/prometheus:go_default_library",
|
"//monitoring/prometheus:go_default_library",
|
||||||
"//monitoring/tracing:go_default_library",
|
"//monitoring/tracing:go_default_library",
|
||||||
"//runtime:go_default_library",
|
"//runtime:go_default_library",
|
||||||
|
|||||||
101
beacon-chain/node/clear_db.go
Normal file
101
beacon-chain/node/clear_db.go
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
package node
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/db/filesystem"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/db/kv"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/db/slasherkv"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/cmd"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type dbClearer struct {
|
||||||
|
shouldClear bool
|
||||||
|
force bool
|
||||||
|
confirmed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
clearConfirmation = "This will delete your beacon chain database stored in your data directory. " +
|
||||||
|
"Your database backups will not be removed - do you want to proceed? (Y/N)"
|
||||||
|
|
||||||
|
clearDeclined = "Database will not be deleted. No changes have been made."
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *dbClearer) clearKV(ctx context.Context, db *kv.Store) (*kv.Store, error) {
|
||||||
|
if !c.shouldProceed() {
|
||||||
|
return db, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Warning("Removing database")
|
||||||
|
if err := db.ClearDB(); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not clear database")
|
||||||
|
}
|
||||||
|
return kv.NewKVStore(ctx, db.DatabasePath())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *dbClearer) clearBlobs(bs *filesystem.BlobStorage) error {
|
||||||
|
if !c.shouldProceed() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Warning("Removing blob storage")
|
||||||
|
if err := bs.Clear(); err != nil {
|
||||||
|
return errors.Wrap(err, "could not clear blob storage")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *dbClearer) clearColumns(cs *filesystem.DataColumnStorage) error {
|
||||||
|
if !c.shouldProceed() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Warning("Removing data columns storage")
|
||||||
|
if err := cs.Clear(); err != nil {
|
||||||
|
return errors.Wrap(err, "could not clear data columns storage")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *dbClearer) clearSlasher(ctx context.Context, db *slasherkv.Store) (*slasherkv.Store, error) {
|
||||||
|
if !c.shouldProceed() {
|
||||||
|
return db, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Warning("Removing slasher database")
|
||||||
|
if err := db.ClearDB(); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not clear slasher database")
|
||||||
|
}
|
||||||
|
return slasherkv.NewKVStore(ctx, db.DatabasePath())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *dbClearer) shouldProceed() bool {
|
||||||
|
if !c.shouldClear {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if c.force {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if !c.confirmed {
|
||||||
|
confirmed, err := cmd.ConfirmAction(clearConfirmation, clearDeclined)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Not clearing db due to confirmation error")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
c.confirmed = confirmed
|
||||||
|
}
|
||||||
|
return c.confirmed
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDbClearer(cliCtx *cli.Context) *dbClearer {
|
||||||
|
force := cliCtx.Bool(cmd.ForceClearDB.Name)
|
||||||
|
return &dbClearer{
|
||||||
|
shouldClear: cliCtx.Bool(cmd.ClearDB.Name) || force,
|
||||||
|
force: force,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -52,7 +52,6 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/sync/backfill"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/sync/backfill"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/sync/backfill/coverage"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/sync/backfill/coverage"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/sync/checkpoint"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/sync/checkpoint"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/sync/genesis"
|
|
||||||
initialsync "github.com/OffchainLabs/prysm/v6/beacon-chain/sync/initial-sync"
|
initialsync "github.com/OffchainLabs/prysm/v6/beacon-chain/sync/initial-sync"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/verification"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/verification"
|
||||||
"github.com/OffchainLabs/prysm/v6/cmd"
|
"github.com/OffchainLabs/prysm/v6/cmd"
|
||||||
@@ -62,6 +61,7 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
||||||
"github.com/OffchainLabs/prysm/v6/container/slice"
|
"github.com/OffchainLabs/prysm/v6/container/slice"
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/genesis"
|
||||||
"github.com/OffchainLabs/prysm/v6/monitoring/prometheus"
|
"github.com/OffchainLabs/prysm/v6/monitoring/prometheus"
|
||||||
"github.com/OffchainLabs/prysm/v6/runtime"
|
"github.com/OffchainLabs/prysm/v6/runtime"
|
||||||
"github.com/OffchainLabs/prysm/v6/runtime/prereqs"
|
"github.com/OffchainLabs/prysm/v6/runtime/prereqs"
|
||||||
@@ -113,7 +113,7 @@ type BeaconNode struct {
|
|||||||
slasherAttestationsFeed *event.Feed
|
slasherAttestationsFeed *event.Feed
|
||||||
finalizedStateAtStartUp state.BeaconState
|
finalizedStateAtStartUp state.BeaconState
|
||||||
serviceFlagOpts *serviceFlagOpts
|
serviceFlagOpts *serviceFlagOpts
|
||||||
GenesisInitializer genesis.Initializer
|
GenesisProviders []genesis.Provider
|
||||||
CheckpointInitializer checkpoint.Initializer
|
CheckpointInitializer checkpoint.Initializer
|
||||||
forkChoicer forkchoice.ForkChoicer
|
forkChoicer forkchoice.ForkChoicer
|
||||||
clockWaiter startup.ClockWaiter
|
clockWaiter startup.ClockWaiter
|
||||||
@@ -128,6 +128,7 @@ type BeaconNode struct {
|
|||||||
syncChecker *initialsync.SyncChecker
|
syncChecker *initialsync.SyncChecker
|
||||||
slasherEnabled bool
|
slasherEnabled bool
|
||||||
lcStore *lightclient.Store
|
lcStore *lightclient.Store
|
||||||
|
ConfigOptions []params.Option
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new node instance, sets up configuration options, and registers
|
// New creates a new node instance, sets up configuration options, and registers
|
||||||
@@ -136,18 +137,13 @@ func New(cliCtx *cli.Context, cancel context.CancelFunc, opts ...Option) (*Beaco
|
|||||||
if err := configureBeacon(cliCtx); err != nil {
|
if err := configureBeacon(cliCtx); err != nil {
|
||||||
return nil, errors.Wrap(err, "could not set beacon configuration options")
|
return nil, errors.Wrap(err, "could not set beacon configuration options")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initializes any forks here.
|
|
||||||
params.BeaconConfig().InitializeForkSchedule()
|
|
||||||
|
|
||||||
registry := runtime.NewServiceRegistry()
|
|
||||||
ctx := cliCtx.Context
|
ctx := cliCtx.Context
|
||||||
|
|
||||||
beacon := &BeaconNode{
|
beacon := &BeaconNode{
|
||||||
cliCtx: cliCtx,
|
cliCtx: cliCtx,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
services: registry,
|
services: runtime.NewServiceRegistry(),
|
||||||
stop: make(chan struct{}),
|
stop: make(chan struct{}),
|
||||||
stateFeed: new(event.Feed),
|
stateFeed: new(event.Feed),
|
||||||
blockFeed: new(event.Feed),
|
blockFeed: new(event.Feed),
|
||||||
@@ -176,6 +172,25 @@ func New(cliCtx *cli.Context, cancel context.CancelFunc, opts ...Option) (*Beaco
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dbClearer := newDbClearer(cliCtx)
|
||||||
|
dataDir := cliCtx.String(cmd.DataDirFlag.Name)
|
||||||
|
boltFname := filepath.Join(dataDir, kv.BeaconNodeDbDirName)
|
||||||
|
kvdb, err := openDB(ctx, boltFname, dbClearer)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not open database")
|
||||||
|
}
|
||||||
|
beacon.db = kvdb
|
||||||
|
|
||||||
|
providers := append(beacon.GenesisProviders, kv.NewLegacyGenesisProvider(kvdb))
|
||||||
|
if err := genesis.Initialize(ctx, dataDir, providers...); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not initialize genesis state")
|
||||||
|
}
|
||||||
|
|
||||||
|
beacon.ConfigOptions = append([]params.Option{params.WithGenesisValidatorsRoot(genesis.ValidatorsRoot())}, beacon.ConfigOptions...)
|
||||||
|
params.BeaconConfig().ApplyOptions(beacon.ConfigOptions...)
|
||||||
|
params.BeaconConfig().InitializeForkSchedule()
|
||||||
|
params.LogDigests(params.BeaconConfig())
|
||||||
|
|
||||||
synchronizer := startup.NewClockSynchronizer()
|
synchronizer := startup.NewClockSynchronizer()
|
||||||
beacon.clockWaiter = synchronizer
|
beacon.clockWaiter = synchronizer
|
||||||
beacon.forkChoicer = doublylinkedtree.New()
|
beacon.forkChoicer = doublylinkedtree.New()
|
||||||
@@ -194,6 +209,9 @@ func New(cliCtx *cli.Context, cancel context.CancelFunc, opts ...Option) (*Beaco
|
|||||||
}
|
}
|
||||||
beacon.BlobStorage = blobs
|
beacon.BlobStorage = blobs
|
||||||
}
|
}
|
||||||
|
if err := dbClearer.clearBlobs(beacon.BlobStorage); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not clear blob storage")
|
||||||
|
}
|
||||||
|
|
||||||
if beacon.DataColumnStorage == nil {
|
if beacon.DataColumnStorage == nil {
|
||||||
dataColumnStorage, err := filesystem.NewDataColumnStorage(cliCtx.Context, beacon.DataColumnStorageOptions...)
|
dataColumnStorage, err := filesystem.NewDataColumnStorage(cliCtx.Context, beacon.DataColumnStorageOptions...)
|
||||||
@@ -203,8 +221,11 @@ func New(cliCtx *cli.Context, cancel context.CancelFunc, opts ...Option) (*Beaco
|
|||||||
|
|
||||||
beacon.DataColumnStorage = dataColumnStorage
|
beacon.DataColumnStorage = dataColumnStorage
|
||||||
}
|
}
|
||||||
|
if err := dbClearer.clearColumns(beacon.DataColumnStorage); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not clear data column storage")
|
||||||
|
}
|
||||||
|
|
||||||
bfs, err := startBaseServices(cliCtx, beacon, depositAddress)
|
bfs, err := startBaseServices(cliCtx, beacon, depositAddress, dbClearer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "could not start modules")
|
return nil, errors.Wrap(err, "could not start modules")
|
||||||
}
|
}
|
||||||
@@ -288,7 +309,7 @@ func configureBeacon(cliCtx *cli.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func startBaseServices(cliCtx *cli.Context, beacon *BeaconNode, depositAddress string) (*backfill.Store, error) {
|
func startBaseServices(cliCtx *cli.Context, beacon *BeaconNode, depositAddress string, clearer *dbClearer) (*backfill.Store, error) {
|
||||||
ctx := cliCtx.Context
|
ctx := cliCtx.Context
|
||||||
log.Debugln("Starting DB")
|
log.Debugln("Starting DB")
|
||||||
if err := beacon.startDB(cliCtx, depositAddress); err != nil {
|
if err := beacon.startDB(cliCtx, depositAddress); err != nil {
|
||||||
@@ -296,9 +317,10 @@ func startBaseServices(cliCtx *cli.Context, beacon *BeaconNode, depositAddress s
|
|||||||
}
|
}
|
||||||
|
|
||||||
beacon.BlobStorage.WarmCache()
|
beacon.BlobStorage.WarmCache()
|
||||||
|
beacon.DataColumnStorage.WarmCache()
|
||||||
|
|
||||||
log.Debugln("Starting Slashing DB")
|
log.Debugln("Starting Slashing DB")
|
||||||
if err := beacon.startSlasherDB(cliCtx); err != nil {
|
if err := beacon.startSlasherDB(cliCtx, clearer); err != nil {
|
||||||
return nil, errors.Wrap(err, "could not start slashing DB")
|
return nil, errors.Wrap(err, "could not start slashing DB")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,43 +500,6 @@ func (b *BeaconNode) Close() {
|
|||||||
close(b.stop)
|
close(b.stop)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BeaconNode) clearDB(clearDB, forceClearDB bool, d *kv.Store, dbPath string) (*kv.Store, error) {
|
|
||||||
var err error
|
|
||||||
clearDBConfirmed := false
|
|
||||||
|
|
||||||
if clearDB && !forceClearDB {
|
|
||||||
const (
|
|
||||||
actionText = "This will delete your beacon chain database stored in your data directory. " +
|
|
||||||
"Your database backups will not be removed - do you want to proceed? (Y/N)"
|
|
||||||
|
|
||||||
deniedText = "Database will not be deleted. No changes have been made."
|
|
||||||
)
|
|
||||||
|
|
||||||
clearDBConfirmed, err = cmd.ConfirmAction(actionText, deniedText)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "could not confirm action")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if clearDBConfirmed || forceClearDB {
|
|
||||||
log.Warning("Removing database")
|
|
||||||
if err := d.ClearDB(); err != nil {
|
|
||||||
return nil, errors.Wrap(err, "could not clear database")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := b.BlobStorage.Clear(); err != nil {
|
|
||||||
return nil, errors.Wrap(err, "could not clear blob storage")
|
|
||||||
}
|
|
||||||
|
|
||||||
d, err = kv.NewKVStore(b.ctx, dbPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "could not create new database")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return d, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *BeaconNode) checkAndSaveDepositContract(depositAddress string) error {
|
func (b *BeaconNode) checkAndSaveDepositContract(depositAddress string) error {
|
||||||
knownContract, err := b.db.DepositContractAddress(b.ctx)
|
knownContract, err := b.db.DepositContractAddress(b.ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -538,60 +523,36 @@ func (b *BeaconNode) checkAndSaveDepositContract(depositAddress string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BeaconNode) startDB(cliCtx *cli.Context, depositAddress string) error {
|
func openDB(ctx context.Context, dbPath string, clearer *dbClearer) (*kv.Store, error) {
|
||||||
var depositCache cache.DepositCache
|
|
||||||
|
|
||||||
baseDir := cliCtx.String(cmd.DataDirFlag.Name)
|
|
||||||
dbPath := filepath.Join(baseDir, kv.BeaconNodeDbDirName)
|
|
||||||
clearDBRequired := cliCtx.Bool(cmd.ClearDB.Name)
|
|
||||||
forceClearDBRequired := cliCtx.Bool(cmd.ForceClearDB.Name)
|
|
||||||
|
|
||||||
log.WithField("databasePath", dbPath).Info("Checking DB")
|
log.WithField("databasePath", dbPath).Info("Checking DB")
|
||||||
|
|
||||||
d, err := kv.NewKVStore(b.ctx, dbPath)
|
d, err := kv.NewKVStore(ctx, dbPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "could not create database at %s", dbPath)
|
return nil, errors.Wrapf(err, "could not create database at %s", dbPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
if clearDBRequired || forceClearDBRequired {
|
d, err = clearer.clearKV(ctx, d)
|
||||||
d, err = b.clearDB(clearDBRequired, forceClearDBRequired, d, dbPath)
|
if err != nil {
|
||||||
if err != nil {
|
return nil, errors.Wrap(err, "could not clear database")
|
||||||
return errors.Wrap(err, "could not clear database")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := d.RunMigrations(b.ctx); err != nil {
|
return d, d.RunMigrations(ctx)
|
||||||
return err
|
}
|
||||||
}
|
|
||||||
|
|
||||||
b.db = d
|
func (b *BeaconNode) startDB(cliCtx *cli.Context, depositAddress string) error {
|
||||||
|
depositCache, err := depositsnapshot.New()
|
||||||
depositCache, err = depositsnapshot.New()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "could not create deposit cache")
|
return errors.Wrap(err, "could not create deposit cache")
|
||||||
}
|
}
|
||||||
|
|
||||||
b.depositCache = depositCache
|
b.depositCache = depositCache
|
||||||
|
|
||||||
if b.GenesisInitializer != nil {
|
|
||||||
if err := b.GenesisInitializer.Initialize(b.ctx, d); err != nil {
|
|
||||||
if errors.Is(err, db.ErrExistingGenesisState) {
|
|
||||||
return errors.Errorf("Genesis state flag specified but a genesis state "+
|
|
||||||
"exists already. Run again with --%s and/or ensure you are using the "+
|
|
||||||
"appropriate testnet flag to load the given genesis state.", cmd.ClearDB.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors.Wrap(err, "could not load genesis from file")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := b.db.EnsureEmbeddedGenesis(b.ctx); err != nil {
|
if err := b.db.EnsureEmbeddedGenesis(b.ctx); err != nil {
|
||||||
return errors.Wrap(err, "could not ensure embedded genesis")
|
return errors.Wrap(err, "could not ensure embedded genesis")
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.CheckpointInitializer != nil {
|
if b.CheckpointInitializer != nil {
|
||||||
log.Info("Checkpoint sync - Downloading origin state and block")
|
log.Info("Checkpoint sync - Downloading origin state and block")
|
||||||
if err := b.CheckpointInitializer.Initialize(b.ctx, d); err != nil {
|
if err := b.CheckpointInitializer.Initialize(b.ctx, b.db); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -603,49 +564,25 @@ func (b *BeaconNode) startDB(cliCtx *cli.Context, depositAddress string) error {
|
|||||||
log.WithField("address", depositAddress).Info("Deposit contract")
|
log.WithField("address", depositAddress).Info("Deposit contract")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
func (b *BeaconNode) startSlasherDB(cliCtx *cli.Context, clearer *dbClearer) error {
|
||||||
func (b *BeaconNode) startSlasherDB(cliCtx *cli.Context) error {
|
|
||||||
if !b.slasherEnabled {
|
if !b.slasherEnabled {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
baseDir := cliCtx.String(cmd.DataDirFlag.Name)
|
baseDir := cliCtx.String(cmd.DataDirFlag.Name)
|
||||||
|
|
||||||
if cliCtx.IsSet(flags.SlasherDirFlag.Name) {
|
if cliCtx.IsSet(flags.SlasherDirFlag.Name) {
|
||||||
baseDir = cliCtx.String(flags.SlasherDirFlag.Name)
|
baseDir = cliCtx.String(flags.SlasherDirFlag.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
dbPath := filepath.Join(baseDir, kv.BeaconNodeDbDirName)
|
dbPath := filepath.Join(baseDir, kv.BeaconNodeDbDirName)
|
||||||
clearDB := cliCtx.Bool(cmd.ClearDB.Name)
|
|
||||||
forceClearDB := cliCtx.Bool(cmd.ForceClearDB.Name)
|
|
||||||
|
|
||||||
log.WithField("databasePath", dbPath).Info("Checking DB")
|
log.WithField("databasePath", dbPath).Info("Checking DB")
|
||||||
|
|
||||||
d, err := slasherkv.NewKVStore(b.ctx, dbPath)
|
d, err := slasherkv.NewKVStore(b.ctx, dbPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
clearDBConfirmed := false
|
d, err = clearer.clearSlasher(b.ctx, d)
|
||||||
if clearDB && !forceClearDB {
|
if err != nil {
|
||||||
actionText := "This will delete your beacon chain database stored in your data directory. " +
|
return errors.Wrap(err, "could not clear slasher database")
|
||||||
"Your database backups will not be removed - do you want to proceed? (Y/N)"
|
|
||||||
deniedText := "Database will not be deleted. No changes have been made."
|
|
||||||
clearDBConfirmed, err = cmd.ConfirmAction(actionText, deniedText)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if clearDBConfirmed || forceClearDB {
|
|
||||||
log.Warning("Removing database")
|
|
||||||
if err := d.ClearDB(); err != nil {
|
|
||||||
return errors.Wrap(err, "could not clear database")
|
|
||||||
}
|
|
||||||
|
|
||||||
d, err = slasherkv.NewKVStore(b.ctx, dbPath)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "could not create new database")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
b.slasherDB = d
|
b.slasherDB = d
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -883,6 +820,8 @@ func (b *BeaconNode) registerSyncService(initialSyncComplete chan struct{}, bFil
|
|||||||
regularsync.WithDataColumnStorage(b.DataColumnStorage),
|
regularsync.WithDataColumnStorage(b.DataColumnStorage),
|
||||||
regularsync.WithVerifierWaiter(b.verifyInitWaiter),
|
regularsync.WithVerifierWaiter(b.verifyInitWaiter),
|
||||||
regularsync.WithAvailableBlocker(bFillStore),
|
regularsync.WithAvailableBlocker(bFillStore),
|
||||||
|
regularsync.WithTrackedValidatorsCache(b.trackedValidatorsCache),
|
||||||
|
regularsync.WithCustodyInfo(b.custodyInfo),
|
||||||
regularsync.WithSlasherEnabled(b.slasherEnabled),
|
regularsync.WithSlasherEnabled(b.slasherEnabled),
|
||||||
regularsync.WithLightClientStore(b.lcStore),
|
regularsync.WithLightClientStore(b.lcStore),
|
||||||
)
|
)
|
||||||
@@ -908,6 +847,8 @@ func (b *BeaconNode) registerInitialSyncService(complete chan struct{}) error {
|
|||||||
ClockWaiter: b.clockWaiter,
|
ClockWaiter: b.clockWaiter,
|
||||||
InitialSyncComplete: complete,
|
InitialSyncComplete: complete,
|
||||||
BlobStorage: b.BlobStorage,
|
BlobStorage: b.BlobStorage,
|
||||||
|
DataColumnStorage: b.DataColumnStorage,
|
||||||
|
CustodyInfo: b.custodyInfo,
|
||||||
}, opts...)
|
}, opts...)
|
||||||
return b.services.RegisterService(is)
|
return b.services.RegisterService(is)
|
||||||
}
|
}
|
||||||
@@ -1002,6 +943,7 @@ func (b *BeaconNode) registerRPCService(router *http.ServeMux) error {
|
|||||||
FinalizationFetcher: chainService,
|
FinalizationFetcher: chainService,
|
||||||
BlockReceiver: chainService,
|
BlockReceiver: chainService,
|
||||||
BlobReceiver: chainService,
|
BlobReceiver: chainService,
|
||||||
|
DataColumnReceiver: chainService,
|
||||||
AttestationReceiver: chainService,
|
AttestationReceiver: chainService,
|
||||||
GenesisTimeFetcher: chainService,
|
GenesisTimeFetcher: chainService,
|
||||||
GenesisFetcher: chainService,
|
GenesisFetcher: chainService,
|
||||||
@@ -1029,6 +971,7 @@ func (b *BeaconNode) registerRPCService(router *http.ServeMux) error {
|
|||||||
Router: router,
|
Router: router,
|
||||||
ClockWaiter: b.clockWaiter,
|
ClockWaiter: b.clockWaiter,
|
||||||
BlobStorage: b.BlobStorage,
|
BlobStorage: b.BlobStorage,
|
||||||
|
DataColumnStorage: b.DataColumnStorage,
|
||||||
TrackedValidatorsCache: b.trackedValidatorsCache,
|
TrackedValidatorsCache: b.trackedValidatorsCache,
|
||||||
PayloadIDCache: b.payloadIDCache,
|
PayloadIDCache: b.payloadIDCache,
|
||||||
LCStore: b.lcStore,
|
LCStore: b.lcStore,
|
||||||
@@ -1170,6 +1113,7 @@ func (b *BeaconNode) registerPrunerService(cliCtx *cli.Context) error {
|
|||||||
|
|
||||||
func (b *BeaconNode) RegisterBackfillService(cliCtx *cli.Context, bfs *backfill.Store) error {
|
func (b *BeaconNode) RegisterBackfillService(cliCtx *cli.Context, bfs *backfill.Store) error {
|
||||||
pa := peers.NewAssigner(b.fetchP2P().Peers(), b.forkChoicer)
|
pa := peers.NewAssigner(b.fetchP2P().Peers(), b.forkChoicer)
|
||||||
|
// TODO: Add backfill for data column storage
|
||||||
bf, err := backfill.NewService(cliCtx.Context, bfs, b.BlobStorage, b.clockWaiter, b.fetchP2P(), pa, b.BackfillOpts...)
|
bf, err := backfill.NewService(cliCtx.Context, bfs, b.BlobStorage, b.clockWaiter, b.fetchP2P(), pa, b.BackfillOpts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "error initializing backfill service")
|
return errors.Wrap(err, "error initializing backfill service")
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/builder"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/builder"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/db/filesystem"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/db/filesystem"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/execution"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/execution"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Option for beacon node configuration.
|
// Option for beacon node configuration.
|
||||||
@@ -51,6 +52,13 @@ func WithBlobStorageOptions(opt ...filesystem.BlobStorageOption) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WithConfigOptions(opt ...params.Option) Option {
|
||||||
|
return func(bn *BeaconNode) error {
|
||||||
|
bn.ConfigOptions = append(bn.ConfigOptions, opt...)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// WithDataColumnStorage sets the DataColumnStorage backend for the BeaconNode
|
// WithDataColumnStorage sets the DataColumnStorage backend for the BeaconNode
|
||||||
func WithDataColumnStorage(bs *filesystem.DataColumnStorage) Option {
|
func WithDataColumnStorage(bs *filesystem.DataColumnStorage) Option {
|
||||||
return func(bn *BeaconNode) error {
|
return func(bn *BeaconNode) error {
|
||||||
|
|||||||
@@ -71,7 +71,6 @@ go_library(
|
|||||||
"//monitoring/tracing:go_default_library",
|
"//monitoring/tracing:go_default_library",
|
||||||
"//monitoring/tracing/trace:go_default_library",
|
"//monitoring/tracing/trace:go_default_library",
|
||||||
"//network:go_default_library",
|
"//network:go_default_library",
|
||||||
"//network/forks:go_default_library",
|
|
||||||
"//proto/prysm/v1alpha1:go_default_library",
|
"//proto/prysm/v1alpha1:go_default_library",
|
||||||
"//proto/prysm/v1alpha1/metadata:go_default_library",
|
"//proto/prysm/v1alpha1/metadata:go_default_library",
|
||||||
"//runtime:go_default_library",
|
"//runtime:go_default_library",
|
||||||
@@ -168,7 +167,6 @@ go_test(
|
|||||||
"//crypto/hash:go_default_library",
|
"//crypto/hash:go_default_library",
|
||||||
"//encoding/bytesutil:go_default_library",
|
"//encoding/bytesutil:go_default_library",
|
||||||
"//network:go_default_library",
|
"//network:go_default_library",
|
||||||
"//network/forks:go_default_library",
|
|
||||||
"//proto/eth/v1:go_default_library",
|
"//proto/eth/v1:go_default_library",
|
||||||
"//proto/prysm/v1alpha1:go_default_library",
|
"//proto/prysm/v1alpha1:go_default_library",
|
||||||
"//proto/prysm/v1alpha1/metadata:go_default_library",
|
"//proto/prysm/v1alpha1/metadata:go_default_library",
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/crypto/hash"
|
"github.com/OffchainLabs/prysm/v6/crypto/hash"
|
||||||
"github.com/OffchainLabs/prysm/v6/monitoring/tracing"
|
"github.com/OffchainLabs/prysm/v6/monitoring/tracing"
|
||||||
"github.com/OffchainLabs/prysm/v6/monitoring/tracing/trace"
|
"github.com/OffchainLabs/prysm/v6/monitoring/tracing/trace"
|
||||||
"github.com/OffchainLabs/prysm/v6/network/forks"
|
|
||||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||||
"github.com/OffchainLabs/prysm/v6/time/slots"
|
"github.com/OffchainLabs/prysm/v6/time/slots"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@@ -279,14 +278,8 @@ func (s *Service) BroadcastLightClientOptimisticUpdate(ctx context.Context, upda
|
|||||||
return errors.New("attempted to broadcast nil light client optimistic update")
|
return errors.New("attempted to broadcast nil light client optimistic update")
|
||||||
}
|
}
|
||||||
|
|
||||||
forkDigest, err := forks.ForkDigestFromEpoch(slots.ToEpoch(update.AttestedHeader().Beacon().Slot), s.genesisValidatorsRoot)
|
digest := params.ForkDigest(slots.ToEpoch(update.AttestedHeader().Beacon().Slot))
|
||||||
if err != nil {
|
if err := s.broadcastObject(ctx, update, lcOptimisticToTopic(digest)); err != nil {
|
||||||
err := errors.Wrap(err, "could not retrieve fork digest")
|
|
||||||
tracing.AnnotateError(span, err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := s.broadcastObject(ctx, update, lcOptimisticToTopic(forkDigest)); err != nil {
|
|
||||||
log.WithError(err).Debug("Failed to broadcast light client optimistic update")
|
log.WithError(err).Debug("Failed to broadcast light client optimistic update")
|
||||||
err := errors.Wrap(err, "could not publish message")
|
err := errors.Wrap(err, "could not publish message")
|
||||||
tracing.AnnotateError(span, err)
|
tracing.AnnotateError(span, err)
|
||||||
@@ -305,13 +298,7 @@ func (s *Service) BroadcastLightClientFinalityUpdate(ctx context.Context, update
|
|||||||
return errors.New("attempted to broadcast nil light client finality update")
|
return errors.New("attempted to broadcast nil light client finality update")
|
||||||
}
|
}
|
||||||
|
|
||||||
forkDigest, err := forks.ForkDigestFromEpoch(slots.ToEpoch(update.AttestedHeader().Beacon().Slot), s.genesisValidatorsRoot)
|
forkDigest := params.ForkDigest(slots.ToEpoch(update.AttestedHeader().Beacon().Slot))
|
||||||
if err != nil {
|
|
||||||
err := errors.Wrap(err, "could not retrieve fork digest")
|
|
||||||
tracing.AnnotateError(span, err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := s.broadcastObject(ctx, update, lcFinalityToTopic(forkDigest)); err != nil {
|
if err := s.broadcastObject(ctx, update, lcFinalityToTopic(forkDigest)); err != nil {
|
||||||
log.WithError(err).Debug("Failed to broadcast light client finality update")
|
log.WithError(err).Debug("Failed to broadcast light client finality update")
|
||||||
err := errors.Wrap(err, "could not publish message")
|
err := errors.Wrap(err, "could not publish message")
|
||||||
|
|||||||
@@ -16,12 +16,13 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/peers"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/peers"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/peers/scorers"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/peers/scorers"
|
||||||
p2ptest "github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/testing"
|
p2ptest "github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/testing"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/startup"
|
||||||
"github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/flags"
|
"github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/flags"
|
||||||
fieldparams "github.com/OffchainLabs/prysm/v6/config/fieldparams"
|
fieldparams "github.com/OffchainLabs/prysm/v6/config/fieldparams"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/interfaces"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/interfaces"
|
||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/wrapper"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/wrapper"
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
||||||
"github.com/OffchainLabs/prysm/v6/network/forks"
|
|
||||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||||
testpb "github.com/OffchainLabs/prysm/v6/proto/testing"
|
testpb "github.com/OffchainLabs/prysm/v6/proto/testing"
|
||||||
"github.com/OffchainLabs/prysm/v6/runtime/version"
|
"github.com/OffchainLabs/prysm/v6/runtime/version"
|
||||||
@@ -61,6 +62,7 @@ func TestService_Broadcast(t *testing.T) {
|
|||||||
topic := "/eth2/%x/testing"
|
topic := "/eth2/%x/testing"
|
||||||
// Set a test gossip mapping for testpb.TestSimpleMessage.
|
// Set a test gossip mapping for testpb.TestSimpleMessage.
|
||||||
GossipTypeMapping[reflect.TypeOf(msg)] = topic
|
GossipTypeMapping[reflect.TypeOf(msg)] = topic
|
||||||
|
p.clock = startup.NewClock(p.genesisTime, bytesutil.ToBytes32(p.genesisValidatorsRoot))
|
||||||
digest, err := p.currentForkDigest()
|
digest, err := p.currentForkDigest()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
topic = fmt.Sprintf(topic, digest)
|
topic = fmt.Sprintf(topic, digest)
|
||||||
@@ -550,9 +552,7 @@ func TestService_BroadcastLightClientOptimisticUpdate(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
GossipTypeMapping[reflect.TypeOf(msg)] = LightClientOptimisticUpdateTopicFormat
|
GossipTypeMapping[reflect.TypeOf(msg)] = LightClientOptimisticUpdateTopicFormat
|
||||||
digest, err := forks.ForkDigestFromEpoch(slots.ToEpoch(msg.AttestedHeader().Beacon().Slot), p.genesisValidatorsRoot)
|
topic := fmt.Sprintf(LightClientOptimisticUpdateTopicFormat, params.ForkDigest(slots.ToEpoch(msg.AttestedHeader().Beacon().Slot)))
|
||||||
require.NoError(t, err)
|
|
||||||
topic := fmt.Sprintf(LightClientOptimisticUpdateTopicFormat, digest)
|
|
||||||
|
|
||||||
// External peer subscribes to the topic.
|
// External peer subscribes to the topic.
|
||||||
topic += p.Encoding().ProtocolSuffix()
|
topic += p.Encoding().ProtocolSuffix()
|
||||||
@@ -617,9 +617,7 @@ func TestService_BroadcastLightClientFinalityUpdate(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
GossipTypeMapping[reflect.TypeOf(msg)] = LightClientFinalityUpdateTopicFormat
|
GossipTypeMapping[reflect.TypeOf(msg)] = LightClientFinalityUpdateTopicFormat
|
||||||
digest, err := forks.ForkDigestFromEpoch(slots.ToEpoch(msg.AttestedHeader().Beacon().Slot), p.genesisValidatorsRoot)
|
topic := fmt.Sprintf(LightClientFinalityUpdateTopicFormat, params.ForkDigest(slots.ToEpoch(msg.AttestedHeader().Beacon().Slot)))
|
||||||
require.NoError(t, err)
|
|
||||||
topic := fmt.Sprintf(LightClientFinalityUpdateTopicFormat, digest)
|
|
||||||
|
|
||||||
// External peer subscribes to the topic.
|
// External peer subscribes to the topic.
|
||||||
topic += p.Encoding().ProtocolSuffix()
|
topic += p.Encoding().ProtocolSuffix()
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/cache"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/cache"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/peerdas"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/peerdas"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/startup"
|
||||||
"github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/flags"
|
"github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/flags"
|
||||||
"github.com/OffchainLabs/prysm/v6/config/features"
|
"github.com/OffchainLabs/prysm/v6/config/features"
|
||||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
@@ -222,29 +223,11 @@ func (s *Service) RefreshPersistentSubnets() {
|
|||||||
// Get the sync subnet bitfield in our metadata.
|
// Get the sync subnet bitfield in our metadata.
|
||||||
currentBitSInMetadata := s.Metadata().SyncnetsBitfield()
|
currentBitSInMetadata := s.Metadata().SyncnetsBitfield()
|
||||||
|
|
||||||
// Is our sync bitvector record up to date?
|
|
||||||
isBitSUpToDate := bytes.Equal(bitS, inRecordBitS) && bytes.Equal(bitS, currentBitSInMetadata)
|
isBitSUpToDate := bytes.Equal(bitS, inRecordBitS) && bytes.Equal(bitS, currentBitSInMetadata)
|
||||||
|
|
||||||
// Compare current epoch with the Fulu fork epoch.
|
// Compare current epoch with the Fulu fork epoch.
|
||||||
fuluForkEpoch := params.BeaconConfig().FuluForkEpoch
|
fuluForkEpoch := params.BeaconConfig().FuluForkEpoch
|
||||||
|
|
||||||
// We add `1` to the current epoch because we want to prepare one epoch before the Fulu fork.
|
|
||||||
if currentEpoch+1 < fuluForkEpoch {
|
|
||||||
// Altair behaviour.
|
|
||||||
if metadataVersion == version.Altair && isBitVUpToDate && isBitSUpToDate {
|
|
||||||
// Nothing to do, return early.
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some data have changed, update our record and metadata.
|
|
||||||
s.updateSubnetRecordWithMetadataV2(bitV, bitS)
|
|
||||||
|
|
||||||
// Ping all peers to inform them of new metadata
|
|
||||||
s.pingPeersAndLogEnr()
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the current custody group count.
|
// Get the current custody group count.
|
||||||
custodyGroupCount := s.cfg.CustodyInfo.ActualGroupCount()
|
custodyGroupCount := s.cfg.CustodyInfo.ActualGroupCount()
|
||||||
|
|
||||||
@@ -255,6 +238,26 @@ func (s *Service) RefreshPersistentSubnets() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We add `1` to the current epoch because we want to prepare one epoch before the Fulu fork.
|
||||||
|
if currentEpoch+1 < fuluForkEpoch {
|
||||||
|
// Is our custody group count record up to date?
|
||||||
|
isCustodyGroupCountUpToDate := custodyGroupCount == inRecordCustodyGroupCount
|
||||||
|
|
||||||
|
// Altair behaviour.
|
||||||
|
if metadataVersion == version.Altair && isBitVUpToDate && isBitSUpToDate && (!params.FuluEnabled() || isCustodyGroupCountUpToDate) {
|
||||||
|
// Nothing to do, return early.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some data have changed, update our record and metadata.
|
||||||
|
s.updateSubnetRecordWithMetadataV2(bitV, bitS, custodyGroupCount)
|
||||||
|
|
||||||
|
// Ping all peers to inform them of new metadata
|
||||||
|
s.pingPeersAndLogEnr()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Get the custody group count in our metadata.
|
// Get the custody group count in our metadata.
|
||||||
inMetadataCustodyGroupCount := s.Metadata().CustodyGroupCount()
|
inMetadataCustodyGroupCount := s.Metadata().CustodyGroupCount()
|
||||||
|
|
||||||
@@ -387,6 +390,7 @@ func (s *Service) listenForNewNodes() {
|
|||||||
s.Peers().RandomizeBackOff(peerInfo.ID)
|
s.Peers().RandomizeBackOff(peerInfo.ID)
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func(info *peer.AddrInfo) {
|
go func(info *peer.AddrInfo) {
|
||||||
|
log.WithField("enr", node.String()).WithField("peerInfo", info.String()).Debug("attempting to connect with peer")
|
||||||
if err := s.connectWithPeer(s.ctx, *info); err != nil {
|
if err := s.connectWithPeer(s.ctx, *info); err != nil {
|
||||||
log.WithError(err).Tracef("Could not connect with peer %s", info.String())
|
log.WithError(err).Tracef("Could not connect with peer %s", info.String())
|
||||||
}
|
}
|
||||||
@@ -504,8 +508,10 @@ func (s *Service) createLocalNode(
|
|||||||
localNode.SetFallbackIP(ipAddr)
|
localNode.SetFallbackIP(ipAddr)
|
||||||
localNode.SetFallbackUDP(udpPort)
|
localNode.SetFallbackUDP(udpPort)
|
||||||
|
|
||||||
localNode, err = addForkEntry(localNode, s.genesisTime, s.genesisValidatorsRoot)
|
clock := startup.NewClock(s.genesisTime, [32]byte(s.genesisValidatorsRoot))
|
||||||
if err != nil {
|
currentEntry := params.GetNetworkScheduleEntry(clock.CurrentEpoch())
|
||||||
|
nextEntry := params.NextNetworkScheduleEntry(clock.CurrentEpoch())
|
||||||
|
if err := updateENR(localNode, currentEntry, nextEntry); err != nil {
|
||||||
return nil, errors.Wrap(err, "could not add eth2 fork version entry to enr")
|
return nil, errors.Wrap(err, "could not add eth2 fork version entry to enr")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -250,7 +250,7 @@ func TestCreateLocalNode(t *testing.T) {
|
|||||||
|
|
||||||
// Check cgc config.
|
// Check cgc config.
|
||||||
custodyGroupCount := new(uint64)
|
custodyGroupCount := new(uint64)
|
||||||
require.NoError(t, localNode.Node().Record().Load(enr.WithEntry(peerdas.CustodyGroupCountEnrKey, custodyGroupCount)))
|
require.NoError(t, localNode.Node().Record().Load(enr.WithEntry(params.BeaconNetworkConfig().CustodyGroupCountKey, custodyGroupCount)))
|
||||||
require.Equal(t, params.BeaconConfig().CustodyRequirement, *custodyGroupCount)
|
require.Equal(t, params.BeaconConfig().CustodyRequirement, *custodyGroupCount)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -621,7 +621,7 @@ func checkPingCountCacheMetadataRecord(
|
|||||||
if expected.custodyGroupCount != nil {
|
if expected.custodyGroupCount != nil {
|
||||||
// Check custody subnet count in ENR.
|
// Check custody subnet count in ENR.
|
||||||
var actualCustodyGroupCount uint64
|
var actualCustodyGroupCount uint64
|
||||||
err := service.dv5Listener.LocalNode().Node().Record().Load(enr.WithEntry(peerdas.CustodyGroupCountEnrKey, &actualCustodyGroupCount))
|
err := service.dv5Listener.LocalNode().Node().Record().Load(enr.WithEntry(params.BeaconNetworkConfig().CustodyGroupCountKey, &actualCustodyGroupCount))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, *expected.custodyGroupCount, actualCustodyGroupCount)
|
require.Equal(t, *expected.custodyGroupCount, actualCustodyGroupCount)
|
||||||
|
|
||||||
|
|||||||
@@ -3,13 +3,10 @@ package p2p
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
|
|
||||||
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/startup"
|
||||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
"github.com/OffchainLabs/prysm/v6/network/forks"
|
|
||||||
pb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
pb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||||
prysmTime "github.com/OffchainLabs/prysm/v6/time"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/time/slots"
|
|
||||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
"github.com/ethereum/go-ethereum/p2p/enr"
|
"github.com/ethereum/go-ethereum/p2p/enr"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@@ -25,7 +22,9 @@ func (s *Service) currentForkDigest() ([4]byte, error) {
|
|||||||
if !s.isInitialized() {
|
if !s.isInitialized() {
|
||||||
return [4]byte{}, errors.New("state is not initialized")
|
return [4]byte{}, errors.New("state is not initialized")
|
||||||
}
|
}
|
||||||
return forks.CreateForkDigest(s.genesisTime, s.genesisValidatorsRoot)
|
|
||||||
|
clock := startup.NewClock(s.genesisTime, [32]byte(s.genesisValidatorsRoot))
|
||||||
|
return params.ForkDigest(clock.CurrentEpoch()), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compares fork ENRs between an incoming peer's record and our node's
|
// Compares fork ENRs between an incoming peer's record and our node's
|
||||||
@@ -74,41 +73,36 @@ func (s *Service) compareForkENR(record *enr.Record) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds a fork entry as an ENR record under the Ethereum consensus EnrKey for
|
func updateENR(node *enode.LocalNode, entry, next params.NetworkScheduleEntry) error {
|
||||||
// the local node. The fork entry is an ssz-encoded enrForkID type
|
|
||||||
// which takes into account the current fork version from the current
|
|
||||||
// epoch to create a fork digest, the next fork version,
|
|
||||||
// and the next fork epoch.
|
|
||||||
func addForkEntry(
|
|
||||||
node *enode.LocalNode,
|
|
||||||
genesisTime time.Time,
|
|
||||||
genesisValidatorsRoot []byte,
|
|
||||||
) (*enode.LocalNode, error) {
|
|
||||||
digest, err := forks.CreateForkDigest(genesisTime, genesisValidatorsRoot)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
currentSlot := slots.Since(genesisTime)
|
|
||||||
currentEpoch := slots.ToEpoch(currentSlot)
|
|
||||||
if prysmTime.Now().Before(genesisTime) {
|
|
||||||
currentEpoch = 0
|
|
||||||
}
|
|
||||||
nextForkVersion, nextForkEpoch, err := forks.NextForkData(currentEpoch)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
enrForkID := &pb.ENRForkID{
|
enrForkID := &pb.ENRForkID{
|
||||||
CurrentForkDigest: digest[:],
|
CurrentForkDigest: entry.ForkDigest[:],
|
||||||
NextForkVersion: nextForkVersion[:],
|
NextForkVersion: next.ForkVersion[:],
|
||||||
NextForkEpoch: nextForkEpoch,
|
NextForkEpoch: next.Epoch,
|
||||||
}
|
}
|
||||||
|
if entry.Epoch == next.Epoch {
|
||||||
|
enrForkID.NextForkEpoch = params.BeaconConfig().FarFutureEpoch
|
||||||
|
}
|
||||||
|
logFields := logrus.Fields{
|
||||||
|
"CurrentForkDigest": fmt.Sprintf("%#x", enrForkID.CurrentForkDigest),
|
||||||
|
"NextForkVersion": fmt.Sprintf("%#x", enrForkID.NextForkVersion),
|
||||||
|
"NextForkEpoch": fmt.Sprintf("%d", enrForkID.NextForkEpoch),
|
||||||
|
}
|
||||||
|
if params.BeaconConfig().FuluForkEpoch != params.BeaconConfig().FarFutureEpoch {
|
||||||
|
if entry.ForkDigest == next.ForkDigest {
|
||||||
|
node.Set(enr.WithEntry(nfdEnrKey, make([]byte, len(next.ForkDigest))))
|
||||||
|
} else {
|
||||||
|
node.Set(enr.WithEntry(nfdEnrKey, next.ForkDigest[:]))
|
||||||
|
}
|
||||||
|
logFields[nfdEnrKey] = fmt.Sprintf("%#x", next.ForkDigest)
|
||||||
|
}
|
||||||
|
log.WithFields(logFields).Info("updating ENR Fork ID")
|
||||||
enc, err := enrForkID.MarshalSSZ()
|
enc, err := enrForkID.MarshalSSZ()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
forkEntry := enr.WithEntry(eth2ENRKey, enc)
|
forkEntry := enr.WithEntry(eth2ENRKey, enc)
|
||||||
node.Set(forkEntry)
|
node.Set(forkEntry)
|
||||||
return node, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieves an enrForkID from an ENR record by key lookup
|
// Retrieves an enrForkID from an ENR record by key lookup
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ import (
|
|||||||
|
|
||||||
mock "github.com/OffchainLabs/prysm/v6/beacon-chain/blockchain/testing"
|
mock "github.com/OffchainLabs/prysm/v6/beacon-chain/blockchain/testing"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/signing"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/signing"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/startup"
|
||||||
fieldparams "github.com/OffchainLabs/prysm/v6/config/fieldparams"
|
fieldparams "github.com/OffchainLabs/prysm/v6/config/fieldparams"
|
||||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
||||||
"github.com/OffchainLabs/prysm/v6/network/forks"
|
|
||||||
pb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
pb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||||
@@ -230,10 +230,8 @@ func TestDiscv5_AddRetrieveForkEntryENR(t *testing.T) {
|
|||||||
nextForkVersion := []byte{0, 0, 0, 1}
|
nextForkVersion := []byte{0, 0, 0, 1}
|
||||||
params.OverrideBeaconConfig(c)
|
params.OverrideBeaconConfig(c)
|
||||||
|
|
||||||
genesisTime := time.Now()
|
clock := startup.NewClock(time.Now(), [32]byte{})
|
||||||
genesisValidatorsRoot := make([]byte, 32)
|
digest := params.ForkDigest(clock.CurrentEpoch())
|
||||||
digest, err := forks.CreateForkDigest(genesisTime, make([]byte, 32))
|
|
||||||
require.NoError(t, err)
|
|
||||||
enrForkID := &pb.ENRForkID{
|
enrForkID := &pb.ENRForkID{
|
||||||
CurrentForkDigest: digest[:],
|
CurrentForkDigest: digest[:],
|
||||||
NextForkVersion: nextForkVersion,
|
NextForkVersion: nextForkVersion,
|
||||||
@@ -255,7 +253,7 @@ func TestDiscv5_AddRetrieveForkEntryENR(t *testing.T) {
|
|||||||
localNode := enode.NewLocalNode(db, pkey)
|
localNode := enode.NewLocalNode(db, pkey)
|
||||||
localNode.Set(entry)
|
localNode.Set(entry)
|
||||||
|
|
||||||
want, err := signing.ComputeForkDigest([]byte{0, 0, 0, 0}, genesisValidatorsRoot)
|
want, err := signing.ComputeForkDigest([]byte{0, 0, 0, 0}, clock.GenesisValidatorsRootSlice())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
resp, err := forkEntry(localNode.Node().Record())
|
resp, err := forkEntry(localNode.Node().Record())
|
||||||
@@ -282,7 +280,11 @@ func TestAddForkEntry_Genesis(t *testing.T) {
|
|||||||
params.OverrideBeaconConfig(bCfg)
|
params.OverrideBeaconConfig(bCfg)
|
||||||
|
|
||||||
localNode := enode.NewLocalNode(db, pkey)
|
localNode := enode.NewLocalNode(db, pkey)
|
||||||
localNode, err = addForkEntry(localNode, time.Now().Add(10*time.Second), bytesutil.PadTo([]byte{'A', 'B', 'C', 'D'}, 32))
|
clock := startup.NewClock(time.Now(), bCfg.GenesisValidatorsRoot)
|
||||||
|
current := clock.CurrentEpoch()
|
||||||
|
entry := params.GetNetworkScheduleEntry(current)
|
||||||
|
next := params.GetNetworkScheduleEntry(entry.Epoch)
|
||||||
|
require.NoError(t, updateENR(localNode, entry, next))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
forkEntry, err := forkEntry(localNode.Node().Record())
|
forkEntry, err := forkEntry(localNode.Node().Record())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|||||||
@@ -10,26 +10,19 @@ import (
|
|||||||
// changes.
|
// changes.
|
||||||
func (s *Service) forkWatcher() {
|
func (s *Service) forkWatcher() {
|
||||||
slotTicker := slots.NewSlotTicker(s.genesisTime, params.BeaconConfig().SecondsPerSlot)
|
slotTicker := slots.NewSlotTicker(s.genesisTime, params.BeaconConfig().SecondsPerSlot)
|
||||||
|
var scheduleEntry params.NetworkScheduleEntry
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case currSlot := <-slotTicker.C():
|
case currSlot := <-slotTicker.C():
|
||||||
currEpoch := slots.ToEpoch(currSlot)
|
currEpoch := slots.ToEpoch(currSlot)
|
||||||
if currEpoch == params.BeaconConfig().AltairForkEpoch ||
|
newEntry := params.GetNetworkScheduleEntry(currEpoch)
|
||||||
currEpoch == params.BeaconConfig().BellatrixForkEpoch ||
|
if newEntry.ForkDigest != scheduleEntry.ForkDigest {
|
||||||
currEpoch == params.BeaconConfig().CapellaForkEpoch ||
|
nextEntry := params.NextNetworkScheduleEntry(currEpoch)
|
||||||
currEpoch == params.BeaconConfig().DenebForkEpoch ||
|
if err := updateENR(s.dv5Listener.LocalNode(), newEntry, nextEntry); err != nil {
|
||||||
currEpoch == params.BeaconConfig().ElectraForkEpoch ||
|
log.WithFields(newEntry.LogFields()).WithError(err).Error("Could not add fork entry")
|
||||||
currEpoch == params.BeaconConfig().FuluForkEpoch {
|
continue // don't replace scheduleEntry until this succeeds
|
||||||
// If we are in the fork epoch, we update our enr with
|
|
||||||
// the updated fork digest. These repeatedly does
|
|
||||||
// this over the epoch, which might be slightly wasteful
|
|
||||||
// but is fine nonetheless.
|
|
||||||
if s.dv5Listener != nil { // make sure it's not a local network
|
|
||||||
_, err := addForkEntry(s.dv5Listener.LocalNode(), s.genesisTime, s.genesisValidatorsRoot)
|
|
||||||
if err != nil {
|
|
||||||
log.WithError(err).Error("Could not add fork entry")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
scheduleEntry = newEntry
|
||||||
}
|
}
|
||||||
case <-s.ctx.Done():
|
case <-s.ctx.Done():
|
||||||
log.Debug("Context closed, exiting goroutine")
|
log.Debug("Context closed, exiting goroutine")
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/peers"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/peers"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/peers/peerdata"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/peers/peerdata"
|
||||||
prysmTime "github.com/OffchainLabs/prysm/v6/time"
|
prysmTime "github.com/OffchainLabs/prysm/v6/time"
|
||||||
|
"github.com/libp2p/go-libp2p/core/host"
|
||||||
"github.com/libp2p/go-libp2p/core/network"
|
"github.com/libp2p/go-libp2p/core/network"
|
||||||
"github.com/libp2p/go-libp2p/core/peer"
|
"github.com/libp2p/go-libp2p/core/peer"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@@ -27,6 +28,22 @@ func peerMultiaddrString(conn network.Conn) string {
|
|||||||
return fmt.Sprintf("%s/p2p/%s", remoteMultiaddr, remotePeerID)
|
return fmt.Sprintf("%s/p2p/%s", remoteMultiaddr, remotePeerID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func peerAgentString(pid peer.ID, host host.Host) string {
|
||||||
|
const unknownAgent = "unknown"
|
||||||
|
|
||||||
|
rawAgent, err := host.Peerstore().Get(pid, "AgentVersion")
|
||||||
|
if err != nil {
|
||||||
|
return unknownAgent
|
||||||
|
}
|
||||||
|
|
||||||
|
agent, ok := rawAgent.(string)
|
||||||
|
if !ok {
|
||||||
|
return unknownAgent
|
||||||
|
}
|
||||||
|
|
||||||
|
return agent
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) connectToPeer(conn network.Conn) {
|
func (s *Service) connectToPeer(conn network.Conn) {
|
||||||
s.peers.SetConnectionState(conn.RemotePeer(), peers.Connected)
|
s.peers.SetConnectionState(conn.RemotePeer(), peers.Connected)
|
||||||
// Go through the handshake process.
|
// Go through the handshake process.
|
||||||
@@ -59,6 +76,7 @@ func (s *Service) disconnectFromPeerOnError(
|
|||||||
WithError(badPeerErr).
|
WithError(badPeerErr).
|
||||||
WithFields(logrus.Fields{
|
WithFields(logrus.Fields{
|
||||||
"multiaddr": peerMultiaddrString(conn),
|
"multiaddr": peerMultiaddrString(conn),
|
||||||
|
"agent": peerAgentString(remotePeerID, s.host),
|
||||||
"direction": conn.Stat().Direction.String(),
|
"direction": conn.Stat().Direction.String(),
|
||||||
"remainingActivePeers": len(s.peers.Active()),
|
"remainingActivePeers": len(s.peers.Active()),
|
||||||
}).
|
}).
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/crypto/hash"
|
"github.com/OffchainLabs/prysm/v6/crypto/hash"
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
||||||
"github.com/OffchainLabs/prysm/v6/math"
|
"github.com/OffchainLabs/prysm/v6/math"
|
||||||
"github.com/OffchainLabs/prysm/v6/network/forks"
|
|
||||||
pubsubpb "github.com/libp2p/go-libp2p-pubsub/pb"
|
pubsubpb "github.com/libp2p/go-libp2p-pubsub/pb"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -39,7 +38,7 @@ func MsgID(genesisValidatorsRoot []byte, pmsg *pubsubpb.Message) string {
|
|||||||
copy(msg, "invalid")
|
copy(msg, "invalid")
|
||||||
return bytesutil.UnsafeCastToString(msg)
|
return bytesutil.UnsafeCastToString(msg)
|
||||||
}
|
}
|
||||||
_, fEpoch, err := forks.RetrieveForkDataFromDigest(digest, genesisValidatorsRoot)
|
_, fEpoch, err := params.ForkDataFromDigest(digest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Impossible condition that should
|
// Impossible condition that should
|
||||||
// never be hit.
|
// never be hit.
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ import (
|
|||||||
|
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/signing"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/signing"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/startup"
|
||||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
"github.com/OffchainLabs/prysm/v6/crypto/hash"
|
"github.com/OffchainLabs/prysm/v6/crypto/hash"
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
||||||
"github.com/OffchainLabs/prysm/v6/network/forks"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
||||||
"github.com/golang/snappy"
|
"github.com/golang/snappy"
|
||||||
pubsubpb "github.com/libp2p/go-libp2p-pubsub/pb"
|
pubsubpb "github.com/libp2p/go-libp2p-pubsub/pb"
|
||||||
@@ -18,22 +18,22 @@ import (
|
|||||||
|
|
||||||
func TestMsgID_HashesCorrectly(t *testing.T) {
|
func TestMsgID_HashesCorrectly(t *testing.T) {
|
||||||
params.SetupTestConfigCleanup(t)
|
params.SetupTestConfigCleanup(t)
|
||||||
genesisValidatorsRoot := bytesutil.PadTo([]byte{'A'}, 32)
|
clock := startup.NewClock(time.Now(), bytesutil.ToBytes32([]byte{'A'}))
|
||||||
d, err := forks.CreateForkDigest(time.Now(), genesisValidatorsRoot)
|
valRoot := clock.GenesisValidatorsRoot()
|
||||||
assert.NoError(t, err)
|
d := params.ForkDigest(clock.CurrentEpoch())
|
||||||
tpc := fmt.Sprintf(p2p.BlockSubnetTopicFormat, d)
|
tpc := fmt.Sprintf(p2p.BlockSubnetTopicFormat, d)
|
||||||
invalidSnappy := [32]byte{'J', 'U', 'N', 'K'}
|
invalidSnappy := [32]byte{'J', 'U', 'N', 'K'}
|
||||||
pMsg := &pubsubpb.Message{Data: invalidSnappy[:], Topic: &tpc}
|
pMsg := &pubsubpb.Message{Data: invalidSnappy[:], Topic: &tpc}
|
||||||
hashedData := hash.Hash(append(params.BeaconConfig().MessageDomainInvalidSnappy[:], pMsg.Data...))
|
hashedData := hash.Hash(append(params.BeaconConfig().MessageDomainInvalidSnappy[:], pMsg.Data...))
|
||||||
msgID := string(hashedData[:20])
|
msgID := string(hashedData[:20])
|
||||||
assert.Equal(t, msgID, p2p.MsgID(genesisValidatorsRoot, pMsg), "Got incorrect msg id")
|
assert.Equal(t, msgID, p2p.MsgID(valRoot[:], pMsg), "Got incorrect msg id")
|
||||||
|
|
||||||
validObj := [32]byte{'v', 'a', 'l', 'i', 'd'}
|
validObj := [32]byte{'v', 'a', 'l', 'i', 'd'}
|
||||||
enc := snappy.Encode(nil, validObj[:])
|
enc := snappy.Encode(nil, validObj[:])
|
||||||
nMsg := &pubsubpb.Message{Data: enc, Topic: &tpc}
|
nMsg := &pubsubpb.Message{Data: enc, Topic: &tpc}
|
||||||
hashedData = hash.Hash(append(params.BeaconConfig().MessageDomainValidSnappy[:], validObj[:]...))
|
hashedData = hash.Hash(append(params.BeaconConfig().MessageDomainValidSnappy[:], validObj[:]...))
|
||||||
msgID = string(hashedData[:20])
|
msgID = string(hashedData[:20])
|
||||||
assert.Equal(t, msgID, p2p.MsgID(genesisValidatorsRoot, nMsg), "Got incorrect msg id")
|
assert.Equal(t, msgID, p2p.MsgID(valRoot[:], nMsg), "Got incorrect msg id")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMessageIDFunction_HashesCorrectlyAltair(t *testing.T) {
|
func TestMessageIDFunction_HashesCorrectlyAltair(t *testing.T) {
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ type PeerData struct {
|
|||||||
NextValidTime time.Time
|
NextValidTime time.Time
|
||||||
// Chain related data.
|
// Chain related data.
|
||||||
MetaData metadata.Metadata
|
MetaData metadata.Metadata
|
||||||
ChainState *ethpb.Status
|
ChainState *ethpb.StatusV2
|
||||||
ChainStateLastUpdated time.Time
|
ChainStateLastUpdated time.Time
|
||||||
ChainStateValidationError error
|
ChainStateValidationError error
|
||||||
// Scorers internal data.
|
// Scorers internal data.
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import (
|
|||||||
|
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/peers/peerdata"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/peers/peerdata"
|
||||||
"github.com/libp2p/go-libp2p/core/peer"
|
"github.com/libp2p/go-libp2p/core/peer"
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ Scorer = (*BadResponsesScorer)(nil)
|
var _ Scorer = (*BadResponsesScorer)(nil)
|
||||||
@@ -129,13 +128,14 @@ func (s *BadResponsesScorer) IsBadPeer(pid peer.ID) error {
|
|||||||
|
|
||||||
// isBadPeerNoLock is lock-free version of IsBadPeer.
|
// isBadPeerNoLock is lock-free version of IsBadPeer.
|
||||||
func (s *BadResponsesScorer) isBadPeerNoLock(pid peer.ID) error {
|
func (s *BadResponsesScorer) isBadPeerNoLock(pid peer.ID) error {
|
||||||
if peerData, ok := s.store.PeerData(pid); ok {
|
// if peerData, ok := s.store.PeerData(pid); ok {
|
||||||
if peerData.BadResponses >= s.config.Threshold {
|
// TODO: Remote this out of devnet
|
||||||
return errors.Errorf("peer exceeded bad responses threshold: got %d, threshold %d", peerData.BadResponses, s.config.Threshold)
|
// if peerData.BadResponses >= s.config.Threshold {
|
||||||
}
|
// return errors.Errorf("peer exceeded bad responses threshold: got %d, threshold %d", peerData.BadResponses, s.config.Threshold)
|
||||||
|
// }
|
||||||
|
|
||||||
return nil
|
// return nil
|
||||||
}
|
// }
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package scorers_test
|
package scorers_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sort"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/peers"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/peers"
|
||||||
@@ -13,39 +12,41 @@ import (
|
|||||||
"github.com/libp2p/go-libp2p/core/peer"
|
"github.com/libp2p/go-libp2p/core/peer"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestScorers_BadResponses_Score(t *testing.T) {
|
// TODO: Uncomment when out of devnet
|
||||||
const pid = "peer1"
|
// func TestScorers_BadResponses_Score(t *testing.T) {
|
||||||
|
// const pid = "peer1"
|
||||||
|
|
||||||
ctx := t.Context()
|
// ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
// defer cancel()
|
||||||
|
|
||||||
peerStatuses := peers.NewStatus(ctx, &peers.StatusConfig{
|
// peerStatuses := peers.NewStatus(ctx, &peers.StatusConfig{
|
||||||
PeerLimit: 30,
|
// PeerLimit: 30,
|
||||||
ScorerParams: &scorers.Config{
|
// ScorerParams: &scorers.Config{
|
||||||
BadResponsesScorerConfig: &scorers.BadResponsesScorerConfig{
|
// BadResponsesScorerConfig: &scorers.BadResponsesScorerConfig{
|
||||||
Threshold: 4,
|
// Threshold: 4,
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
})
|
// })
|
||||||
scorer := peerStatuses.Scorers().BadResponsesScorer()
|
// scorer := peerStatuses.Scorers().BadResponsesScorer()
|
||||||
|
|
||||||
assert.Equal(t, 0., scorer.Score(pid), "Unexpected score for unregistered peer")
|
// assert.Equal(t, 0., scorer.Score(pid), "Unexpected score for unregistered peer")
|
||||||
|
|
||||||
scorer.Increment(pid)
|
// scorer.Increment(pid)
|
||||||
assert.NoError(t, scorer.IsBadPeer(pid))
|
// assert.NoError(t, scorer.IsBadPeer(pid))
|
||||||
assert.Equal(t, -2.5, scorer.Score(pid))
|
// assert.Equal(t, -2.5, scorer.Score(pid))
|
||||||
|
|
||||||
scorer.Increment(pid)
|
// scorer.Increment(pid)
|
||||||
assert.NoError(t, scorer.IsBadPeer(pid))
|
// assert.NoError(t, scorer.IsBadPeer(pid))
|
||||||
assert.Equal(t, float64(-5), scorer.Score(pid))
|
// assert.Equal(t, float64(-5), scorer.Score(pid))
|
||||||
|
|
||||||
scorer.Increment(pid)
|
// scorer.Increment(pid)
|
||||||
assert.NoError(t, scorer.IsBadPeer(pid))
|
// assert.NoError(t, scorer.IsBadPeer(pid))
|
||||||
assert.Equal(t, float64(-7.5), scorer.Score(pid))
|
// assert.Equal(t, float64(-7.5), scorer.Score(pid))
|
||||||
|
|
||||||
scorer.Increment(pid)
|
// scorer.Increment(pid)
|
||||||
assert.NotNil(t, scorer.IsBadPeer(pid))
|
// assert.NotNil(t, scorer.IsBadPeer(pid))
|
||||||
assert.Equal(t, -100.0, scorer.Score(pid))
|
// assert.Equal(t, -100.0, scorer.Score(pid))
|
||||||
}
|
// }
|
||||||
|
|
||||||
func TestScorers_BadResponses_ParamsThreshold(t *testing.T) {
|
func TestScorers_BadResponses_ParamsThreshold(t *testing.T) {
|
||||||
ctx := t.Context()
|
ctx := t.Context()
|
||||||
@@ -137,56 +138,60 @@ func TestScorers_BadResponses_Decay(t *testing.T) {
|
|||||||
assert.Equal(t, 1, badResponses, "unexpected bad responses for pid3")
|
assert.Equal(t, 1, badResponses, "unexpected bad responses for pid3")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestScorers_BadResponses_IsBadPeer(t *testing.T) {
|
// TODO: Uncomment when out of devnet
|
||||||
ctx := t.Context()
|
// func TestScorers_BadResponses_IsBadPeer(t *testing.T) {
|
||||||
|
// ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
// defer cancel()
|
||||||
|
|
||||||
peerStatuses := peers.NewStatus(ctx, &peers.StatusConfig{
|
// peerStatuses := peers.NewStatus(ctx, &peers.StatusConfig{
|
||||||
PeerLimit: 30,
|
// PeerLimit: 30,
|
||||||
ScorerParams: &scorers.Config{},
|
// ScorerParams: &scorers.Config{},
|
||||||
})
|
// })
|
||||||
scorer := peerStatuses.Scorers().BadResponsesScorer()
|
// scorer := peerStatuses.Scorers().BadResponsesScorer()
|
||||||
pid := peer.ID("peer1")
|
// pid := peer.ID("peer1")
|
||||||
assert.NoError(t, scorer.IsBadPeer(pid))
|
// assert.NoError(t, scorer.IsBadPeer(pid))
|
||||||
|
|
||||||
peerStatuses.Add(nil, pid, nil, network.DirUnknown)
|
// peerStatuses.Add(nil, pid, nil, network.DirUnknown)
|
||||||
assert.NoError(t, scorer.IsBadPeer(pid))
|
// assert.NoError(t, scorer.IsBadPeer(pid))
|
||||||
|
|
||||||
for i := 0; i < scorers.DefaultBadResponsesThreshold; i++ {
|
// for i := 0; i < scorers.DefaultBadResponsesThreshold; i++ {
|
||||||
scorer.Increment(pid)
|
// scorer.Increment(pid)
|
||||||
if i == scorers.DefaultBadResponsesThreshold-1 {
|
// if i == scorers.DefaultBadResponsesThreshold-1 {
|
||||||
assert.NotNil(t, scorer.IsBadPeer(pid), "Unexpected peer status")
|
// assert.NotNil(t, scorer.IsBadPeer(pid), "Unexpected peer status")
|
||||||
} else {
|
// } else {
|
||||||
assert.NoError(t, scorer.IsBadPeer(pid), "Unexpected peer status")
|
// assert.NoError(t, scorer.IsBadPeer(pid), "Unexpected peer status")
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
func TestScorers_BadResponses_BadPeers(t *testing.T) {
|
// TODO: Uncomment when out of devnet
|
||||||
ctx := t.Context()
|
// func TestScorers_BadResponses_BadPeers(t *testing.T) {
|
||||||
|
// ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
// defer cancel()
|
||||||
|
|
||||||
peerStatuses := peers.NewStatus(ctx, &peers.StatusConfig{
|
// peerStatuses := peers.NewStatus(ctx, &peers.StatusConfig{
|
||||||
PeerLimit: 30,
|
// PeerLimit: 30,
|
||||||
ScorerParams: &scorers.Config{},
|
// ScorerParams: &scorers.Config{},
|
||||||
})
|
// })
|
||||||
scorer := peerStatuses.Scorers().BadResponsesScorer()
|
// scorer := peerStatuses.Scorers().BadResponsesScorer()
|
||||||
pids := []peer.ID{peer.ID("peer1"), peer.ID("peer2"), peer.ID("peer3"), peer.ID("peer4"), peer.ID("peer5")}
|
// pids := []peer.ID{peer.ID("peer1"), peer.ID("peer2"), peer.ID("peer3"), peer.ID("peer4"), peer.ID("peer5")}
|
||||||
for i := 0; i < len(pids); i++ {
|
// for i := 0; i < len(pids); i++ {
|
||||||
peerStatuses.Add(nil, pids[i], nil, network.DirUnknown)
|
// peerStatuses.Add(nil, pids[i], nil, network.DirUnknown)
|
||||||
}
|
// }
|
||||||
for i := 0; i < scorers.DefaultBadResponsesThreshold; i++ {
|
// for i := 0; i < scorers.DefaultBadResponsesThreshold; i++ {
|
||||||
scorer.Increment(pids[1])
|
// scorer.Increment(pids[1])
|
||||||
scorer.Increment(pids[2])
|
// scorer.Increment(pids[2])
|
||||||
scorer.Increment(pids[4])
|
// scorer.Increment(pids[4])
|
||||||
}
|
// }
|
||||||
assert.NoError(t, scorer.IsBadPeer(pids[0]), "Invalid peer status")
|
// assert.NoError(t, scorer.IsBadPeer(pids[0]), "Invalid peer status")
|
||||||
assert.NotNil(t, scorer.IsBadPeer(pids[1]), "Invalid peer status")
|
// assert.NotNil(t, scorer.IsBadPeer(pids[1]), "Invalid peer status")
|
||||||
assert.NotNil(t, scorer.IsBadPeer(pids[2]), "Invalid peer status")
|
// assert.NotNil(t, scorer.IsBadPeer(pids[2]), "Invalid peer status")
|
||||||
assert.NoError(t, scorer.IsBadPeer(pids[3]), "Invalid peer status")
|
// assert.NoError(t, scorer.IsBadPeer(pids[3]), "Invalid peer status")
|
||||||
assert.NotNil(t, scorer.IsBadPeer(pids[4]), "Invalid peer status")
|
// assert.NotNil(t, scorer.IsBadPeer(pids[4]), "Invalid peer status")
|
||||||
want := []peer.ID{pids[1], pids[2], pids[4]}
|
// want := []peer.ID{pids[1], pids[2], pids[4]}
|
||||||
badPeers := scorer.BadPeers()
|
// badPeers := scorer.BadPeers()
|
||||||
sort.Slice(badPeers, func(i, j int) bool {
|
// sort.Slice(badPeers, func(i, j int) bool {
|
||||||
return badPeers[i] < badPeers[j]
|
// return badPeers[i] < badPeers[j]
|
||||||
})
|
// })
|
||||||
assert.DeepEqual(t, want, badPeers, "Unexpected list of bad peers")
|
// assert.DeepEqual(t, want, badPeers, "Unexpected list of bad peers")
|
||||||
}
|
// }
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ func TestScorers_Gossip_Score(t *testing.T) {
|
|||||||
},
|
},
|
||||||
check: func(scorer *scorers.GossipScorer) {
|
check: func(scorer *scorers.GossipScorer) {
|
||||||
assert.Equal(t, 10.0, scorer.Score("peer1"), "Unexpected score")
|
assert.Equal(t, 10.0, scorer.Score("peer1"), "Unexpected score")
|
||||||
assert.Equal(t, nil, scorer.IsBadPeer("peer1"), "Unexpected bad peer")
|
assert.NoError(t, scorer.IsBadPeer("peer1"), "Unexpected bad peer")
|
||||||
_, _, topicMap, err := scorer.GossipData("peer1")
|
_, _, topicMap, err := scorer.GossipData("peer1")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, uint64(100), topicMap["a"].TimeInMesh, "incorrect time in mesh")
|
assert.Equal(t, uint64(100), topicMap["a"].TimeInMesh, "incorrect time in mesh")
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ func (s *PeerStatusScorer) BadPeers() []peer.ID {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetPeerStatus sets chain state data for a given peer.
|
// SetPeerStatus sets chain state data for a given peer.
|
||||||
func (s *PeerStatusScorer) SetPeerStatus(pid peer.ID, chainState *pb.Status, validationError error) {
|
func (s *PeerStatusScorer) SetPeerStatus(pid peer.ID, chainState *pb.StatusV2, validationError error) {
|
||||||
s.store.Lock()
|
s.store.Lock()
|
||||||
defer s.store.Unlock()
|
defer s.store.Unlock()
|
||||||
|
|
||||||
@@ -130,14 +130,14 @@ func (s *PeerStatusScorer) SetPeerStatus(pid peer.ID, chainState *pb.Status, val
|
|||||||
// PeerStatus gets the chain state of the given remote peer.
|
// PeerStatus gets the chain state of the given remote peer.
|
||||||
// This can return nil if there is no known chain state for the peer.
|
// This can return nil if there is no known chain state for the peer.
|
||||||
// This will error if the peer does not exist.
|
// This will error if the peer does not exist.
|
||||||
func (s *PeerStatusScorer) PeerStatus(pid peer.ID) (*pb.Status, error) {
|
func (s *PeerStatusScorer) PeerStatus(pid peer.ID) (*pb.StatusV2, error) {
|
||||||
s.store.RLock()
|
s.store.RLock()
|
||||||
defer s.store.RUnlock()
|
defer s.store.RUnlock()
|
||||||
return s.peerStatusNoLock(pid)
|
return s.peerStatusNoLock(pid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// peerStatusNoLock lock-free version of PeerStatus.
|
// peerStatusNoLock lock-free version of PeerStatus.
|
||||||
func (s *PeerStatusScorer) peerStatusNoLock(pid peer.ID) (*pb.Status, error) {
|
func (s *PeerStatusScorer) peerStatusNoLock(pid peer.ID) (*pb.StatusV2, error) {
|
||||||
if peerData, ok := s.store.PeerData(pid); ok {
|
if peerData, ok := s.store.PeerData(pid); ok {
|
||||||
if peerData.ChainState == nil {
|
if peerData.ChainState == nil {
|
||||||
return nil, peerdata.ErrNoPeerStatus
|
return nil, peerdata.ErrNoPeerStatus
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ func TestScorers_PeerStatus_Score(t *testing.T) {
|
|||||||
name: "existent bad peer",
|
name: "existent bad peer",
|
||||||
update: func(scorer *scorers.PeerStatusScorer) {
|
update: func(scorer *scorers.PeerStatusScorer) {
|
||||||
scorer.SetHeadSlot(0)
|
scorer.SetHeadSlot(0)
|
||||||
scorer.SetPeerStatus("peer1", &pb.Status{
|
scorer.SetPeerStatus("peer1", &pb.StatusV2{
|
||||||
HeadRoot: make([]byte, 32),
|
HeadRoot: make([]byte, 32),
|
||||||
HeadSlot: 64,
|
HeadSlot: 64,
|
||||||
}, p2ptypes.ErrWrongForkDigestVersion)
|
}, p2ptypes.ErrWrongForkDigestVersion)
|
||||||
@@ -48,7 +48,7 @@ func TestScorers_PeerStatus_Score(t *testing.T) {
|
|||||||
name: "existent peer no head slot for the host node is known",
|
name: "existent peer no head slot for the host node is known",
|
||||||
update: func(scorer *scorers.PeerStatusScorer) {
|
update: func(scorer *scorers.PeerStatusScorer) {
|
||||||
scorer.SetHeadSlot(0)
|
scorer.SetHeadSlot(0)
|
||||||
scorer.SetPeerStatus("peer1", &pb.Status{
|
scorer.SetPeerStatus("peer1", &pb.StatusV2{
|
||||||
HeadRoot: make([]byte, 32),
|
HeadRoot: make([]byte, 32),
|
||||||
HeadSlot: 64,
|
HeadSlot: 64,
|
||||||
}, nil)
|
}, nil)
|
||||||
@@ -61,7 +61,7 @@ func TestScorers_PeerStatus_Score(t *testing.T) {
|
|||||||
name: "existent peer head is before ours",
|
name: "existent peer head is before ours",
|
||||||
update: func(scorer *scorers.PeerStatusScorer) {
|
update: func(scorer *scorers.PeerStatusScorer) {
|
||||||
scorer.SetHeadSlot(128)
|
scorer.SetHeadSlot(128)
|
||||||
scorer.SetPeerStatus("peer1", &pb.Status{
|
scorer.SetPeerStatus("peer1", &pb.StatusV2{
|
||||||
HeadRoot: make([]byte, 32),
|
HeadRoot: make([]byte, 32),
|
||||||
HeadSlot: 64,
|
HeadSlot: 64,
|
||||||
}, nil)
|
}, nil)
|
||||||
@@ -75,12 +75,12 @@ func TestScorers_PeerStatus_Score(t *testing.T) {
|
|||||||
update: func(scorer *scorers.PeerStatusScorer) {
|
update: func(scorer *scorers.PeerStatusScorer) {
|
||||||
headSlot := primitives.Slot(128)
|
headSlot := primitives.Slot(128)
|
||||||
scorer.SetHeadSlot(headSlot)
|
scorer.SetHeadSlot(headSlot)
|
||||||
scorer.SetPeerStatus("peer1", &pb.Status{
|
scorer.SetPeerStatus("peer1", &pb.StatusV2{
|
||||||
HeadRoot: make([]byte, 32),
|
HeadRoot: make([]byte, 32),
|
||||||
HeadSlot: headSlot + 64,
|
HeadSlot: headSlot + 64,
|
||||||
}, nil)
|
}, nil)
|
||||||
// Set another peer to a higher score.
|
// Set another peer to a higher score.
|
||||||
scorer.SetPeerStatus("peer2", &pb.Status{
|
scorer.SetPeerStatus("peer2", &pb.StatusV2{
|
||||||
HeadRoot: make([]byte, 32),
|
HeadRoot: make([]byte, 32),
|
||||||
HeadSlot: headSlot + 128,
|
HeadSlot: headSlot + 128,
|
||||||
}, nil)
|
}, nil)
|
||||||
@@ -95,7 +95,7 @@ func TestScorers_PeerStatus_Score(t *testing.T) {
|
|||||||
update: func(scorer *scorers.PeerStatusScorer) {
|
update: func(scorer *scorers.PeerStatusScorer) {
|
||||||
headSlot := primitives.Slot(128)
|
headSlot := primitives.Slot(128)
|
||||||
scorer.SetHeadSlot(headSlot)
|
scorer.SetHeadSlot(headSlot)
|
||||||
scorer.SetPeerStatus("peer1", &pb.Status{
|
scorer.SetPeerStatus("peer1", &pb.StatusV2{
|
||||||
HeadRoot: make([]byte, 32),
|
HeadRoot: make([]byte, 32),
|
||||||
HeadSlot: headSlot + 64,
|
HeadSlot: headSlot + 64,
|
||||||
}, nil)
|
}, nil)
|
||||||
@@ -108,7 +108,7 @@ func TestScorers_PeerStatus_Score(t *testing.T) {
|
|||||||
name: "existent peer no max known slot",
|
name: "existent peer no max known slot",
|
||||||
update: func(scorer *scorers.PeerStatusScorer) {
|
update: func(scorer *scorers.PeerStatusScorer) {
|
||||||
scorer.SetHeadSlot(0)
|
scorer.SetHeadSlot(0)
|
||||||
scorer.SetPeerStatus("peer1", &pb.Status{
|
scorer.SetPeerStatus("peer1", &pb.StatusV2{
|
||||||
HeadRoot: make([]byte, 32),
|
HeadRoot: make([]byte, 32),
|
||||||
HeadSlot: 0,
|
HeadSlot: 0,
|
||||||
}, nil)
|
}, nil)
|
||||||
@@ -141,7 +141,7 @@ func TestScorers_PeerStatus_IsBadPeer(t *testing.T) {
|
|||||||
assert.NoError(t, peerStatuses.Scorers().IsBadPeer(pid))
|
assert.NoError(t, peerStatuses.Scorers().IsBadPeer(pid))
|
||||||
assert.NoError(t, peerStatuses.Scorers().PeerStatusScorer().IsBadPeer(pid))
|
assert.NoError(t, peerStatuses.Scorers().PeerStatusScorer().IsBadPeer(pid))
|
||||||
|
|
||||||
peerStatuses.Scorers().PeerStatusScorer().SetPeerStatus(pid, &pb.Status{}, p2ptypes.ErrWrongForkDigestVersion)
|
peerStatuses.Scorers().PeerStatusScorer().SetPeerStatus(pid, &pb.StatusV2{}, p2ptypes.ErrWrongForkDigestVersion)
|
||||||
assert.NotNil(t, peerStatuses.Scorers().IsBadPeer(pid))
|
assert.NotNil(t, peerStatuses.Scorers().IsBadPeer(pid))
|
||||||
assert.NotNil(t, peerStatuses.Scorers().PeerStatusScorer().IsBadPeer(pid))
|
assert.NotNil(t, peerStatuses.Scorers().PeerStatusScorer().IsBadPeer(pid))
|
||||||
}
|
}
|
||||||
@@ -160,9 +160,9 @@ func TestScorers_PeerStatus_BadPeers(t *testing.T) {
|
|||||||
assert.NoError(t, peerStatuses.Scorers().IsBadPeer(pid3))
|
assert.NoError(t, peerStatuses.Scorers().IsBadPeer(pid3))
|
||||||
assert.NoError(t, peerStatuses.Scorers().PeerStatusScorer().IsBadPeer(pid3))
|
assert.NoError(t, peerStatuses.Scorers().PeerStatusScorer().IsBadPeer(pid3))
|
||||||
|
|
||||||
peerStatuses.Scorers().PeerStatusScorer().SetPeerStatus(pid1, &pb.Status{}, p2ptypes.ErrWrongForkDigestVersion)
|
peerStatuses.Scorers().PeerStatusScorer().SetPeerStatus(pid1, &pb.StatusV2{}, p2ptypes.ErrWrongForkDigestVersion)
|
||||||
peerStatuses.Scorers().PeerStatusScorer().SetPeerStatus(pid2, &pb.Status{}, nil)
|
peerStatuses.Scorers().PeerStatusScorer().SetPeerStatus(pid2, &pb.StatusV2{}, nil)
|
||||||
peerStatuses.Scorers().PeerStatusScorer().SetPeerStatus(pid3, &pb.Status{}, p2ptypes.ErrWrongForkDigestVersion)
|
peerStatuses.Scorers().PeerStatusScorer().SetPeerStatus(pid3, &pb.StatusV2{}, p2ptypes.ErrWrongForkDigestVersion)
|
||||||
assert.NotNil(t, peerStatuses.Scorers().IsBadPeer(pid1))
|
assert.NotNil(t, peerStatuses.Scorers().IsBadPeer(pid1))
|
||||||
assert.NotNil(t, peerStatuses.Scorers().PeerStatusScorer().IsBadPeer(pid1))
|
assert.NotNil(t, peerStatuses.Scorers().PeerStatusScorer().IsBadPeer(pid1))
|
||||||
assert.NoError(t, peerStatuses.Scorers().IsBadPeer(pid2))
|
assert.NoError(t, peerStatuses.Scorers().IsBadPeer(pid2))
|
||||||
@@ -179,12 +179,12 @@ func TestScorers_PeerStatus_PeerStatus(t *testing.T) {
|
|||||||
})
|
})
|
||||||
status, err := peerStatuses.Scorers().PeerStatusScorer().PeerStatus("peer1")
|
status, err := peerStatuses.Scorers().PeerStatusScorer().PeerStatus("peer1")
|
||||||
require.ErrorContains(t, peerdata.ErrPeerUnknown.Error(), err)
|
require.ErrorContains(t, peerdata.ErrPeerUnknown.Error(), err)
|
||||||
assert.Equal(t, (*pb.Status)(nil), status)
|
assert.Equal(t, (*pb.StatusV2)(nil), status)
|
||||||
|
|
||||||
peerStatuses.Scorers().PeerStatusScorer().SetPeerStatus("peer1", &pb.Status{
|
peerStatuses.Scorers().PeerStatusScorer().SetPeerStatus("peer1", &pb.StatusV2{
|
||||||
HeadSlot: 128,
|
HeadSlot: 128,
|
||||||
}, nil)
|
}, nil)
|
||||||
peerStatuses.Scorers().PeerStatusScorer().SetPeerStatus("peer2", &pb.Status{
|
peerStatuses.Scorers().PeerStatusScorer().SetPeerStatus("peer2", &pb.StatusV2{
|
||||||
HeadSlot: 128,
|
HeadSlot: 128,
|
||||||
}, p2ptypes.ErrInvalidEpoch)
|
}, p2ptypes.ErrInvalidEpoch)
|
||||||
status, err = peerStatuses.Scorers().PeerStatusScorer().PeerStatus("peer1")
|
status, err = peerStatuses.Scorers().PeerStatusScorer().PeerStatus("peer1")
|
||||||
|
|||||||
@@ -211,99 +211,102 @@ func TestScorers_Service_Score(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestScorers_Service_loop(t *testing.T) {
|
// TODO: Uncomment when out of devnet
|
||||||
ctx, cancel := context.WithTimeout(t.Context(), 3*time.Second)
|
// func TestScorers_Service_loop(t *testing.T) {
|
||||||
defer cancel()
|
// ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
|
// defer cancel()
|
||||||
|
|
||||||
peerStatuses := peers.NewStatus(ctx, &peers.StatusConfig{
|
// peerStatuses := peers.NewStatus(ctx, &peers.StatusConfig{
|
||||||
PeerLimit: 30,
|
// PeerLimit: 30,
|
||||||
ScorerParams: &scorers.Config{
|
// ScorerParams: &scorers.Config{
|
||||||
BadResponsesScorerConfig: &scorers.BadResponsesScorerConfig{
|
// BadResponsesScorerConfig: &scorers.BadResponsesScorerConfig{
|
||||||
Threshold: 5,
|
// Threshold: 5,
|
||||||
DecayInterval: 50 * time.Millisecond,
|
// DecayInterval: 50 * time.Millisecond,
|
||||||
},
|
// },
|
||||||
BlockProviderScorerConfig: &scorers.BlockProviderScorerConfig{
|
// BlockProviderScorerConfig: &scorers.BlockProviderScorerConfig{
|
||||||
DecayInterval: 25 * time.Millisecond,
|
// DecayInterval: 25 * time.Millisecond,
|
||||||
Decay: 64,
|
// Decay: 64,
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
})
|
// })
|
||||||
s1 := peerStatuses.Scorers().BadResponsesScorer()
|
// s1 := peerStatuses.Scorers().BadResponsesScorer()
|
||||||
s2 := peerStatuses.Scorers().BlockProviderScorer()
|
// s2 := peerStatuses.Scorers().BlockProviderScorer()
|
||||||
|
|
||||||
pid1 := peer.ID("peer1")
|
// pid1 := peer.ID("peer1")
|
||||||
peerStatuses.Add(nil, pid1, nil, network.DirUnknown)
|
// peerStatuses.Add(nil, pid1, nil, network.DirUnknown)
|
||||||
for i := 0; i < s1.Params().Threshold+5; i++ {
|
// for i := 0; i < s1.Params().Threshold+5; i++ {
|
||||||
s1.Increment(pid1)
|
// s1.Increment(pid1)
|
||||||
}
|
// }
|
||||||
assert.NotNil(t, s1.IsBadPeer(pid1), "Peer should be marked as bad")
|
// assert.NotNil(t, s1.IsBadPeer(pid1), "Peer should be marked as bad")
|
||||||
|
|
||||||
s2.IncrementProcessedBlocks("peer1", 221)
|
// s2.IncrementProcessedBlocks("peer1", 221)
|
||||||
assert.Equal(t, uint64(221), s2.ProcessedBlocks("peer1"))
|
// assert.Equal(t, uint64(221), s2.ProcessedBlocks("peer1"))
|
||||||
|
|
||||||
done := make(chan struct{}, 1)
|
// done := make(chan struct{}, 1)
|
||||||
go func() {
|
// go func() {
|
||||||
defer func() {
|
// defer func() {
|
||||||
done <- struct{}{}
|
// done <- struct{}{}
|
||||||
}()
|
// }()
|
||||||
ticker := time.NewTicker(50 * time.Millisecond)
|
// ticker := time.NewTicker(50 * time.Millisecond)
|
||||||
defer ticker.Stop()
|
// defer ticker.Stop()
|
||||||
for {
|
// for {
|
||||||
select {
|
// select {
|
||||||
case <-ticker.C:
|
// case <-ticker.C:
|
||||||
if s1.IsBadPeer(pid1) == nil && s2.ProcessedBlocks("peer1") == 0 {
|
// if s1.IsBadPeer(pid1) == nil && s2.ProcessedBlocks("peer1") == 0 {
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
case <-ctx.Done():
|
// case <-ctx.Done():
|
||||||
t.Error("Timed out")
|
// t.Error("Timed out")
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}()
|
// }()
|
||||||
|
|
||||||
<-done
|
// <-done
|
||||||
assert.NoError(t, s1.IsBadPeer(pid1), "Peer should not be marked as bad")
|
// assert.NoError(t, s1.IsBadPeer(pid1), "Peer should not be marked as bad")
|
||||||
assert.Equal(t, uint64(0), s2.ProcessedBlocks("peer1"), "No blocks are expected")
|
// assert.Equal(t, uint64(0), s2.ProcessedBlocks("peer1"), "No blocks are expected")
|
||||||
}
|
// }
|
||||||
|
|
||||||
func TestScorers_Service_IsBadPeer(t *testing.T) {
|
// TODO: Uncomment when out of devnet
|
||||||
peerStatuses := peers.NewStatus(t.Context(), &peers.StatusConfig{
|
// func TestScorers_Service_IsBadPeer(t *testing.T) {
|
||||||
PeerLimit: 30,
|
// peerStatuses := peers.NewStatus(context.Background(), &peers.StatusConfig{
|
||||||
ScorerParams: &scorers.Config{
|
// PeerLimit: 30,
|
||||||
BadResponsesScorerConfig: &scorers.BadResponsesScorerConfig{
|
// ScorerParams: &scorers.Config{
|
||||||
Threshold: 2,
|
// BadResponsesScorerConfig: &scorers.BadResponsesScorerConfig{
|
||||||
DecayInterval: 50 * time.Second,
|
// Threshold: 2,
|
||||||
},
|
// DecayInterval: 50 * time.Second,
|
||||||
},
|
// },
|
||||||
})
|
// },
|
||||||
|
// })
|
||||||
|
|
||||||
assert.NoError(t, peerStatuses.Scorers().IsBadPeer("peer1"))
|
// assert.NoError(t, peerStatuses.Scorers().IsBadPeer("peer1"))
|
||||||
peerStatuses.Scorers().BadResponsesScorer().Increment("peer1")
|
// peerStatuses.Scorers().BadResponsesScorer().Increment("peer1")
|
||||||
peerStatuses.Scorers().BadResponsesScorer().Increment("peer1")
|
// peerStatuses.Scorers().BadResponsesScorer().Increment("peer1")
|
||||||
assert.NotNil(t, peerStatuses.Scorers().IsBadPeer("peer1"))
|
// assert.NotNil(t, peerStatuses.Scorers().IsBadPeer("peer1"))
|
||||||
}
|
// }
|
||||||
|
|
||||||
func TestScorers_Service_BadPeers(t *testing.T) {
|
// TODO: Uncomment when out of devnet
|
||||||
peerStatuses := peers.NewStatus(t.Context(), &peers.StatusConfig{
|
// func TestScorers_Service_BadPeers(t *testing.T) {
|
||||||
PeerLimit: 30,
|
// peerStatuses := peers.NewStatus(context.Background(), &peers.StatusConfig{
|
||||||
ScorerParams: &scorers.Config{
|
// PeerLimit: 30,
|
||||||
BadResponsesScorerConfig: &scorers.BadResponsesScorerConfig{
|
// ScorerParams: &scorers.Config{
|
||||||
Threshold: 2,
|
// BadResponsesScorerConfig: &scorers.BadResponsesScorerConfig{
|
||||||
DecayInterval: 50 * time.Second,
|
// Threshold: 2,
|
||||||
},
|
// DecayInterval: 50 * time.Second,
|
||||||
},
|
// },
|
||||||
})
|
// },
|
||||||
|
// })
|
||||||
|
|
||||||
assert.NoError(t, peerStatuses.Scorers().IsBadPeer("peer1"))
|
// assert.NoError(t, peerStatuses.Scorers().IsBadPeer("peer1"))
|
||||||
assert.NoError(t, peerStatuses.Scorers().IsBadPeer("peer2"))
|
// assert.NoError(t, peerStatuses.Scorers().IsBadPeer("peer2"))
|
||||||
assert.NoError(t, peerStatuses.Scorers().IsBadPeer("peer3"))
|
// assert.NoError(t, peerStatuses.Scorers().IsBadPeer("peer3"))
|
||||||
assert.Equal(t, 0, len(peerStatuses.Scorers().BadPeers()))
|
// assert.Equal(t, 0, len(peerStatuses.Scorers().BadPeers()))
|
||||||
for _, pid := range []peer.ID{"peer1", "peer3"} {
|
// for _, pid := range []peer.ID{"peer1", "peer3"} {
|
||||||
peerStatuses.Scorers().BadResponsesScorer().Increment(pid)
|
// peerStatuses.Scorers().BadResponsesScorer().Increment(pid)
|
||||||
peerStatuses.Scorers().BadResponsesScorer().Increment(pid)
|
// peerStatuses.Scorers().BadResponsesScorer().Increment(pid)
|
||||||
}
|
// }
|
||||||
assert.NotNil(t, peerStatuses.Scorers().IsBadPeer("peer1"))
|
// assert.NotNil(t, peerStatuses.Scorers().IsBadPeer("peer1"))
|
||||||
assert.NoError(t, peerStatuses.Scorers().IsBadPeer("peer2"))
|
// assert.NoError(t, peerStatuses.Scorers().IsBadPeer("peer2"))
|
||||||
assert.NotNil(t, peerStatuses.Scorers().IsBadPeer("peer3"))
|
// assert.NotNil(t, peerStatuses.Scorers().IsBadPeer("peer3"))
|
||||||
assert.Equal(t, 2, len(peerStatuses.Scorers().BadPeers()))
|
// assert.Equal(t, 2, len(peerStatuses.Scorers().BadPeers()))
|
||||||
}
|
// }
|
||||||
|
|||||||
@@ -205,14 +205,14 @@ func (p *Status) ENR(pid peer.ID) (*enr.Record, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetChainState sets the chain state of the given remote peer.
|
// SetChainState sets the chain state of the given remote peer.
|
||||||
func (p *Status) SetChainState(pid peer.ID, chainState *pb.Status) {
|
func (p *Status) SetChainState(pid peer.ID, chainState *pb.StatusV2) {
|
||||||
p.scorers.PeerStatusScorer().SetPeerStatus(pid, chainState, nil)
|
p.scorers.PeerStatusScorer().SetPeerStatus(pid, chainState, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChainState gets the chain state of the given remote peer.
|
// ChainState gets the chain state of the given remote peer.
|
||||||
// This will error if the peer does not exist.
|
// This will error if the peer does not exist.
|
||||||
// This will error if there is no known chain state for the peer.
|
// This will error if there is no known chain state for the peer.
|
||||||
func (p *Status) ChainState(pid peer.ID) (*pb.Status, error) {
|
func (p *Status) ChainState(pid peer.ID) (*pb.StatusV2, error) {
|
||||||
return p.scorers.PeerStatusScorer().PeerStatus(pid)
|
return p.scorers.PeerStatusScorer().PeerStatus(pid)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -705,31 +705,47 @@ func (p *Status) deprecatedPrune() {
|
|||||||
p.tallyIPTracker()
|
p.tallyIPTracker()
|
||||||
}
|
}
|
||||||
|
|
||||||
// BestFinalized returns the highest finalized epoch equal to or higher than ours that is agreed
|
// BestFinalized returns the highest finalized epoch equal to or higher than `ourFinalizedEpoch`
|
||||||
// upon by the majority of peers. This method may not return the absolute highest finalized, but
|
// that is agreed upon by the majority of peers, and the peers agreeing on this finalized epoch.
|
||||||
// the finalized epoch in which most peers can serve blocks (plurality voting).
|
// This method may not return the absolute highest finalized epoch, but the finalized epoch in which
|
||||||
// Ideally, all peers would be reporting the same finalized epoch but some may be behind due to their
|
// most peers can serve blocks (plurality voting). Ideally, all peers would be reporting the same
|
||||||
// own latency, or because of their finalized epoch at the time we queried them.
|
// finalized epoch but some may be behind due to their own latency, or because of their finalized
|
||||||
// Returns epoch number and list of peers that are at or beyond that epoch.
|
// epoch at the time we queried them. Returns epoch number and list of peers that are at or beyond
|
||||||
|
// that epoch.
|
||||||
func (p *Status) BestFinalized(maxPeers int, ourFinalizedEpoch primitives.Epoch) (primitives.Epoch, []peer.ID) {
|
func (p *Status) BestFinalized(maxPeers int, ourFinalizedEpoch primitives.Epoch) (primitives.Epoch, []peer.ID) {
|
||||||
|
// Retrieve all connected peers.
|
||||||
connected := p.Connected()
|
connected := p.Connected()
|
||||||
|
|
||||||
|
// key: finalized epoch, value: number of peers that support this finalized epoch.
|
||||||
finalizedEpochVotes := make(map[primitives.Epoch]uint64)
|
finalizedEpochVotes := make(map[primitives.Epoch]uint64)
|
||||||
|
|
||||||
|
// key: peer ID, value: finalized epoch of the peer.
|
||||||
pidEpoch := make(map[peer.ID]primitives.Epoch, len(connected))
|
pidEpoch := make(map[peer.ID]primitives.Epoch, len(connected))
|
||||||
|
|
||||||
|
// key: peer ID, value: head slot of the peer.
|
||||||
pidHead := make(map[peer.ID]primitives.Slot, len(connected))
|
pidHead := make(map[peer.ID]primitives.Slot, len(connected))
|
||||||
|
|
||||||
potentialPIDs := make([]peer.ID, 0, len(connected))
|
potentialPIDs := make([]peer.ID, 0, len(connected))
|
||||||
for _, pid := range connected {
|
for _, pid := range connected {
|
||||||
peerChainState, err := p.ChainState(pid)
|
peerChainState, err := p.ChainState(pid)
|
||||||
if err == nil && peerChainState != nil && peerChainState.FinalizedEpoch >= ourFinalizedEpoch {
|
|
||||||
finalizedEpochVotes[peerChainState.FinalizedEpoch]++
|
// Skip if the peer's finalized epoch is not defined, or if the peer's finalized epoch is
|
||||||
pidEpoch[pid] = peerChainState.FinalizedEpoch
|
// lower than ours.
|
||||||
potentialPIDs = append(potentialPIDs, pid)
|
if err != nil || peerChainState == nil || peerChainState.FinalizedEpoch < ourFinalizedEpoch {
|
||||||
pidHead[pid] = peerChainState.HeadSlot
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
finalizedEpochVotes[peerChainState.FinalizedEpoch]++
|
||||||
|
|
||||||
|
pidEpoch[pid] = peerChainState.FinalizedEpoch
|
||||||
|
pidHead[pid] = peerChainState.HeadSlot
|
||||||
|
|
||||||
|
potentialPIDs = append(potentialPIDs, pid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select the target epoch, which is the epoch most peers agree upon.
|
// Select the target epoch, which is the epoch most peers agree upon.
|
||||||
var targetEpoch primitives.Epoch
|
// If there is a tie, select the highest epoch.
|
||||||
var mostVotes uint64
|
targetEpoch, mostVotes := primitives.Epoch(0), uint64(0)
|
||||||
for epoch, count := range finalizedEpochVotes {
|
for epoch, count := range finalizedEpochVotes {
|
||||||
if count > mostVotes || (count == mostVotes && epoch > targetEpoch) {
|
if count > mostVotes || (count == mostVotes && epoch > targetEpoch) {
|
||||||
mostVotes = count
|
mostVotes = count
|
||||||
@@ -737,11 +753,12 @@ func (p *Status) BestFinalized(maxPeers int, ourFinalizedEpoch primitives.Epoch)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort PIDs by finalized epoch, in decreasing order.
|
// Sort PIDs by finalized (epoch, head), in decreasing order.
|
||||||
sort.Slice(potentialPIDs, func(i, j int) bool {
|
sort.Slice(potentialPIDs, func(i, j int) bool {
|
||||||
if pidEpoch[potentialPIDs[i]] == pidEpoch[potentialPIDs[j]] {
|
if pidEpoch[potentialPIDs[i]] == pidEpoch[potentialPIDs[j]] {
|
||||||
return pidHead[potentialPIDs[i]] > pidHead[potentialPIDs[j]]
|
return pidHead[potentialPIDs[i]] > pidHead[potentialPIDs[j]]
|
||||||
}
|
}
|
||||||
|
|
||||||
return pidEpoch[potentialPIDs[i]] > pidEpoch[potentialPIDs[j]]
|
return pidEpoch[potentialPIDs[i]] > pidEpoch[potentialPIDs[j]]
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -764,26 +781,42 @@ func (p *Status) BestFinalized(maxPeers int, ourFinalizedEpoch primitives.Epoch)
|
|||||||
// BestNonFinalized returns the highest known epoch, higher than ours,
|
// BestNonFinalized returns the highest known epoch, higher than ours,
|
||||||
// and is shared by at least minPeers.
|
// and is shared by at least minPeers.
|
||||||
func (p *Status) BestNonFinalized(minPeers int, ourHeadEpoch primitives.Epoch) (primitives.Epoch, []peer.ID) {
|
func (p *Status) BestNonFinalized(minPeers int, ourHeadEpoch primitives.Epoch) (primitives.Epoch, []peer.ID) {
|
||||||
|
// Retrieve all connected peers.
|
||||||
connected := p.Connected()
|
connected := p.Connected()
|
||||||
|
|
||||||
|
// Calculate our head slot.
|
||||||
|
slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch
|
||||||
|
ourHeadSlot := slotsPerEpoch.Mul(uint64(ourHeadEpoch))
|
||||||
|
|
||||||
|
// key: head epoch, value: number of peers that support this epoch.
|
||||||
epochVotes := make(map[primitives.Epoch]uint64)
|
epochVotes := make(map[primitives.Epoch]uint64)
|
||||||
|
|
||||||
|
// key: peer ID, value: head epoch of the peer.
|
||||||
pidEpoch := make(map[peer.ID]primitives.Epoch, len(connected))
|
pidEpoch := make(map[peer.ID]primitives.Epoch, len(connected))
|
||||||
|
|
||||||
|
// key: peer ID, value: head slot of the peer.
|
||||||
pidHead := make(map[peer.ID]primitives.Slot, len(connected))
|
pidHead := make(map[peer.ID]primitives.Slot, len(connected))
|
||||||
|
|
||||||
potentialPIDs := make([]peer.ID, 0, len(connected))
|
potentialPIDs := make([]peer.ID, 0, len(connected))
|
||||||
|
|
||||||
ourHeadSlot := params.BeaconConfig().SlotsPerEpoch.Mul(uint64(ourHeadEpoch))
|
|
||||||
for _, pid := range connected {
|
for _, pid := range connected {
|
||||||
peerChainState, err := p.ChainState(pid)
|
peerChainState, err := p.ChainState(pid)
|
||||||
if err == nil && peerChainState != nil && peerChainState.HeadSlot > ourHeadSlot {
|
// Skip if the peer's head epoch is not defined, or if the peer's head slot is
|
||||||
epoch := slots.ToEpoch(peerChainState.HeadSlot)
|
// lower or equal than ours.
|
||||||
epochVotes[epoch]++
|
if err != nil || peerChainState == nil || peerChainState.HeadSlot <= ourHeadSlot {
|
||||||
pidEpoch[pid] = epoch
|
continue
|
||||||
pidHead[pid] = peerChainState.HeadSlot
|
|
||||||
potentialPIDs = append(potentialPIDs, pid)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
epoch := slots.ToEpoch(peerChainState.HeadSlot)
|
||||||
|
|
||||||
|
epochVotes[epoch]++
|
||||||
|
pidEpoch[pid] = epoch
|
||||||
|
pidHead[pid] = peerChainState.HeadSlot
|
||||||
|
potentialPIDs = append(potentialPIDs, pid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select the target epoch, which has enough peers' votes (>= minPeers).
|
// Select the target epoch, which has enough peers' votes (>= minPeers).
|
||||||
var targetEpoch primitives.Epoch
|
targetEpoch := primitives.Epoch(0)
|
||||||
for epoch, votes := range epochVotes {
|
for epoch, votes := range epochVotes {
|
||||||
if votes >= uint64(minPeers) && targetEpoch < epoch {
|
if votes >= uint64(minPeers) && targetEpoch < epoch {
|
||||||
targetEpoch = epoch
|
targetEpoch = epoch
|
||||||
@@ -1012,16 +1045,23 @@ func (p *Status) isfromBadIP(pid peer.ID) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ip, err := manet.ToIP(peerData.Address)
|
// ip, err := manet.ToIP(peerData.Address)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return errors.Wrap(err, "to ip")
|
// return errors.Wrap(err, "to ip")
|
||||||
}
|
// }
|
||||||
|
|
||||||
if val, ok := p.ipTracker[ip.String()]; ok {
|
// if val, ok := p.ipTracker[ip.String()]; ok {
|
||||||
if val > CollocationLimit {
|
// if val > CollocationLimit {
|
||||||
return errors.Errorf("collocation limit exceeded: got %d - limit %d", val, CollocationLimit)
|
// TODO: Remove this out of denvet.
|
||||||
}
|
// return errors.Errorf("colocation limit exceeded: got %d - limit %d", val, CollocationLimit)
|
||||||
}
|
// log.WithFields(logrus.Fields{
|
||||||
|
// "pid": pid,
|
||||||
|
// "ip": ip.String(),
|
||||||
|
// "colocationCount": val,
|
||||||
|
// "colocationLimit": CollocationLimit,
|
||||||
|
// }).Debug("Colocation limit exceeded. Peer should be banned.")
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package peers_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"strconv"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -289,7 +288,7 @@ func TestPeerChainState(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
finalizedEpoch := primitives.Epoch(123)
|
finalizedEpoch := primitives.Epoch(123)
|
||||||
p.SetChainState(id, &pb.Status{FinalizedEpoch: finalizedEpoch})
|
p.SetChainState(id, &pb.StatusV2{FinalizedEpoch: finalizedEpoch})
|
||||||
|
|
||||||
resChainState, err := p.ChainState(id)
|
resChainState, err := p.ChainState(id)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -324,59 +323,60 @@ func TestPeerWithNilChainState(t *testing.T) {
|
|||||||
|
|
||||||
resChainState, err := p.ChainState(id)
|
resChainState, err := p.ChainState(id)
|
||||||
require.Equal(t, peerdata.ErrNoPeerStatus, err)
|
require.Equal(t, peerdata.ErrNoPeerStatus, err)
|
||||||
var nothing *pb.Status
|
var nothing *pb.StatusV2
|
||||||
require.Equal(t, resChainState, nothing)
|
require.Equal(t, resChainState, nothing)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPeerBadResponses(t *testing.T) {
|
// TODO: Uncomment when out of devnet
|
||||||
maxBadResponses := 2
|
// func TestPeerBadResponses(t *testing.T) {
|
||||||
p := peers.NewStatus(t.Context(), &peers.StatusConfig{
|
// maxBadResponses := 2
|
||||||
PeerLimit: 30,
|
// p := peers.NewStatus(context.Background(), &peers.StatusConfig{
|
||||||
ScorerParams: &scorers.Config{
|
// PeerLimit: 30,
|
||||||
BadResponsesScorerConfig: &scorers.BadResponsesScorerConfig{
|
// ScorerParams: &scorers.Config{
|
||||||
Threshold: maxBadResponses,
|
// BadResponsesScorerConfig: &scorers.BadResponsesScorerConfig{
|
||||||
},
|
// Threshold: maxBadResponses,
|
||||||
},
|
// },
|
||||||
})
|
// },
|
||||||
|
// })
|
||||||
|
|
||||||
id, err := peer.Decode("16Uiu2HAkyWZ4Ni1TpvDS8dPxsozmHY85KaiFjodQuV6Tz5tkHVeR")
|
// id, err := peer.Decode("16Uiu2HAkyWZ4Ni1TpvDS8dPxsozmHY85KaiFjodQuV6Tz5tkHVeR")
|
||||||
require.NoError(t, err)
|
// require.NoError(t, err)
|
||||||
{
|
// {
|
||||||
_, err := id.MarshalBinary()
|
// _, err := id.MarshalBinary()
|
||||||
require.NoError(t, err)
|
// require.NoError(t, err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
assert.NoError(t, p.IsBad(id), "Peer marked as bad when should be good")
|
// assert.NoError(t, p.IsBad(id), "Peer marked as bad when should be good")
|
||||||
|
|
||||||
address, err := ma.NewMultiaddr("/ip4/213.202.254.180/tcp/13000")
|
// address, err := ma.NewMultiaddr("/ip4/213.202.254.180/tcp/13000")
|
||||||
require.NoError(t, err, "Failed to create address")
|
// require.NoError(t, err, "Failed to create address")
|
||||||
direction := network.DirInbound
|
// direction := network.DirInbound
|
||||||
p.Add(new(enr.Record), id, address, direction)
|
// p.Add(new(enr.Record), id, address, direction)
|
||||||
|
|
||||||
scorer := p.Scorers().BadResponsesScorer()
|
// scorer := p.Scorers().BadResponsesScorer()
|
||||||
resBadResponses, err := scorer.Count(id)
|
// resBadResponses, err := scorer.Count(id)
|
||||||
require.NoError(t, err)
|
// require.NoError(t, err)
|
||||||
assert.Equal(t, 0, resBadResponses, "Unexpected bad responses")
|
// assert.Equal(t, 0, resBadResponses, "Unexpected bad responses")
|
||||||
assert.NoError(t, p.IsBad(id), "Peer marked as bad when should be good")
|
// assert.NoError(t, p.IsBad(id), "Peer marked as bad when should be good")
|
||||||
|
|
||||||
scorer.Increment(id)
|
// scorer.Increment(id)
|
||||||
resBadResponses, err = scorer.Count(id)
|
// resBadResponses, err = scorer.Count(id)
|
||||||
require.NoError(t, err)
|
// require.NoError(t, err)
|
||||||
assert.Equal(t, 1, resBadResponses, "Unexpected bad responses")
|
// assert.Equal(t, 1, resBadResponses, "Unexpected bad responses")
|
||||||
assert.NoError(t, p.IsBad(id), "Peer marked as bad when should be good")
|
// assert.NoError(t, p.IsBad(id), "Peer marked as bad when should be good")
|
||||||
|
|
||||||
scorer.Increment(id)
|
// scorer.Increment(id)
|
||||||
resBadResponses, err = scorer.Count(id)
|
// resBadResponses, err = scorer.Count(id)
|
||||||
require.NoError(t, err)
|
// require.NoError(t, err)
|
||||||
assert.Equal(t, 2, resBadResponses, "Unexpected bad responses")
|
// assert.Equal(t, 2, resBadResponses, "Unexpected bad responses")
|
||||||
assert.NotNil(t, p.IsBad(id), "Peer not marked as bad when it should be")
|
// assert.NotNil(t, p.IsBad(id), "Peer not marked as bad when it should be")
|
||||||
|
|
||||||
scorer.Increment(id)
|
// scorer.Increment(id)
|
||||||
resBadResponses, err = scorer.Count(id)
|
// resBadResponses, err = scorer.Count(id)
|
||||||
require.NoError(t, err)
|
// require.NoError(t, err)
|
||||||
assert.Equal(t, 3, resBadResponses, "Unexpected bad responses")
|
// assert.Equal(t, 3, resBadResponses, "Unexpected bad responses")
|
||||||
assert.NotNil(t, p.IsBad(id), "Peer not marked as bad when it should be")
|
// assert.NotNil(t, p.IsBad(id), "Peer not marked as bad when it should be")
|
||||||
}
|
// }
|
||||||
|
|
||||||
func TestAddMetaData(t *testing.T) {
|
func TestAddMetaData(t *testing.T) {
|
||||||
maxBadResponses := 2
|
maxBadResponses := 2
|
||||||
@@ -495,100 +495,102 @@ func TestPeerValidTime(t *testing.T) {
|
|||||||
assert.Equal(t, numPeersConnected, len(p.Connected()), "Unexpected number of connected peers")
|
assert.Equal(t, numPeersConnected, len(p.Connected()), "Unexpected number of connected peers")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPrune(t *testing.T) {
|
// TODO: Uncomment when out of devnet
|
||||||
maxBadResponses := 2
|
// func TestPrune(t *testing.T) {
|
||||||
p := peers.NewStatus(t.Context(), &peers.StatusConfig{
|
// maxBadResponses := 2
|
||||||
PeerLimit: 30,
|
// p := peers.NewStatus(context.Background(), &peers.StatusConfig{
|
||||||
ScorerParams: &scorers.Config{
|
// PeerLimit: 30,
|
||||||
BadResponsesScorerConfig: &scorers.BadResponsesScorerConfig{
|
// ScorerParams: &scorers.Config{
|
||||||
Threshold: maxBadResponses,
|
// BadResponsesScorerConfig: &scorers.BadResponsesScorerConfig{
|
||||||
},
|
// Threshold: maxBadResponses,
|
||||||
},
|
// },
|
||||||
})
|
// },
|
||||||
|
// })
|
||||||
|
|
||||||
for i := 0; i < p.MaxPeerLimit()+100; i++ {
|
// for i := 0; i < p.MaxPeerLimit()+100; i++ {
|
||||||
if i%7 == 0 {
|
// if i%7 == 0 {
|
||||||
// Peer added as disconnected.
|
// // Peer added as disconnected.
|
||||||
_ = addPeer(t, p, peers.Disconnected)
|
// _ = addPeer(t, p, peers.PeerDisconnected)
|
||||||
}
|
// }
|
||||||
// Peer added to peer handler.
|
// // Peer added to peer handler.
|
||||||
_ = addPeer(t, p, peers.Connected)
|
// _ = addPeer(t, p, peers.PeerConnected)
|
||||||
}
|
// }
|
||||||
|
|
||||||
disPeers := p.Disconnected()
|
// disPeers := p.Disconnected()
|
||||||
firstPID := disPeers[0]
|
// firstPID := disPeers[0]
|
||||||
secondPID := disPeers[1]
|
// secondPID := disPeers[1]
|
||||||
thirdPID := disPeers[2]
|
// thirdPID := disPeers[2]
|
||||||
|
|
||||||
scorer := p.Scorers().BadResponsesScorer()
|
// scorer := p.Scorers().BadResponsesScorer()
|
||||||
|
|
||||||
// Make first peer a bad peer
|
// // Make first peer a bad peer
|
||||||
scorer.Increment(firstPID)
|
// scorer.Increment(firstPID)
|
||||||
scorer.Increment(firstPID)
|
// scorer.Increment(firstPID)
|
||||||
|
|
||||||
// Add bad response for p2.
|
// // Add bad response for p2.
|
||||||
scorer.Increment(secondPID)
|
// scorer.Increment(secondPID)
|
||||||
|
|
||||||
// Prune peers
|
// // Prune peers
|
||||||
p.Prune()
|
// p.Prune()
|
||||||
|
|
||||||
// Bad peer is expected to still be kept in handler.
|
// // Bad peer is expected to still be kept in handler.
|
||||||
badRes, err := scorer.Count(firstPID)
|
// badRes, err := scorer.Count(firstPID)
|
||||||
assert.NoError(t, err, "error is supposed to be nil")
|
// assert.NoError(t, err, "error is supposed to be nil")
|
||||||
assert.Equal(t, 2, badRes, "Did not get expected amount")
|
// assert.Equal(t, 2, badRes, "Did not get expected amount")
|
||||||
|
|
||||||
// Not so good peer is pruned away so that we can reduce the
|
// // Not so good peer is pruned away so that we can reduce the
|
||||||
// total size of the handler.
|
// // total size of the handler.
|
||||||
_, err = scorer.Count(secondPID)
|
// _, err = scorer.Count(secondPID)
|
||||||
assert.ErrorContains(t, "peer unknown", err)
|
// assert.ErrorContains(t, "peer unknown", err)
|
||||||
|
|
||||||
// Last peer has been removed.
|
// // Last peer has been removed.
|
||||||
_, err = scorer.Count(thirdPID)
|
// _, err = scorer.Count(thirdPID)
|
||||||
assert.ErrorContains(t, "peer unknown", err)
|
// assert.ErrorContains(t, "peer unknown", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
func TestPeerIPTracker(t *testing.T) {
|
// TODO: Uncomment when out of devnet
|
||||||
resetCfg := features.InitWithReset(&features.Flags{
|
// func TestPeerIPTracker(t *testing.T) {
|
||||||
EnablePeerScorer: false,
|
// resetCfg := features.InitWithReset(&features.Flags{
|
||||||
})
|
// EnablePeerScorer: false,
|
||||||
defer resetCfg()
|
// })
|
||||||
maxBadResponses := 2
|
// defer resetCfg()
|
||||||
p := peers.NewStatus(t.Context(), &peers.StatusConfig{
|
// maxBadResponses := 2
|
||||||
PeerLimit: 30,
|
// p := peers.NewStatus(context.Background(), &peers.StatusConfig{
|
||||||
ScorerParams: &scorers.Config{
|
// PeerLimit: 30,
|
||||||
BadResponsesScorerConfig: &scorers.BadResponsesScorerConfig{
|
// ScorerParams: &scorers.Config{
|
||||||
Threshold: maxBadResponses,
|
// BadResponsesScorerConfig: &scorers.BadResponsesScorerConfig{
|
||||||
},
|
// Threshold: maxBadResponses,
|
||||||
},
|
// },
|
||||||
})
|
// },
|
||||||
|
// })
|
||||||
|
|
||||||
badIP := "211.227.218.116"
|
// badIP := "211.227.218.116"
|
||||||
var badPeers []peer.ID
|
// var badPeers []peer.ID
|
||||||
for i := 0; i < peers.CollocationLimit+10; i++ {
|
// for i := 0; i < peers.CollocationLimit+10; i++ {
|
||||||
port := strconv.Itoa(3000 + i)
|
// port := strconv.Itoa(3000 + i)
|
||||||
addr, err := ma.NewMultiaddr("/ip4/" + badIP + "/tcp/" + port)
|
// addr, err := ma.NewMultiaddr("/ip4/" + badIP + "/tcp/" + port)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
t.Fatal(err)
|
// t.Fatal(err)
|
||||||
}
|
// }
|
||||||
badPeers = append(badPeers, createPeer(t, p, addr, network.DirUnknown, peerdata.ConnectionState(ethpb.ConnectionState_DISCONNECTED)))
|
// badPeers = append(badPeers, createPeer(t, p, addr, network.DirUnknown, peerdata.PeerConnectionState(ethpb.ConnectionState_DISCONNECTED)))
|
||||||
}
|
// }
|
||||||
for _, pr := range badPeers {
|
// for _, pr := range badPeers {
|
||||||
assert.NotNil(t, p.IsBad(pr), "peer with bad ip is not bad")
|
// assert.NotNil(t, p.IsBad(pr), "peer with bad ip is not bad")
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Add in bad peers, so that our records are trimmed out
|
// // Add in bad peers, so that our records are trimmed out
|
||||||
// from the peer store.
|
// // from the peer store.
|
||||||
for i := 0; i < p.MaxPeerLimit()+100; i++ {
|
// for i := 0; i < p.MaxPeerLimit()+100; i++ {
|
||||||
// Peer added to peer handler.
|
// // Peer added to peer handler.
|
||||||
pid := addPeer(t, p, peers.Disconnected)
|
// pid := addPeer(t, p, peers.PeerDisconnected)
|
||||||
p.Scorers().BadResponsesScorer().Increment(pid)
|
// p.Scorers().BadResponsesScorer().Increment(pid)
|
||||||
}
|
// }
|
||||||
p.Prune()
|
// p.Prune()
|
||||||
|
|
||||||
for _, pr := range badPeers {
|
// for _, pr := range badPeers {
|
||||||
assert.NoError(t, p.IsBad(pr), "peer with good ip is regarded as bad")
|
// assert.NoError(t, p.IsBad(pr), "peer with good ip is regarded as bad")
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
func TestTrimmedOrderedPeers(t *testing.T) {
|
func TestTrimmedOrderedPeers(t *testing.T) {
|
||||||
p := peers.NewStatus(t.Context(), &peers.StatusConfig{
|
p := peers.NewStatus(t.Context(), &peers.StatusConfig{
|
||||||
@@ -616,7 +618,7 @@ func TestTrimmedOrderedPeers(t *testing.T) {
|
|||||||
|
|
||||||
// Peer 1
|
// Peer 1
|
||||||
pid1 := addPeer(t, p, peers.Connected)
|
pid1 := addPeer(t, p, peers.Connected)
|
||||||
p.SetChainState(pid1, &pb.Status{
|
p.SetChainState(pid1, &pb.StatusV2{
|
||||||
HeadSlot: 3 * params.BeaconConfig().SlotsPerEpoch,
|
HeadSlot: 3 * params.BeaconConfig().SlotsPerEpoch,
|
||||||
FinalizedEpoch: 3,
|
FinalizedEpoch: 3,
|
||||||
FinalizedRoot: mockroot3[:],
|
FinalizedRoot: mockroot3[:],
|
||||||
@@ -624,7 +626,7 @@ func TestTrimmedOrderedPeers(t *testing.T) {
|
|||||||
|
|
||||||
// Peer 2
|
// Peer 2
|
||||||
pid2 := addPeer(t, p, peers.Connected)
|
pid2 := addPeer(t, p, peers.Connected)
|
||||||
p.SetChainState(pid2, &pb.Status{
|
p.SetChainState(pid2, &pb.StatusV2{
|
||||||
HeadSlot: 4 * params.BeaconConfig().SlotsPerEpoch,
|
HeadSlot: 4 * params.BeaconConfig().SlotsPerEpoch,
|
||||||
FinalizedEpoch: 4,
|
FinalizedEpoch: 4,
|
||||||
FinalizedRoot: mockroot4[:],
|
FinalizedRoot: mockroot4[:],
|
||||||
@@ -632,7 +634,7 @@ func TestTrimmedOrderedPeers(t *testing.T) {
|
|||||||
|
|
||||||
// Peer 3
|
// Peer 3
|
||||||
pid3 := addPeer(t, p, peers.Connected)
|
pid3 := addPeer(t, p, peers.Connected)
|
||||||
p.SetChainState(pid3, &pb.Status{
|
p.SetChainState(pid3, &pb.StatusV2{
|
||||||
HeadSlot: 5 * params.BeaconConfig().SlotsPerEpoch,
|
HeadSlot: 5 * params.BeaconConfig().SlotsPerEpoch,
|
||||||
FinalizedEpoch: 5,
|
FinalizedEpoch: 5,
|
||||||
FinalizedRoot: mockroot5[:],
|
FinalizedRoot: mockroot5[:],
|
||||||
@@ -640,7 +642,7 @@ func TestTrimmedOrderedPeers(t *testing.T) {
|
|||||||
|
|
||||||
// Peer 4
|
// Peer 4
|
||||||
pid4 := addPeer(t, p, peers.Connected)
|
pid4 := addPeer(t, p, peers.Connected)
|
||||||
p.SetChainState(pid4, &pb.Status{
|
p.SetChainState(pid4, &pb.StatusV2{
|
||||||
HeadSlot: 2 * params.BeaconConfig().SlotsPerEpoch,
|
HeadSlot: 2 * params.BeaconConfig().SlotsPerEpoch,
|
||||||
FinalizedEpoch: 2,
|
FinalizedEpoch: 2,
|
||||||
FinalizedRoot: mockroot2[:],
|
FinalizedRoot: mockroot2[:],
|
||||||
@@ -648,7 +650,7 @@ func TestTrimmedOrderedPeers(t *testing.T) {
|
|||||||
|
|
||||||
// Peer 5
|
// Peer 5
|
||||||
pid5 := addPeer(t, p, peers.Connected)
|
pid5 := addPeer(t, p, peers.Connected)
|
||||||
p.SetChainState(pid5, &pb.Status{
|
p.SetChainState(pid5, &pb.StatusV2{
|
||||||
HeadSlot: 2 * params.BeaconConfig().SlotsPerEpoch,
|
HeadSlot: 2 * params.BeaconConfig().SlotsPerEpoch,
|
||||||
FinalizedEpoch: 2,
|
FinalizedEpoch: 2,
|
||||||
FinalizedRoot: mockroot2[:],
|
FinalizedRoot: mockroot2[:],
|
||||||
@@ -1012,7 +1014,7 @@ func TestStatus_BestPeer(t *testing.T) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
for _, peerConfig := range tt.peers {
|
for _, peerConfig := range tt.peers {
|
||||||
p.SetChainState(addPeer(t, p, peers.Connected), &pb.Status{
|
p.SetChainState(addPeer(t, p, peers.Connected), &pb.StatusV2{
|
||||||
FinalizedEpoch: peerConfig.finalizedEpoch,
|
FinalizedEpoch: peerConfig.finalizedEpoch,
|
||||||
HeadSlot: peerConfig.headSlot,
|
HeadSlot: peerConfig.headSlot,
|
||||||
})
|
})
|
||||||
@@ -1039,7 +1041,7 @@ func TestBestFinalized_returnsMaxValue(t *testing.T) {
|
|||||||
for i := 0; i <= maxPeers+100; i++ {
|
for i := 0; i <= maxPeers+100; i++ {
|
||||||
p.Add(new(enr.Record), peer.ID(rune(i)), nil, network.DirOutbound)
|
p.Add(new(enr.Record), peer.ID(rune(i)), nil, network.DirOutbound)
|
||||||
p.SetConnectionState(peer.ID(rune(i)), peers.Connected)
|
p.SetConnectionState(peer.ID(rune(i)), peers.Connected)
|
||||||
p.SetChainState(peer.ID(rune(i)), &pb.Status{
|
p.SetChainState(peer.ID(rune(i)), &pb.StatusV2{
|
||||||
FinalizedEpoch: 10,
|
FinalizedEpoch: 10,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -1062,7 +1064,7 @@ func TestStatus_BestNonFinalized(t *testing.T) {
|
|||||||
for i, headSlot := range peerSlots {
|
for i, headSlot := range peerSlots {
|
||||||
p.Add(new(enr.Record), peer.ID(rune(i)), nil, network.DirOutbound)
|
p.Add(new(enr.Record), peer.ID(rune(i)), nil, network.DirOutbound)
|
||||||
p.SetConnectionState(peer.ID(rune(i)), peers.Connected)
|
p.SetConnectionState(peer.ID(rune(i)), peers.Connected)
|
||||||
p.SetChainState(peer.ID(rune(i)), &pb.Status{
|
p.SetChainState(peer.ID(rune(i)), &pb.StatusV2{
|
||||||
HeadSlot: headSlot,
|
HeadSlot: headSlot,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -1085,17 +1087,17 @@ func TestStatus_CurrentEpoch(t *testing.T) {
|
|||||||
})
|
})
|
||||||
// Peer 1
|
// Peer 1
|
||||||
pid1 := addPeer(t, p, peers.Connected)
|
pid1 := addPeer(t, p, peers.Connected)
|
||||||
p.SetChainState(pid1, &pb.Status{
|
p.SetChainState(pid1, &pb.StatusV2{
|
||||||
HeadSlot: params.BeaconConfig().SlotsPerEpoch * 4,
|
HeadSlot: params.BeaconConfig().SlotsPerEpoch * 4,
|
||||||
})
|
})
|
||||||
// Peer 2
|
// Peer 2
|
||||||
pid2 := addPeer(t, p, peers.Connected)
|
pid2 := addPeer(t, p, peers.Connected)
|
||||||
p.SetChainState(pid2, &pb.Status{
|
p.SetChainState(pid2, &pb.StatusV2{
|
||||||
HeadSlot: params.BeaconConfig().SlotsPerEpoch * 5,
|
HeadSlot: params.BeaconConfig().SlotsPerEpoch * 5,
|
||||||
})
|
})
|
||||||
// Peer 3
|
// Peer 3
|
||||||
pid3 := addPeer(t, p, peers.Connected)
|
pid3 := addPeer(t, p, peers.Connected)
|
||||||
p.SetChainState(pid3, &pb.Status{
|
p.SetChainState(pid3, &pb.StatusV2{
|
||||||
HeadSlot: params.BeaconConfig().SlotsPerEpoch * 4,
|
HeadSlot: params.BeaconConfig().SlotsPerEpoch * 4,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
package p2p
|
package p2p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/encoder"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/encoder"
|
||||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
"github.com/OffchainLabs/prysm/v6/network/forks"
|
|
||||||
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"
|
||||||
"github.com/libp2p/go-libp2p/core/peer"
|
"github.com/libp2p/go-libp2p/core/peer"
|
||||||
@@ -32,6 +32,14 @@ var _ pubsub.SubscriptionFilter = (*Service)(nil)
|
|||||||
// (Note: BlobSidecar is not included in this list since it is superseded by DataColumnSidecar)
|
// (Note: BlobSidecar is not included in this list since it is superseded by DataColumnSidecar)
|
||||||
const pubsubSubscriptionRequestLimit = 500
|
const pubsubSubscriptionRequestLimit = 500
|
||||||
|
|
||||||
|
func (s *Service) setAllForkDigests() {
|
||||||
|
entries := params.SortedNetworkScheduleEntries()
|
||||||
|
s.allForkDigests = make(map[[4]byte]struct{}, len(entries))
|
||||||
|
for _, entry := range entries {
|
||||||
|
s.allForkDigests[entry.ForkDigest] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// CanSubscribe returns true if the topic is of interest and we could subscribe to it.
|
// CanSubscribe returns true if the topic is of interest and we could subscribe to it.
|
||||||
func (s *Service) CanSubscribe(topic string) bool {
|
func (s *Service) CanSubscribe(topic string) bool {
|
||||||
if !s.isInitialized() {
|
if !s.isInitialized() {
|
||||||
@@ -48,50 +56,18 @@ func (s *Service) CanSubscribe(topic string) bool {
|
|||||||
if parts[1] != "eth2" {
|
if parts[1] != "eth2" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
phase0ForkDigest, err := s.currentForkDigest()
|
|
||||||
|
var digest [4]byte
|
||||||
|
dl, err := hex.Decode(digest[:], []byte(parts[2]))
|
||||||
|
if err == nil && dl != 4 {
|
||||||
|
err = fmt.Errorf("expected 4 bytes, got %d", dl)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Error("Could not determine fork digest")
|
log.WithError(err).WithField("topic", topic).WithField("digest", parts[2]).Error("CanSubscribe failed to parse message")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
altairForkDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().AltairForkEpoch, s.genesisValidatorsRoot)
|
if _, ok := s.allForkDigests[digest]; !ok {
|
||||||
if err != nil {
|
log.WithField("topic", topic).WithField("digest", fmt.Sprintf("%#x", digest)).Error("CanSubscribe failed to find digest in allForkDigests")
|
||||||
log.WithError(err).Error("Could not determine altair fork digest")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
bellatrixForkDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().BellatrixForkEpoch, s.genesisValidatorsRoot)
|
|
||||||
if err != nil {
|
|
||||||
log.WithError(err).Error("Could not determine Bellatrix fork digest")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
capellaForkDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().CapellaForkEpoch, s.genesisValidatorsRoot)
|
|
||||||
if err != nil {
|
|
||||||
log.WithError(err).Error("Could not determine Capella fork digest")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
denebForkDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().DenebForkEpoch, s.genesisValidatorsRoot)
|
|
||||||
if err != nil {
|
|
||||||
log.WithError(err).Error("Could not determine Deneb fork digest")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
electraForkDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().ElectraForkEpoch, s.genesisValidatorsRoot)
|
|
||||||
if err != nil {
|
|
||||||
log.WithError(err).Error("Could not determine Electra fork digest")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
fuluForkDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().FuluForkEpoch, s.genesisValidatorsRoot)
|
|
||||||
if err != nil {
|
|
||||||
log.WithError(err).Error("Could not determine Fulu fork digest")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
switch parts[2] {
|
|
||||||
case fmt.Sprintf("%x", phase0ForkDigest):
|
|
||||||
case fmt.Sprintf("%x", altairForkDigest):
|
|
||||||
case fmt.Sprintf("%x", bellatrixForkDigest):
|
|
||||||
case fmt.Sprintf("%x", capellaForkDigest):
|
|
||||||
case fmt.Sprintf("%x", denebForkDigest):
|
|
||||||
case fmt.Sprintf("%x", electraForkDigest):
|
|
||||||
case fmt.Sprintf("%x", fuluForkDigest):
|
|
||||||
default:
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,6 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/startup"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/startup"
|
||||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
||||||
"github.com/OffchainLabs/prysm/v6/network/forks"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||||
prysmTime "github.com/OffchainLabs/prysm/v6/time"
|
prysmTime "github.com/OffchainLabs/prysm/v6/time"
|
||||||
pubsubpb "github.com/libp2p/go-libp2p-pubsub/pb"
|
pubsubpb "github.com/libp2p/go-libp2p-pubsub/pb"
|
||||||
@@ -23,10 +21,8 @@ func TestService_CanSubscribe(t *testing.T) {
|
|||||||
params.SetupTestConfigCleanup(t)
|
params.SetupTestConfigCleanup(t)
|
||||||
currentFork := [4]byte{0x01, 0x02, 0x03, 0x04}
|
currentFork := [4]byte{0x01, 0x02, 0x03, 0x04}
|
||||||
validProtocolSuffix := "/" + encoder.ProtocolSuffixSSZSnappy
|
validProtocolSuffix := "/" + encoder.ProtocolSuffixSSZSnappy
|
||||||
genesisTime := time.Now()
|
clock := startup.NewClock(time.Now(), [32]byte{})
|
||||||
var valRoot [32]byte
|
digest := params.ForkDigest(clock.CurrentEpoch())
|
||||||
digest, err := forks.CreateForkDigest(genesisTime, valRoot[:])
|
|
||||||
assert.NoError(t, err)
|
|
||||||
type test struct {
|
type test struct {
|
||||||
name string
|
name string
|
||||||
topic string
|
topic string
|
||||||
@@ -108,11 +104,12 @@ func TestService_CanSubscribe(t *testing.T) {
|
|||||||
}
|
}
|
||||||
tests = append(tests, tt)
|
tests = append(tests, tt)
|
||||||
}
|
}
|
||||||
|
valRoot := clock.GenesisValidatorsRoot()
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
s := &Service{
|
s := &Service{
|
||||||
genesisValidatorsRoot: valRoot[:],
|
genesisValidatorsRoot: valRoot[:],
|
||||||
genesisTime: genesisTime,
|
genesisTime: clock.GenesisTime(),
|
||||||
}
|
}
|
||||||
if got := s.CanSubscribe(tt.topic); got != tt.want {
|
if got := s.CanSubscribe(tt.topic); got != tt.want {
|
||||||
t.Errorf("CanSubscribe(%s) = %v, want %v", tt.topic, got, tt.want)
|
t.Errorf("CanSubscribe(%s) = %v, want %v", tt.topic, got, tt.want)
|
||||||
@@ -220,10 +217,8 @@ func TestGossipTopicMapping_scanfcheck_GossipTopicFormattingSanityCheck(t *testi
|
|||||||
func TestService_FilterIncomingSubscriptions(t *testing.T) {
|
func TestService_FilterIncomingSubscriptions(t *testing.T) {
|
||||||
params.SetupTestConfigCleanup(t)
|
params.SetupTestConfigCleanup(t)
|
||||||
validProtocolSuffix := "/" + encoder.ProtocolSuffixSSZSnappy
|
validProtocolSuffix := "/" + encoder.ProtocolSuffixSSZSnappy
|
||||||
genesisTime := time.Now()
|
clock := startup.NewClock(time.Now(), [32]byte{})
|
||||||
var valRoot [32]byte
|
digest := params.ForkDigest(clock.CurrentEpoch())
|
||||||
digest, err := forks.CreateForkDigest(genesisTime, valRoot[:])
|
|
||||||
assert.NoError(t, err)
|
|
||||||
type args struct {
|
type args struct {
|
||||||
id peer.ID
|
id peer.ID
|
||||||
subs []*pubsubpb.RPC_SubOpts
|
subs []*pubsubpb.RPC_SubOpts
|
||||||
@@ -320,11 +315,12 @@ func TestService_FilterIncomingSubscriptions(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
valRoot := clock.GenesisValidatorsRoot()
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
s := &Service{
|
s := &Service{
|
||||||
genesisValidatorsRoot: valRoot[:],
|
genesisValidatorsRoot: valRoot[:],
|
||||||
genesisTime: genesisTime,
|
genesisTime: clock.GenesisTime(),
|
||||||
}
|
}
|
||||||
got, err := s.FilterIncomingSubscriptions(tt.args.id, tt.args.subs)
|
got, err := s.FilterIncomingSubscriptions(tt.args.id, tt.args.subs)
|
||||||
if (err != nil) != tt.wantErr {
|
if (err != nil) != tt.wantErr {
|
||||||
|
|||||||
@@ -22,50 +22,52 @@ const (
|
|||||||
SchemaVersionV3 = "/3"
|
SchemaVersionV3 = "/3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Specifies the protocol prefix for all our Req/Resp topics.
|
const (
|
||||||
const protocolPrefix = "/eth2/beacon_chain/req"
|
// Specifies the protocol prefix for all our Req/Resp topics.
|
||||||
|
protocolPrefix = "/eth2/beacon_chain/req"
|
||||||
|
|
||||||
// StatusMessageName specifies the name for the status message topic.
|
// StatusMessageName specifies the name for the status message topic.
|
||||||
const StatusMessageName = "/status"
|
StatusMessageName = "/status"
|
||||||
|
|
||||||
// GoodbyeMessageName specifies the name for the goodbye message topic.
|
// GoodbyeMessageName specifies the name for the goodbye message topic.
|
||||||
const GoodbyeMessageName = "/goodbye"
|
GoodbyeMessageName = "/goodbye"
|
||||||
|
|
||||||
// BeaconBlocksByRangeMessageName specifies the name for the beacon blocks by range message topic.
|
// BeaconBlocksByRangeMessageName specifies the name for the beacon blocks by range message topic.
|
||||||
const BeaconBlocksByRangeMessageName = "/beacon_blocks_by_range"
|
BeaconBlocksByRangeMessageName = "/beacon_blocks_by_range"
|
||||||
|
|
||||||
// BeaconBlocksByRootsMessageName specifies the name for the beacon blocks by root message topic.
|
// BeaconBlocksByRootsMessageName specifies the name for the beacon blocks by root message topic.
|
||||||
const BeaconBlocksByRootsMessageName = "/beacon_blocks_by_root"
|
BeaconBlocksByRootsMessageName = "/beacon_blocks_by_root"
|
||||||
|
|
||||||
// PingMessageName Specifies the name for the ping message topic.
|
// PingMessageName Specifies the name for the ping message topic.
|
||||||
const PingMessageName = "/ping"
|
PingMessageName = "/ping"
|
||||||
|
|
||||||
// MetadataMessageName specifies the name for the metadata message topic.
|
// MetadataMessageName specifies the name for the metadata message topic.
|
||||||
const MetadataMessageName = "/metadata"
|
MetadataMessageName = "/metadata"
|
||||||
|
|
||||||
// BlobSidecarsByRangeName is the name for the BlobSidecarsByRange v1 message topic.
|
// BlobSidecarsByRangeName is the name for the BlobSidecarsByRange v1 message topic.
|
||||||
const BlobSidecarsByRangeName = "/blob_sidecars_by_range"
|
BlobSidecarsByRangeName = "/blob_sidecars_by_range"
|
||||||
|
|
||||||
// BlobSidecarsByRootName is the name for the BlobSidecarsByRoot v1 message topic.
|
// BlobSidecarsByRootName is the name for the BlobSidecarsByRoot v1 message topic.
|
||||||
const BlobSidecarsByRootName = "/blob_sidecars_by_root"
|
BlobSidecarsByRootName = "/blob_sidecars_by_root"
|
||||||
|
|
||||||
// LightClientBootstrapName is the name for the LightClientBootstrap message topic,
|
// LightClientBootstrapName is the name for the LightClientBootstrap message topic,
|
||||||
const LightClientBootstrapName = "/light_client_bootstrap"
|
LightClientBootstrapName = "/light_client_bootstrap"
|
||||||
|
|
||||||
// LightClientUpdatesByRangeName is the name for the LightClientUpdatesByRange topic.
|
// LightClientUpdatesByRangeName is the name for the LightClientUpdatesByRange topic.
|
||||||
const LightClientUpdatesByRangeName = "/light_client_updates_by_range"
|
LightClientUpdatesByRangeName = "/light_client_updates_by_range"
|
||||||
|
|
||||||
// LightClientFinalityUpdateName is the name for the LightClientFinalityUpdate topic.
|
// LightClientFinalityUpdateName is the name for the LightClientFinalityUpdate topic.
|
||||||
const LightClientFinalityUpdateName = "/light_client_finality_update"
|
LightClientFinalityUpdateName = "/light_client_finality_update"
|
||||||
|
|
||||||
// LightClientOptimisticUpdateName is the name for the LightClientOptimisticUpdate topic.
|
// LightClientOptimisticUpdateName is the name for the LightClientOptimisticUpdate topic.
|
||||||
const LightClientOptimisticUpdateName = "/light_client_optimistic_update"
|
LightClientOptimisticUpdateName = "/light_client_optimistic_update"
|
||||||
|
|
||||||
// DataColumnSidecarsByRootName is the name for the DataColumnSidecarsByRoot v1 message topic.
|
// DataColumnSidecarsByRootName is the name for the DataColumnSidecarsByRoot v1 message topic.
|
||||||
const DataColumnSidecarsByRootName = "/data_column_sidecars_by_root"
|
DataColumnSidecarsByRootName = "/data_column_sidecars_by_root"
|
||||||
|
|
||||||
// DataColumnSidecarsByRangeName is the name for the DataColumnSidecarsByRange v1 message topic.
|
// DataColumnSidecarsByRangeName is the name for the DataColumnSidecarsByRange v1 message topic.
|
||||||
const DataColumnSidecarsByRangeName = "/data_column_sidecars_by_range"
|
DataColumnSidecarsByRangeName = "/data_column_sidecars_by_range"
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// V1 RPC Topics
|
// V1 RPC Topics
|
||||||
@@ -106,6 +108,8 @@ const (
|
|||||||
RPCDataColumnSidecarsByRangeTopicV1 = protocolPrefix + DataColumnSidecarsByRangeName + SchemaVersionV1
|
RPCDataColumnSidecarsByRangeTopicV1 = protocolPrefix + DataColumnSidecarsByRangeName + SchemaVersionV1
|
||||||
|
|
||||||
// V2 RPC Topics
|
// V2 RPC Topics
|
||||||
|
// RPCStatusTopicV2 defines the v1 topic for the status rpc method.
|
||||||
|
RPCStatusTopicV2 = protocolPrefix + StatusMessageName + SchemaVersionV2
|
||||||
// RPCBlocksByRangeTopicV2 defines v2 the topic for the blocks by range rpc method.
|
// RPCBlocksByRangeTopicV2 defines v2 the topic for the blocks by range rpc method.
|
||||||
RPCBlocksByRangeTopicV2 = protocolPrefix + BeaconBlocksByRangeMessageName + SchemaVersionV2
|
RPCBlocksByRangeTopicV2 = protocolPrefix + BeaconBlocksByRangeMessageName + SchemaVersionV2
|
||||||
// RPCBlocksByRootTopicV2 defines the v2 topic for the blocks by root rpc method.
|
// RPCBlocksByRootTopicV2 defines the v2 topic for the blocks by root rpc method.
|
||||||
@@ -124,94 +128,106 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// RPCTopicMappings map the base message type to the rpc request.
|
// RPCTopicMappings map the base message type to the rpc request.
|
||||||
var RPCTopicMappings = map[string]interface{}{
|
var (
|
||||||
// RPC Status Message
|
RPCTopicMappings = map[string]interface{}{
|
||||||
RPCStatusTopicV1: new(pb.Status),
|
// RPC Status Message
|
||||||
// RPC Goodbye Message
|
RPCStatusTopicV1: new(pb.Status),
|
||||||
RPCGoodByeTopicV1: new(primitives.SSZUint64),
|
RPCStatusTopicV2: new(pb.StatusV2),
|
||||||
// RPC Block By Range Message
|
|
||||||
RPCBlocksByRangeTopicV1: new(pb.BeaconBlocksByRangeRequest),
|
|
||||||
RPCBlocksByRangeTopicV2: new(pb.BeaconBlocksByRangeRequest),
|
|
||||||
// RPC Block By Root Message
|
|
||||||
RPCBlocksByRootTopicV1: new(p2ptypes.BeaconBlockByRootsReq),
|
|
||||||
RPCBlocksByRootTopicV2: new(p2ptypes.BeaconBlockByRootsReq),
|
|
||||||
// RPC Ping Message
|
|
||||||
RPCPingTopicV1: new(primitives.SSZUint64),
|
|
||||||
// RPC Metadata Message
|
|
||||||
RPCMetaDataTopicV1: new(interface{}),
|
|
||||||
RPCMetaDataTopicV2: new(interface{}),
|
|
||||||
RPCMetaDataTopicV3: new(interface{}),
|
|
||||||
// BlobSidecarsByRange v1 Message
|
|
||||||
RPCBlobSidecarsByRangeTopicV1: new(pb.BlobSidecarsByRangeRequest),
|
|
||||||
// BlobSidecarsByRoot v1 Message
|
|
||||||
RPCBlobSidecarsByRootTopicV1: new(p2ptypes.BlobSidecarsByRootReq),
|
|
||||||
|
|
||||||
// Light client
|
// RPC Goodbye Message
|
||||||
RPCLightClientBootstrapTopicV1: new([fieldparams.RootLength]byte),
|
RPCGoodByeTopicV1: new(primitives.SSZUint64),
|
||||||
RPCLightClientUpdatesByRangeTopicV1: new(pb.LightClientUpdatesByRangeRequest),
|
|
||||||
RPCLightClientFinalityUpdateTopicV1: new(interface{}),
|
|
||||||
RPCLightClientOptimisticUpdateTopicV1: new(interface{}),
|
|
||||||
|
|
||||||
// DataColumnSidecarsByRange v1 Message
|
// RPC Block By Range Message
|
||||||
RPCDataColumnSidecarsByRangeTopicV1: new(pb.DataColumnSidecarsByRangeRequest),
|
RPCBlocksByRangeTopicV1: new(pb.BeaconBlocksByRangeRequest),
|
||||||
// DataColumnSidecarsByRoot v1 Message
|
RPCBlocksByRangeTopicV2: new(pb.BeaconBlocksByRangeRequest),
|
||||||
RPCDataColumnSidecarsByRootTopicV1: new(p2ptypes.DataColumnsByRootIdentifiers),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Maps all registered protocol prefixes.
|
// RPC Block By Root Message
|
||||||
var protocolMapping = map[string]bool{
|
RPCBlocksByRootTopicV1: new(p2ptypes.BeaconBlockByRootsReq),
|
||||||
protocolPrefix: true,
|
RPCBlocksByRootTopicV2: new(p2ptypes.BeaconBlockByRootsReq),
|
||||||
}
|
|
||||||
|
|
||||||
// Maps all the protocol message names for the different rpc
|
// RPC Ping Message
|
||||||
// topics.
|
RPCPingTopicV1: new(primitives.SSZUint64),
|
||||||
var messageMapping = map[string]bool{
|
|
||||||
StatusMessageName: true,
|
|
||||||
GoodbyeMessageName: true,
|
|
||||||
BeaconBlocksByRangeMessageName: true,
|
|
||||||
BeaconBlocksByRootsMessageName: true,
|
|
||||||
PingMessageName: true,
|
|
||||||
MetadataMessageName: true,
|
|
||||||
BlobSidecarsByRangeName: true,
|
|
||||||
BlobSidecarsByRootName: true,
|
|
||||||
LightClientBootstrapName: true,
|
|
||||||
LightClientUpdatesByRangeName: true,
|
|
||||||
LightClientFinalityUpdateName: true,
|
|
||||||
LightClientOptimisticUpdateName: true,
|
|
||||||
DataColumnSidecarsByRootName: true,
|
|
||||||
DataColumnSidecarsByRangeName: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Maps all the RPC messages which are to updated in altair.
|
// RPC Metadata Message
|
||||||
var altairMapping = map[string]bool{
|
RPCMetaDataTopicV1: new(interface{}),
|
||||||
BeaconBlocksByRangeMessageName: true,
|
RPCMetaDataTopicV2: new(interface{}),
|
||||||
BeaconBlocksByRootsMessageName: true,
|
RPCMetaDataTopicV3: new(interface{}),
|
||||||
MetadataMessageName: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Maps all the RPC messages which are to updated in fulu.
|
// BlobSidecarsByRange v1 Message
|
||||||
var fuluMapping = map[string]bool{
|
RPCBlobSidecarsByRangeTopicV1: new(pb.BlobSidecarsByRangeRequest),
|
||||||
MetadataMessageName: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
var versionMapping = map[string]bool{
|
// BlobSidecarsByRoot v1 Message
|
||||||
SchemaVersionV1: true,
|
RPCBlobSidecarsByRootTopicV1: new(p2ptypes.BlobSidecarsByRootReq),
|
||||||
SchemaVersionV2: true,
|
|
||||||
SchemaVersionV3: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
// OmitContextBytesV1 keeps track of which RPC methods do not write context bytes in their v1 incarnations.
|
// Light client
|
||||||
// Phase0 did not have the notion of context bytes, which prefix wire-encoded values with a [4]byte identifier
|
RPCLightClientBootstrapTopicV1: new([fieldparams.RootLength]byte),
|
||||||
// to convey the schema for the receiver to use. These RPCs had a version bump to V2 when the context byte encoding
|
RPCLightClientUpdatesByRangeTopicV1: new(pb.LightClientUpdatesByRangeRequest),
|
||||||
// was introduced. For other RPC methods, context bytes are always required.
|
RPCLightClientFinalityUpdateTopicV1: new(interface{}),
|
||||||
var OmitContextBytesV1 = map[string]bool{
|
RPCLightClientOptimisticUpdateTopicV1: new(interface{}),
|
||||||
StatusMessageName: true,
|
|
||||||
GoodbyeMessageName: true,
|
// DataColumnSidecarsByRange v1 Message
|
||||||
BeaconBlocksByRangeMessageName: true,
|
RPCDataColumnSidecarsByRangeTopicV1: new(pb.DataColumnSidecarsByRangeRequest),
|
||||||
BeaconBlocksByRootsMessageName: true,
|
|
||||||
PingMessageName: true,
|
// DataColumnSidecarsByRoot v1 Message
|
||||||
MetadataMessageName: true,
|
RPCDataColumnSidecarsByRootTopicV1: new(p2ptypes.DataColumnsByRootIdentifiers),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Maps all registered protocol prefixes.
|
||||||
|
protocolMapping = map[string]bool{
|
||||||
|
protocolPrefix: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maps all the protocol message names for the different rpc
|
||||||
|
// topics.
|
||||||
|
messageMapping = map[string]bool{
|
||||||
|
StatusMessageName: true,
|
||||||
|
GoodbyeMessageName: true,
|
||||||
|
BeaconBlocksByRangeMessageName: true,
|
||||||
|
BeaconBlocksByRootsMessageName: true,
|
||||||
|
PingMessageName: true,
|
||||||
|
MetadataMessageName: true,
|
||||||
|
BlobSidecarsByRangeName: true,
|
||||||
|
BlobSidecarsByRootName: true,
|
||||||
|
LightClientBootstrapName: true,
|
||||||
|
LightClientUpdatesByRangeName: true,
|
||||||
|
LightClientFinalityUpdateName: true,
|
||||||
|
LightClientOptimisticUpdateName: true,
|
||||||
|
DataColumnSidecarsByRootName: true,
|
||||||
|
DataColumnSidecarsByRangeName: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maps all the RPC messages which are to updated in altair.
|
||||||
|
altairMapping = map[string]string{
|
||||||
|
BeaconBlocksByRangeMessageName: SchemaVersionV2,
|
||||||
|
BeaconBlocksByRootsMessageName: SchemaVersionV2,
|
||||||
|
MetadataMessageName: SchemaVersionV2,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maps all the RPC messages which are to updated in fulu.
|
||||||
|
fuluMapping = map[string]string{
|
||||||
|
StatusMessageName: SchemaVersionV2,
|
||||||
|
MetadataMessageName: SchemaVersionV3,
|
||||||
|
}
|
||||||
|
|
||||||
|
versionMapping = map[string]bool{
|
||||||
|
SchemaVersionV1: true,
|
||||||
|
SchemaVersionV2: true,
|
||||||
|
SchemaVersionV3: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
// OmitContextBytesV1 keeps track of which RPC methods do not write context bytes in their v1 incarnations.
|
||||||
|
// Phase0 did not have the notion of context bytes, which prefix wire-encoded values with a [4]byte identifier
|
||||||
|
// to convey the schema for the receiver to use. These RPCs had a version bump to V2 when the context byte encoding
|
||||||
|
// was introduced. For other RPC methods, context bytes are always required.
|
||||||
|
OmitContextBytesV1 = map[string]bool{
|
||||||
|
StatusMessageName: true,
|
||||||
|
GoodbyeMessageName: true,
|
||||||
|
BeaconBlocksByRangeMessageName: true,
|
||||||
|
BeaconBlocksByRootsMessageName: true,
|
||||||
|
PingMessageName: true,
|
||||||
|
MetadataMessageName: true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
// VerifyTopicMapping verifies that the topic and its accompanying
|
// VerifyTopicMapping verifies that the topic and its accompanying
|
||||||
// message type is correct.
|
// message type is correct.
|
||||||
@@ -333,13 +349,17 @@ func TopicFromMessage(msg string, epoch primitives.Epoch) (string, error) {
|
|||||||
beaconConfig := params.BeaconConfig()
|
beaconConfig := params.BeaconConfig()
|
||||||
|
|
||||||
// Check if the message is to be updated in fulu.
|
// Check if the message is to be updated in fulu.
|
||||||
if epoch >= beaconConfig.FuluForkEpoch && fuluMapping[msg] {
|
if epoch >= beaconConfig.FuluForkEpoch {
|
||||||
return protocolPrefix + msg + SchemaVersionV3, nil
|
if version, ok := fuluMapping[msg]; ok {
|
||||||
|
return protocolPrefix + msg + version, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the message is to be updated in altair.
|
// Check if the message is to be updated in altair.
|
||||||
if epoch >= beaconConfig.AltairForkEpoch && altairMapping[msg] {
|
if epoch >= beaconConfig.AltairForkEpoch {
|
||||||
return protocolPrefix + msg + SchemaVersionV2, nil
|
if version, ok := altairMapping[msg]; ok {
|
||||||
|
return protocolPrefix + msg + version, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return protocolPrefix + msg + SchemaVersionV1, nil
|
return protocolPrefix + msg + SchemaVersionV1, nil
|
||||||
|
|||||||
@@ -119,50 +119,36 @@ func TestTopicFromMessage_CorrectType(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("after altair fork but before fulu fork", func(t *testing.T) {
|
t.Run("after altair fork but before fulu fork", func(t *testing.T) {
|
||||||
for m := range messageMapping {
|
// Not modified in altair fork.
|
||||||
topic, err := TopicFromMessage(m, altairForkEpoch)
|
topic, err := TopicFromMessage(GoodbyeMessageName, altairForkEpoch)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, "/eth2/beacon_chain/req/goodbye/1", topic)
|
||||||
|
|
||||||
if altairMapping[m] {
|
// Modified in altair fork.
|
||||||
require.Equal(t, true, strings.Contains(topic, SchemaVersionV2))
|
topic, err = TopicFromMessage(MetadataMessageName, altairForkEpoch)
|
||||||
_, _, version, err := TopicDeconstructor(topic)
|
require.NoError(t, err)
|
||||||
require.NoError(t, err)
|
require.Equal(t, "/eth2/beacon_chain/req/metadata/2", topic)
|
||||||
require.Equal(t, SchemaVersionV2, version)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
require.Equal(t, true, strings.Contains(topic, SchemaVersionV1))
|
|
||||||
_, _, version, err := TopicDeconstructor(topic)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, SchemaVersionV1, version)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("after fulu fork", func(t *testing.T) {
|
t.Run("after fulu fork", func(t *testing.T) {
|
||||||
for m := range messageMapping {
|
// Not modified in any fork.
|
||||||
topic, err := TopicFromMessage(m, fuluForkEpoch)
|
topic, err := TopicFromMessage(GoodbyeMessageName, fuluForkEpoch)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, "/eth2/beacon_chain/req/goodbye/1", topic)
|
||||||
|
|
||||||
if fuluMapping[m] {
|
// Modified in altair fork.
|
||||||
require.Equal(t, true, strings.Contains(topic, SchemaVersionV3))
|
topic, err = TopicFromMessage(BeaconBlocksByRangeMessageName, fuluForkEpoch)
|
||||||
_, _, version, err := TopicDeconstructor(topic)
|
require.NoError(t, err)
|
||||||
require.NoError(t, err)
|
require.Equal(t, "/eth2/beacon_chain/req/beacon_blocks_by_range/2", topic)
|
||||||
require.Equal(t, SchemaVersionV3, version)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if altairMapping[m] {
|
// Modified in fulu fork.
|
||||||
require.Equal(t, true, strings.Contains(topic, SchemaVersionV2))
|
topic, err = TopicFromMessage(StatusMessageName, fuluForkEpoch)
|
||||||
_, _, version, err := TopicDeconstructor(topic)
|
require.NoError(t, err)
|
||||||
require.NoError(t, err)
|
require.Equal(t, "/eth2/beacon_chain/req/status/2", topic)
|
||||||
require.Equal(t, SchemaVersionV2, version)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
require.Equal(t, true, strings.Contains(topic, SchemaVersionV1))
|
// Modified both in altair and fulu fork.
|
||||||
_, _, version, err := TopicDeconstructor(topic)
|
topic, err = TopicFromMessage(MetadataMessageName, fuluForkEpoch)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, SchemaVersionV1, version)
|
require.Equal(t, "/eth2/beacon_chain/req/metadata/3", topic)
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/peers"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/peers"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/peers/scorers"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/peers/scorers"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/types"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/types"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/startup"
|
||||||
"github.com/OffchainLabs/prysm/v6/config/features"
|
"github.com/OffchainLabs/prysm/v6/config/features"
|
||||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
leakybucket "github.com/OffchainLabs/prysm/v6/container/leaky-bucket"
|
leakybucket "github.com/OffchainLabs/prysm/v6/container/leaky-bucket"
|
||||||
@@ -82,6 +83,8 @@ type Service struct {
|
|||||||
genesisTime time.Time
|
genesisTime time.Time
|
||||||
genesisValidatorsRoot []byte
|
genesisValidatorsRoot []byte
|
||||||
activeValidatorCount uint64
|
activeValidatorCount uint64
|
||||||
|
clock *startup.Clock
|
||||||
|
allForkDigests map[[4]byte]struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewService initializes a new p2p service compatible with shared.Service interface. No
|
// NewService initializes a new p2p service compatible with shared.Service interface. No
|
||||||
@@ -431,10 +434,11 @@ func (s *Service) awaitStateInitialized() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Fatal("failed to receive initial genesis data")
|
log.WithError(err).Fatal("failed to receive initial genesis data")
|
||||||
}
|
}
|
||||||
|
s.setAllForkDigests()
|
||||||
s.genesisTime = clock.GenesisTime()
|
s.genesisTime = clock.GenesisTime()
|
||||||
gvr := clock.GenesisValidatorsRoot()
|
gvr := clock.GenesisValidatorsRoot()
|
||||||
s.genesisValidatorsRoot = gvr[:]
|
s.genesisValidatorsRoot = gvr[:]
|
||||||
_, err = s.currentForkDigest() // initialize fork digest cache
|
_, err = s.currentForkDigest()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Error("Could not initialize fork digest")
|
log.WithError(err).Error("Could not initialize fork digest")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,12 +10,9 @@ import (
|
|||||||
|
|
||||||
mock "github.com/OffchainLabs/prysm/v6/beacon-chain/blockchain/testing"
|
mock "github.com/OffchainLabs/prysm/v6/beacon-chain/blockchain/testing"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/encoder"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/encoder"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/peers"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/peers/scorers"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/startup"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/startup"
|
||||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
||||||
"github.com/OffchainLabs/prysm/v6/network/forks"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||||
prysmTime "github.com/OffchainLabs/prysm/v6/time"
|
prysmTime "github.com/OffchainLabs/prysm/v6/time"
|
||||||
@@ -348,58 +345,57 @@ func TestService_JoinLeaveTopic(t *testing.T) {
|
|||||||
func initializeStateWithForkDigest(_ context.Context, t *testing.T, gs startup.ClockSetter) [4]byte {
|
func initializeStateWithForkDigest(_ context.Context, t *testing.T, gs startup.ClockSetter) [4]byte {
|
||||||
gt := prysmTime.Now()
|
gt := prysmTime.Now()
|
||||||
gvr := bytesutil.ToBytes32(bytesutil.PadTo([]byte("genesis validators root"), 32))
|
gvr := bytesutil.ToBytes32(bytesutil.PadTo([]byte("genesis validators root"), 32))
|
||||||
require.NoError(t, gs.SetClock(startup.NewClock(gt, gvr)))
|
clock := startup.NewClock(gt, gvr)
|
||||||
|
require.NoError(t, gs.SetClock(clock))
|
||||||
fd, err := forks.CreateForkDigest(gt, gvr[:])
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
time.Sleep(50 * time.Millisecond) // wait for pubsub filter to initialize.
|
time.Sleep(50 * time.Millisecond) // wait for pubsub filter to initialize.
|
||||||
|
|
||||||
return fd
|
return params.ForkDigest(clock.CurrentEpoch())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestService_connectWithPeer(t *testing.T) {
|
// TODO: Uncomment when out of devnet
|
||||||
params.SetupTestConfigCleanup(t)
|
// func TestService_connectWithPeer(t *testing.T) {
|
||||||
tests := []struct {
|
// params.SetupTestConfigCleanup(t)
|
||||||
name string
|
// tests := []struct {
|
||||||
peers *peers.Status
|
// name string
|
||||||
info peer.AddrInfo
|
// peers *peers.Status
|
||||||
wantErr string
|
// info peer.AddrInfo
|
||||||
}{
|
// wantErr string
|
||||||
{
|
// }{
|
||||||
name: "bad peer",
|
// {
|
||||||
peers: func() *peers.Status {
|
// name: "bad peer",
|
||||||
ps := peers.NewStatus(t.Context(), &peers.StatusConfig{
|
// peers: func() *peers.Status {
|
||||||
ScorerParams: &scorers.Config{},
|
// ps := peers.NewStatus(context.Background(), &peers.StatusConfig{
|
||||||
})
|
// ScorerParams: &scorers.Config{},
|
||||||
for i := 0; i < 10; i++ {
|
// })
|
||||||
ps.Scorers().BadResponsesScorer().Increment("bad")
|
// for i := 0; i < 10; i++ {
|
||||||
}
|
// ps.Scorers().BadResponsesScorer().Increment("bad")
|
||||||
return ps
|
// }
|
||||||
}(),
|
// return ps
|
||||||
info: peer.AddrInfo{ID: "bad"},
|
// }(),
|
||||||
wantErr: "refused to connect to bad peer",
|
// info: peer.AddrInfo{ID: "bad"},
|
||||||
},
|
// wantErr: "refused to connect to bad peer",
|
||||||
}
|
// },
|
||||||
for _, tt := range tests {
|
// }
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
// for _, tt := range tests {
|
||||||
h, _, _ := createHost(t, 34567)
|
// t.Run(tt.name, func(t *testing.T) {
|
||||||
defer func() {
|
// h, _, _ := createHost(t, 34567)
|
||||||
if err := h.Close(); err != nil {
|
// defer func() {
|
||||||
t.Fatal(err)
|
// if err := h.Close(); err != nil {
|
||||||
}
|
// t.Fatal(err)
|
||||||
}()
|
// }
|
||||||
ctx := t.Context()
|
// }()
|
||||||
s := &Service{
|
// ctx := context.Background()
|
||||||
host: h,
|
// s := &Service{
|
||||||
peers: tt.peers,
|
// host: h,
|
||||||
}
|
// peers: tt.peers,
|
||||||
err := s.connectWithPeer(ctx, tt.info)
|
// }
|
||||||
if len(tt.wantErr) > 0 {
|
// err := s.connectWithPeer(ctx, tt.info)
|
||||||
require.ErrorContains(t, tt.wantErr, err)
|
// if len(tt.wantErr) > 0 {
|
||||||
} else {
|
// require.ErrorContains(t, tt.wantErr, err)
|
||||||
require.NoError(t, err)
|
// } else {
|
||||||
}
|
// require.NoError(t, err)
|
||||||
})
|
// }
|
||||||
}
|
// })
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import (
|
|||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/prysmaticlabs/go-bitfield"
|
"github.com/prysmaticlabs/go-bitfield"
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -35,6 +34,8 @@ var (
|
|||||||
custodyGroupCountEnrKey = params.BeaconNetworkConfig().CustodyGroupCountKey
|
custodyGroupCountEnrKey = params.BeaconNetworkConfig().CustodyGroupCountKey
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const nfdEnrKey = "nfd" // The ENR record key for "nfd" (Next Fork Digest).
|
||||||
|
|
||||||
// The value used with the subnet, in order
|
// The value used with the subnet, in order
|
||||||
// to create an appropriate key to retrieve
|
// to create an appropriate key to retrieve
|
||||||
// the relevant lock. This is used to differentiate
|
// the relevant lock. This is used to differentiate
|
||||||
@@ -74,8 +75,8 @@ func (s *Service) nodeFilter(topic string, index uint64) (func(node *enode.Node)
|
|||||||
|
|
||||||
// searchForPeers performs a network search for peers subscribed to a particular subnet.
|
// searchForPeers performs a network search for peers subscribed to a particular subnet.
|
||||||
// It exits as soon as one of these conditions is met:
|
// It exits as soon as one of these conditions is met:
|
||||||
// - It looped through `batchSize` nodes.
|
// - It looped during `batchPeriod` duration, or
|
||||||
// - It found `peersToFindCount“ peers corresponding to the `filter` criteria.
|
// - It found `peersToFindCount“ peers corresponding to the `filter` criteria, or
|
||||||
// - Iterator is exhausted.
|
// - Iterator is exhausted.
|
||||||
func searchForPeers(
|
func searchForPeers(
|
||||||
iterator enode.Iterator,
|
iterator enode.Iterator,
|
||||||
@@ -147,8 +148,6 @@ func (s *Service) FindPeersWithSubnet(
|
|||||||
index uint64,
|
index uint64,
|
||||||
threshold int,
|
threshold int,
|
||||||
) (bool, error) {
|
) (bool, error) {
|
||||||
const minLogInterval = 1 * time.Minute
|
|
||||||
|
|
||||||
ctx, span := trace.StartSpan(ctx, "p2p.FindPeersWithSubnet")
|
ctx, span := trace.StartSpan(ctx, "p2p.FindPeersWithSubnet")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
@@ -168,41 +167,29 @@ func (s *Service) FindPeersWithSubnet(
|
|||||||
return false, errors.Wrap(err, "node filter")
|
return false, errors.Wrap(err, "node filter")
|
||||||
}
|
}
|
||||||
|
|
||||||
peersSummary := func(topic string, threshold int) (int, int) {
|
peersSummary := func(topic string, threshold int) int {
|
||||||
// Retrieve how many peers we have for this topic.
|
// Retrieve how many peers we have for this topic.
|
||||||
peerCountForTopic := len(s.pubsub.ListPeers(topic))
|
peerCountForTopic := len(s.pubsub.ListPeers(topic))
|
||||||
|
|
||||||
// Compute how many peers we are missing to reach the threshold.
|
// Compute how many peers we are missing to reach the threshold.
|
||||||
missingPeerCountForTopic := max(0, threshold-peerCountForTopic)
|
missingPeerCountForTopic := max(0, threshold-peerCountForTopic)
|
||||||
|
|
||||||
return peerCountForTopic, missingPeerCountForTopic
|
return missingPeerCountForTopic
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute how many peers we are missing to reach the threshold.
|
// Compute how many peers we are missing to reach the threshold.
|
||||||
peerCountForTopic, missingPeerCountForTopic := peersSummary(topic, threshold)
|
missingPeerCountForTopic := peersSummary(topic, threshold)
|
||||||
|
|
||||||
// Exit early if we have enough peers.
|
// Exit early if we have enough peers.
|
||||||
if missingPeerCountForTopic == 0 {
|
if missingPeerCountForTopic == 0 {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
log := log.WithFields(logrus.Fields{
|
|
||||||
"topic": topic,
|
|
||||||
"targetPeerCount": threshold,
|
|
||||||
})
|
|
||||||
|
|
||||||
log.WithField("currentPeerCount", peerCountForTopic).Debug("Searching for new peers for a subnet - start")
|
|
||||||
|
|
||||||
lastLogTime := time.Now()
|
|
||||||
|
|
||||||
wg := new(sync.WaitGroup)
|
wg := new(sync.WaitGroup)
|
||||||
for {
|
for {
|
||||||
// If the context is done, we can exit the loop. This is the unhappy path.
|
// If the context is done, we can exit the loop. This is the unhappy path.
|
||||||
if err := ctx.Err(); err != nil {
|
if ctx.Err() != nil {
|
||||||
return false, errors.Errorf(
|
return false, nil
|
||||||
"unable to find requisite number of peers for topic %s - only %d out of %d peers available after searching",
|
|
||||||
topic, peerCountForTopic, threshold,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search for new peers in the network.
|
// Search for new peers in the network.
|
||||||
@@ -225,20 +212,14 @@ func (s *Service) FindPeersWithSubnet(
|
|||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
peerCountForTopic, missingPeerCountForTopic := peersSummary(topic, threshold)
|
missingPeerCountForTopic := peersSummary(topic, threshold)
|
||||||
|
|
||||||
// If we have enough peers, we can exit the loop. This is the happy path.
|
// If we have enough peers, we can exit the loop. This is the happy path.
|
||||||
if missingPeerCountForTopic == 0 {
|
if missingPeerCountForTopic == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if time.Since(lastLogTime) > minLogInterval {
|
|
||||||
lastLogTime = time.Now()
|
|
||||||
log.WithField("currentPeerCount", peerCountForTopic).Debug("Searching for new peers for a subnet - continue")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.WithField("currentPeerCount", threshold).Debug("Searching for new peers for a subnet - success")
|
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,11 +317,23 @@ func (s *Service) updateSubnetRecordWithMetadata(bitV bitfield.Bitvector64) {
|
|||||||
// with a new value for a bitfield of subnets tracked. It also record's
|
// with a new value for a bitfield of subnets tracked. It also record's
|
||||||
// the sync committee subnet in the enr. It also updates the node's
|
// the sync committee subnet in the enr. It also updates the node's
|
||||||
// metadata by increasing the sequence number and the subnets tracked by the node.
|
// metadata by increasing the sequence number and the subnets tracked by the node.
|
||||||
func (s *Service) updateSubnetRecordWithMetadataV2(bitVAtt bitfield.Bitvector64, bitVSync bitfield.Bitvector4) {
|
func (s *Service) updateSubnetRecordWithMetadataV2(
|
||||||
|
bitVAtt bitfield.Bitvector64,
|
||||||
|
bitVSync bitfield.Bitvector4,
|
||||||
|
custodyGroupCount uint64,
|
||||||
|
) {
|
||||||
entry := enr.WithEntry(attSubnetEnrKey, &bitVAtt)
|
entry := enr.WithEntry(attSubnetEnrKey, &bitVAtt)
|
||||||
subEntry := enr.WithEntry(syncCommsSubnetEnrKey, &bitVSync)
|
subEntry := enr.WithEntry(syncCommsSubnetEnrKey, &bitVSync)
|
||||||
s.dv5Listener.LocalNode().Set(entry)
|
|
||||||
s.dv5Listener.LocalNode().Set(subEntry)
|
localNode := s.dv5Listener.LocalNode()
|
||||||
|
localNode.Set(entry)
|
||||||
|
localNode.Set(subEntry)
|
||||||
|
|
||||||
|
if params.FuluEnabled() {
|
||||||
|
custodyGroupCountEntry := enr.WithEntry(custodyGroupCountEnrKey, custodyGroupCount)
|
||||||
|
localNode.Set(custodyGroupCountEntry)
|
||||||
|
}
|
||||||
|
|
||||||
s.metaData = wrapper.WrappedMetadataV1(&pb.MetaDataV1{
|
s.metaData = wrapper.WrappedMetadataV1(&pb.MetaDataV1{
|
||||||
SeqNumber: s.metaData.SequenceNumber() + 1,
|
SeqNumber: s.metaData.SequenceNumber() + 1,
|
||||||
Attnets: bitVAtt,
|
Attnets: bitVAtt,
|
||||||
@@ -367,10 +360,8 @@ func (s *Service) updateSubnetRecordWithMetadataV3(
|
|||||||
localNode.Set(syncSubnetsEntry)
|
localNode.Set(syncSubnetsEntry)
|
||||||
localNode.Set(custodyGroupCountEntry)
|
localNode.Set(custodyGroupCountEntry)
|
||||||
|
|
||||||
newSeqNumber := s.metaData.SequenceNumber() + 1
|
|
||||||
|
|
||||||
s.metaData = wrapper.WrappedMetadataV2(&pb.MetaDataV2{
|
s.metaData = wrapper.WrappedMetadataV2(&pb.MetaDataV2{
|
||||||
SeqNumber: newSeqNumber,
|
SeqNumber: s.metaData.SequenceNumber() + 1,
|
||||||
Attnets: bitVAtt,
|
Attnets: bitVAtt,
|
||||||
Syncnets: bitVSync,
|
Syncnets: bitVSync,
|
||||||
CustodyGroupCount: custodyGroupCount,
|
CustodyGroupCount: custodyGroupCount,
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ func (m *MockPeersProvider) Peers() *peers.Status {
|
|||||||
}
|
}
|
||||||
m.peers.Add(createENR(), id0, ma0, network.DirInbound)
|
m.peers.Add(createENR(), id0, ma0, network.DirInbound)
|
||||||
m.peers.SetConnectionState(id0, peers.Connected)
|
m.peers.SetConnectionState(id0, peers.Connected)
|
||||||
m.peers.SetChainState(id0, &pb.Status{FinalizedEpoch: 10})
|
m.peers.SetChainState(id0, &pb.StatusV2{FinalizedEpoch: 10})
|
||||||
id1, err := peer.Decode(MockRawPeerId1)
|
id1, err := peer.Decode(MockRawPeerId1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Debug("Cannot decode")
|
log.WithError(err).Debug("Cannot decode")
|
||||||
@@ -76,7 +76,7 @@ func (m *MockPeersProvider) Peers() *peers.Status {
|
|||||||
}
|
}
|
||||||
m.peers.Add(createENR(), id1, ma1, network.DirOutbound)
|
m.peers.Add(createENR(), id1, ma1, network.DirOutbound)
|
||||||
m.peers.SetConnectionState(id1, peers.Connected)
|
m.peers.SetConnectionState(id1, peers.Connected)
|
||||||
m.peers.SetChainState(id1, &pb.Status{FinalizedEpoch: 11})
|
m.peers.SetChainState(id1, &pb.StatusV2{FinalizedEpoch: 11})
|
||||||
}
|
}
|
||||||
return m.peers
|
return m.peers
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -206,8 +206,8 @@ func (s BlobSidecarsByRootReq) Swap(i, j int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Len is the number of elements in the collection.
|
// Len is the number of elements in the collection.
|
||||||
func (s BlobSidecarsByRootReq) Len() int {
|
func (s *BlobSidecarsByRootReq) Len() int {
|
||||||
return len(s)
|
return len(*s)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ====================================
|
// ====================================
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ go_library(
|
|||||||
"//api/server/structs:go_default_library",
|
"//api/server/structs:go_default_library",
|
||||||
"//config/params:go_default_library",
|
"//config/params:go_default_library",
|
||||||
"//monitoring/tracing/trace:go_default_library",
|
"//monitoring/tracing/trace:go_default_library",
|
||||||
"//network/forks:go_default_library",
|
|
||||||
"//network/httputil:go_default_library",
|
"//network/httputil:go_default_library",
|
||||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||||
],
|
],
|
||||||
@@ -22,9 +21,6 @@ go_test(
|
|||||||
deps = [
|
deps = [
|
||||||
"//api/server/structs:go_default_library",
|
"//api/server/structs:go_default_library",
|
||||||
"//config/params:go_default_library",
|
"//config/params:go_default_library",
|
||||||
"//consensus-types/primitives:go_default_library",
|
|
||||||
"//encoding/bytesutil:go_default_library",
|
|
||||||
"//network/forks:go_default_library",
|
|
||||||
"//testing/assert:go_default_library",
|
"//testing/assert:go_default_library",
|
||||||
"//testing/require:go_default_library",
|
"//testing/require:go_default_library",
|
||||||
"@com_github_ethereum_go_ethereum//common:go_default_library",
|
"@com_github_ethereum_go_ethereum//common:go_default_library",
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/api/server/structs"
|
"github.com/OffchainLabs/prysm/v6/api/server/structs"
|
||||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
"github.com/OffchainLabs/prysm/v6/monitoring/tracing/trace"
|
"github.com/OffchainLabs/prysm/v6/monitoring/tracing/trace"
|
||||||
"github.com/OffchainLabs/prysm/v6/network/forks"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/network/httputil"
|
"github.com/OffchainLabs/prysm/v6/network/httputil"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
)
|
)
|
||||||
@@ -33,34 +32,25 @@ func GetForkSchedule(w http.ResponseWriter, r *http.Request) {
|
|||||||
_, span := trace.StartSpan(r.Context(), "config.GetForkSchedule")
|
_, span := trace.StartSpan(r.Context(), "config.GetForkSchedule")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
schedule := params.BeaconConfig().ForkVersionSchedule
|
schedule := params.SortedForkSchedule()
|
||||||
|
data := make([]*structs.Fork, 0, len(schedule))
|
||||||
if len(schedule) == 0 {
|
if len(schedule) == 0 {
|
||||||
httputil.WriteJson(w, &structs.GetForkScheduleResponse{
|
httputil.WriteJson(w, &structs.GetForkScheduleResponse{
|
||||||
Data: make([]*structs.Fork, 0),
|
Data: data,
|
||||||
})
|
})
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
previous := schedule[0]
|
||||||
versions := forks.SortedForkVersions(schedule)
|
for _, entry := range schedule {
|
||||||
chainForks := make([]*structs.Fork, len(schedule))
|
data = append(data, &structs.Fork{
|
||||||
var previous, current []byte
|
PreviousVersion: hexutil.Encode(previous.ForkVersion[:]),
|
||||||
for i, v := range versions {
|
CurrentVersion: hexutil.Encode(entry.ForkVersion[:]),
|
||||||
if i == 0 {
|
Epoch: fmt.Sprintf("%d", entry.Epoch),
|
||||||
previous = params.BeaconConfig().GenesisForkVersion
|
})
|
||||||
} else {
|
previous = entry
|
||||||
previous = current
|
|
||||||
}
|
|
||||||
copyV := v
|
|
||||||
current = copyV[:]
|
|
||||||
chainForks[i] = &structs.Fork{
|
|
||||||
PreviousVersion: hexutil.Encode(previous),
|
|
||||||
CurrentVersion: hexutil.Encode(current),
|
|
||||||
Epoch: fmt.Sprintf("%d", schedule[v]),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
httputil.WriteJson(w, &structs.GetForkScheduleResponse{
|
httputil.WriteJson(w, &structs.GetForkScheduleResponse{
|
||||||
Data: chainForks,
|
Data: data,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,8 +70,8 @@ func GetSpec(w http.ResponseWriter, r *http.Request) {
|
|||||||
httputil.WriteJson(w, &structs.GetSpecResponse{Data: data})
|
httputil.WriteJson(w, &structs.GetSpecResponse{Data: data})
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareConfigSpec() (map[string]string, error) {
|
func prepareConfigSpec() (map[string]interface{}, error) {
|
||||||
data := make(map[string]string)
|
data := make(map[string]interface{})
|
||||||
config := *params.BeaconConfig()
|
config := *params.BeaconConfig()
|
||||||
t := reflect.TypeOf(config)
|
t := reflect.TypeOf(config)
|
||||||
v := reflect.ValueOf(config)
|
v := reflect.ValueOf(config)
|
||||||
@@ -102,7 +92,16 @@ func prepareConfigSpec() (map[string]string, error) {
|
|||||||
case reflect.Uint64:
|
case reflect.Uint64:
|
||||||
data[tagValue] = strconv.FormatUint(vField.Uint(), 10)
|
data[tagValue] = strconv.FormatUint(vField.Uint(), 10)
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
data[tagValue] = hexutil.Encode(vField.Bytes())
|
// Handle byte slices with hexutil.Encode
|
||||||
|
if vField.Type().Elem().Kind() == reflect.Uint8 {
|
||||||
|
data[tagValue] = hexutil.Encode(vField.Bytes())
|
||||||
|
} else if vField.Type().Elem().Kind() == reflect.Struct {
|
||||||
|
// Handle struct slices - convert numeric fields to strings for consistent JSON output
|
||||||
|
data[tagValue] = convertStructSliceForJSON(vField)
|
||||||
|
} else {
|
||||||
|
// Handle other slice types - return as interface{} for JSON serialization
|
||||||
|
data[tagValue] = vField.Interface()
|
||||||
|
}
|
||||||
case reflect.Array:
|
case reflect.Array:
|
||||||
data[tagValue] = hexutil.Encode(reflect.ValueOf(&config).Elem().Field(i).Slice(0, vField.Len()).Bytes())
|
data[tagValue] = hexutil.Encode(reflect.ValueOf(&config).Elem().Field(i).Slice(0, vField.Len()).Bytes())
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
@@ -116,3 +115,45 @@ func prepareConfigSpec() (map[string]string, error) {
|
|||||||
|
|
||||||
return data, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// convertStructSliceForJSON converts struct slices to ensure numeric fields are strings
|
||||||
|
func convertStructSliceForJSON(sliceValue reflect.Value) []map[string]interface{} {
|
||||||
|
length := sliceValue.Len()
|
||||||
|
result := make([]map[string]interface{}, length)
|
||||||
|
|
||||||
|
for i := 0; i < length; i++ {
|
||||||
|
elem := sliceValue.Index(i)
|
||||||
|
elemType := elem.Type()
|
||||||
|
elemMap := make(map[string]interface{})
|
||||||
|
|
||||||
|
for j := 0; j < elem.NumField(); j++ {
|
||||||
|
field := elem.Field(j)
|
||||||
|
fieldType := elemType.Field(j)
|
||||||
|
|
||||||
|
// Skip unexported fields
|
||||||
|
if !field.CanInterface() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get JSON tag name (fallback to field name if no JSON tag)
|
||||||
|
jsonTag := fieldType.Tag.Get("json")
|
||||||
|
if jsonTag == "" || jsonTag == "-" {
|
||||||
|
jsonTag = fieldType.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert numeric types to strings for consistent JSON output
|
||||||
|
switch field.Kind() {
|
||||||
|
case reflect.Uint64, reflect.Uint, reflect.Uint32, reflect.Uint16, reflect.Uint8:
|
||||||
|
elemMap[jsonTag] = strconv.FormatUint(field.Uint(), 10)
|
||||||
|
case reflect.Int64, reflect.Int, reflect.Int32, reflect.Int16, reflect.Int8:
|
||||||
|
elemMap[jsonTag] = strconv.FormatInt(field.Int(), 10)
|
||||||
|
default:
|
||||||
|
elemMap[jsonTag] = field.Interface()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result[i] = elemMap
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/api/server/structs"
|
"github.com/OffchainLabs/prysm/v6/api/server/structs"
|
||||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/network/forks"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
@@ -200,7 +198,7 @@ func TestGetSpec(t *testing.T) {
|
|||||||
data, ok := resp.Data.(map[string]interface{})
|
data, ok := resp.Data.(map[string]interface{})
|
||||||
require.Equal(t, true, ok)
|
require.Equal(t, true, ok)
|
||||||
|
|
||||||
assert.Equal(t, 175, len(data))
|
assert.Equal(t, 176, len(data))
|
||||||
for k, v := range data {
|
for k, v := range data {
|
||||||
t.Run(k, func(t *testing.T) {
|
t.Run(k, func(t *testing.T) {
|
||||||
switch k {
|
switch k {
|
||||||
@@ -577,6 +575,11 @@ func TestGetSpec(t *testing.T) {
|
|||||||
assert.Equal(t, "102", v)
|
assert.Equal(t, "102", v)
|
||||||
case "BLOB_SIDECAR_SUBNET_COUNT_ELECTRA":
|
case "BLOB_SIDECAR_SUBNET_COUNT_ELECTRA":
|
||||||
assert.Equal(t, "103", v)
|
assert.Equal(t, "103", v)
|
||||||
|
case "BLOB_SCHEDULE":
|
||||||
|
// BLOB_SCHEDULE should be an empty slice when no schedule is defined
|
||||||
|
blobSchedule, ok := v.([]interface{})
|
||||||
|
assert.Equal(t, true, ok)
|
||||||
|
assert.Equal(t, 0, len(blobSchedule))
|
||||||
default:
|
default:
|
||||||
t.Errorf("Incorrect key: %s", k)
|
t.Errorf("Incorrect key: %s", k)
|
||||||
}
|
}
|
||||||
@@ -586,43 +589,34 @@ func TestGetSpec(t *testing.T) {
|
|||||||
|
|
||||||
func TestForkSchedule_Ok(t *testing.T) {
|
func TestForkSchedule_Ok(t *testing.T) {
|
||||||
t.Run("ok", func(t *testing.T) {
|
t.Run("ok", func(t *testing.T) {
|
||||||
genesisForkVersion := []byte("Genesis")
|
|
||||||
firstForkVersion, firstForkEpoch := []byte("Firs"), primitives.Epoch(100)
|
|
||||||
secondForkVersion, secondForkEpoch := []byte("Seco"), primitives.Epoch(200)
|
|
||||||
thirdForkVersion, thirdForkEpoch := []byte("Thir"), primitives.Epoch(300)
|
|
||||||
|
|
||||||
params.SetupTestConfigCleanup(t)
|
params.SetupTestConfigCleanup(t)
|
||||||
config := params.BeaconConfig().Copy()
|
config := params.BeaconConfig().Copy()
|
||||||
config.GenesisForkVersion = genesisForkVersion
|
config.InitializeForkSchedule()
|
||||||
// Create fork schedule adding keys in non-sorted order.
|
|
||||||
schedule := make(map[[4]byte]primitives.Epoch, 3)
|
|
||||||
schedule[bytesutil.ToBytes4(secondForkVersion)] = secondForkEpoch
|
|
||||||
schedule[bytesutil.ToBytes4(firstForkVersion)] = firstForkEpoch
|
|
||||||
schedule[bytesutil.ToBytes4(thirdForkVersion)] = thirdForkEpoch
|
|
||||||
config.ForkVersionSchedule = schedule
|
|
||||||
params.OverrideBeaconConfig(config)
|
|
||||||
|
|
||||||
request := httptest.NewRequest(http.MethodGet, "http://example.com/eth/v1/config/fork_schedule", nil)
|
request := httptest.NewRequest(http.MethodGet, "http://example.com/eth/v1/config/fork_schedule", nil)
|
||||||
writer := httptest.NewRecorder()
|
writer := httptest.NewRecorder()
|
||||||
writer.Body = &bytes.Buffer{}
|
writer.Body = &bytes.Buffer{}
|
||||||
|
|
||||||
|
genesisStr, firstStr, secondStr := hexutil.Encode(config.GenesisForkVersion), hexutil.Encode(config.AltairForkVersion), hexutil.Encode(config.BellatrixForkVersion)
|
||||||
GetForkSchedule(writer, request)
|
GetForkSchedule(writer, request)
|
||||||
require.Equal(t, http.StatusOK, writer.Code)
|
require.Equal(t, http.StatusOK, writer.Code)
|
||||||
resp := &structs.GetForkScheduleResponse{}
|
resp := &structs.GetForkScheduleResponse{}
|
||||||
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
|
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
|
||||||
require.Equal(t, 3, len(resp.Data))
|
schedule := params.SortedForkSchedule()
|
||||||
|
require.Equal(t, len(schedule), len(resp.Data))
|
||||||
fork := resp.Data[0]
|
fork := resp.Data[0]
|
||||||
assert.DeepEqual(t, hexutil.Encode(genesisForkVersion), fork.PreviousVersion)
|
assert.Equal(t, genesisStr, fork.PreviousVersion)
|
||||||
assert.DeepEqual(t, hexutil.Encode(firstForkVersion), fork.CurrentVersion)
|
assert.Equal(t, genesisStr, fork.CurrentVersion)
|
||||||
assert.Equal(t, fmt.Sprintf("%d", firstForkEpoch), fork.Epoch)
|
assert.Equal(t, fmt.Sprintf("%d", config.GenesisEpoch), fork.Epoch)
|
||||||
fork = resp.Data[1]
|
fork = resp.Data[1]
|
||||||
assert.DeepEqual(t, hexutil.Encode(firstForkVersion), fork.PreviousVersion)
|
assert.Equal(t, genesisStr, fork.PreviousVersion)
|
||||||
assert.DeepEqual(t, hexutil.Encode(secondForkVersion), fork.CurrentVersion)
|
assert.Equal(t, firstStr, fork.CurrentVersion)
|
||||||
assert.Equal(t, fmt.Sprintf("%d", secondForkEpoch), fork.Epoch)
|
assert.Equal(t, fmt.Sprintf("%d", config.AltairForkEpoch), fork.Epoch)
|
||||||
fork = resp.Data[2]
|
fork = resp.Data[2]
|
||||||
assert.DeepEqual(t, hexutil.Encode(secondForkVersion), fork.PreviousVersion)
|
assert.Equal(t, firstStr, fork.PreviousVersion)
|
||||||
assert.DeepEqual(t, hexutil.Encode(thirdForkVersion), fork.CurrentVersion)
|
assert.Equal(t, secondStr, fork.CurrentVersion)
|
||||||
assert.Equal(t, fmt.Sprintf("%d", thirdForkEpoch), fork.Epoch)
|
assert.Equal(t, fmt.Sprintf("%d", config.BellatrixForkEpoch), fork.Epoch)
|
||||||
})
|
})
|
||||||
t.Run("correct number of forks", func(t *testing.T) {
|
t.Run("correct number of forks", func(t *testing.T) {
|
||||||
request := httptest.NewRequest(http.MethodGet, "http://example.com/eth/v1/config/fork_schedule", nil)
|
request := httptest.NewRequest(http.MethodGet, "http://example.com/eth/v1/config/fork_schedule", nil)
|
||||||
@@ -633,7 +627,64 @@ func TestForkSchedule_Ok(t *testing.T) {
|
|||||||
require.Equal(t, http.StatusOK, writer.Code)
|
require.Equal(t, http.StatusOK, writer.Code)
|
||||||
resp := &structs.GetForkScheduleResponse{}
|
resp := &structs.GetForkScheduleResponse{}
|
||||||
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
|
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
|
||||||
os := forks.NewOrderedSchedule(params.BeaconConfig())
|
os := params.SortedForkSchedule()
|
||||||
assert.Equal(t, os.Len(), len(resp.Data))
|
assert.Equal(t, len(os), len(resp.Data))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetSpec_BlobSchedule(t *testing.T) {
|
||||||
|
params.SetupTestConfigCleanup(t)
|
||||||
|
config := params.BeaconConfig().Copy()
|
||||||
|
|
||||||
|
// Set up a blob schedule with test data
|
||||||
|
config.BlobSchedule = []params.BlobScheduleEntry{
|
||||||
|
{
|
||||||
|
Epoch: primitives.Epoch(100),
|
||||||
|
MaxBlobsPerBlock: 6,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Epoch: primitives.Epoch(200),
|
||||||
|
MaxBlobsPerBlock: 9,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
params.OverrideBeaconConfig(config)
|
||||||
|
|
||||||
|
request := httptest.NewRequest(http.MethodGet, "http://example.com/eth/v1/config/spec", nil)
|
||||||
|
writer := httptest.NewRecorder()
|
||||||
|
writer.Body = &bytes.Buffer{}
|
||||||
|
|
||||||
|
GetSpec(writer, request)
|
||||||
|
require.Equal(t, http.StatusOK, writer.Code)
|
||||||
|
resp := structs.GetSpecResponse{}
|
||||||
|
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), &resp))
|
||||||
|
data, ok := resp.Data.(map[string]interface{})
|
||||||
|
require.Equal(t, true, ok)
|
||||||
|
|
||||||
|
// Verify BLOB_SCHEDULE is present and properly formatted
|
||||||
|
blobScheduleValue, exists := data["BLOB_SCHEDULE"]
|
||||||
|
require.Equal(t, true, exists)
|
||||||
|
|
||||||
|
// Verify it's a slice of maps (actual JSON object, not string)
|
||||||
|
// The JSON unmarshaling converts it to []interface{} with map[string]interface{} entries
|
||||||
|
blobScheduleSlice, ok := blobScheduleValue.([]interface{})
|
||||||
|
require.Equal(t, true, ok)
|
||||||
|
|
||||||
|
// Convert to generic interface for easier testing
|
||||||
|
var blobSchedule []map[string]interface{}
|
||||||
|
for _, entry := range blobScheduleSlice {
|
||||||
|
entryMap, ok := entry.(map[string]interface{})
|
||||||
|
require.Equal(t, true, ok)
|
||||||
|
blobSchedule = append(blobSchedule, entryMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the blob schedule content
|
||||||
|
require.Equal(t, 2, len(blobSchedule))
|
||||||
|
|
||||||
|
// Check first entry - values should be strings for consistent API output
|
||||||
|
assert.Equal(t, "100", blobSchedule[0]["EPOCH"])
|
||||||
|
assert.Equal(t, "6", blobSchedule[0]["MAX_BLOBS_PER_BLOCK"])
|
||||||
|
|
||||||
|
// Check second entry - values should be strings for consistent API output
|
||||||
|
assert.Equal(t, "200", blobSchedule[1]["EPOCH"])
|
||||||
|
assert.Equal(t, "9", blobSchedule[1]["MAX_BLOBS_PER_BLOCK"])
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ go_library(
|
|||||||
"//config/params:go_default_library",
|
"//config/params:go_default_library",
|
||||||
"//encoding/bytesutil:go_default_library",
|
"//encoding/bytesutil:go_default_library",
|
||||||
"//monitoring/tracing/trace:go_default_library",
|
"//monitoring/tracing/trace:go_default_library",
|
||||||
"//network/forks:go_default_library",
|
|
||||||
"//network/httputil:go_default_library",
|
"//network/httputil:go_default_library",
|
||||||
"//runtime/version:go_default_library",
|
"//runtime/version:go_default_library",
|
||||||
"//time/slots:go_default_library",
|
"//time/slots:go_default_library",
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
||||||
"github.com/OffchainLabs/prysm/v6/monitoring/tracing/trace"
|
"github.com/OffchainLabs/prysm/v6/monitoring/tracing/trace"
|
||||||
"github.com/OffchainLabs/prysm/v6/network/forks"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/network/httputil"
|
"github.com/OffchainLabs/prysm/v6/network/httputil"
|
||||||
"github.com/OffchainLabs/prysm/v6/runtime/version"
|
"github.com/OffchainLabs/prysm/v6/runtime/version"
|
||||||
"github.com/OffchainLabs/prysm/v6/time/slots"
|
"github.com/OffchainLabs/prysm/v6/time/slots"
|
||||||
@@ -115,7 +114,7 @@ func (s *Server) GetLightClientUpdatesByRange(w http.ResponseWriter, req *http.R
|
|||||||
|
|
||||||
updateSlot := update.AttestedHeader().Beacon().Slot
|
updateSlot := update.AttestedHeader().Beacon().Slot
|
||||||
updateEpoch := slots.ToEpoch(updateSlot)
|
updateEpoch := slots.ToEpoch(updateSlot)
|
||||||
updateFork, err := forks.Fork(updateEpoch)
|
updateFork, err := params.Fork(updateEpoch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httputil.HandleError(w, "Could not get fork Version: "+err.Error(), http.StatusInternalServerError)
|
httputil.HandleError(w, "Could not get fork Version: "+err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -10,11 +10,13 @@ go_library(
|
|||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
deps = [
|
deps = [
|
||||||
"//beacon-chain/blockchain:go_default_library",
|
"//beacon-chain/blockchain:go_default_library",
|
||||||
|
"//beacon-chain/core/peerdas:go_default_library",
|
||||||
"//beacon-chain/db:go_default_library",
|
"//beacon-chain/db:go_default_library",
|
||||||
"//beacon-chain/db/filesystem:go_default_library",
|
"//beacon-chain/db/filesystem:go_default_library",
|
||||||
"//beacon-chain/rpc/core:go_default_library",
|
"//beacon-chain/rpc/core:go_default_library",
|
||||||
"//beacon-chain/state:go_default_library",
|
"//beacon-chain/state:go_default_library",
|
||||||
"//beacon-chain/state/stategen:go_default_library",
|
"//beacon-chain/state/stategen:go_default_library",
|
||||||
|
"//cmd/beacon-chain/flags: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/blocks:go_default_library",
|
"//consensus-types/blocks:go_default_library",
|
||||||
@@ -36,6 +38,7 @@ go_test(
|
|||||||
],
|
],
|
||||||
embed = [":go_default_library"],
|
embed = [":go_default_library"],
|
||||||
deps = [
|
deps = [
|
||||||
|
"//beacon-chain/blockchain/kzg:go_default_library",
|
||||||
"//beacon-chain/blockchain/testing:go_default_library",
|
"//beacon-chain/blockchain/testing:go_default_library",
|
||||||
"//beacon-chain/db/filesystem:go_default_library",
|
"//beacon-chain/db/filesystem:go_default_library",
|
||||||
"//beacon-chain/db/testing:go_default_library",
|
"//beacon-chain/db/testing:go_default_library",
|
||||||
@@ -47,12 +50,16 @@ go_test(
|
|||||||
"//beacon-chain/verification:go_default_library",
|
"//beacon-chain/verification:go_default_library",
|
||||||
"//config/params:go_default_library",
|
"//config/params:go_default_library",
|
||||||
"//consensus-types/blocks:go_default_library",
|
"//consensus-types/blocks:go_default_library",
|
||||||
|
"//consensus-types/interfaces:go_default_library",
|
||||||
"//consensus-types/primitives:go_default_library",
|
"//consensus-types/primitives:go_default_library",
|
||||||
"//encoding/bytesutil:go_default_library",
|
"//encoding/bytesutil:go_default_library",
|
||||||
"//proto/prysm/v1alpha1:go_default_library",
|
"//proto/prysm/v1alpha1:go_default_library",
|
||||||
"//testing/assert:go_default_library",
|
"//testing/assert:go_default_library",
|
||||||
"//testing/require:go_default_library",
|
"//testing/require:go_default_library",
|
||||||
"//testing/util:go_default_library",
|
"//testing/util:go_default_library",
|
||||||
|
"@com_github_consensys_gnark_crypto//ecc/bls12-381/fr:go_default_library",
|
||||||
|
"@com_github_crate_crypto_go_kzg_4844//:go_default_library",
|
||||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||||
|
"@com_github_sirupsen_logrus//:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,12 +3,15 @@ package lookup
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/blockchain"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/blockchain"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/peerdas"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/db"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/db"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/db/filesystem"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/db/filesystem"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/rpc/core"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/rpc/core"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/flags"
|
||||||
fieldparams "github.com/OffchainLabs/prysm/v6/config/fieldparams"
|
fieldparams "github.com/OffchainLabs/prysm/v6/config/fieldparams"
|
||||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/blocks"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/blocks"
|
||||||
@@ -49,6 +52,7 @@ type BeaconDbBlocker struct {
|
|||||||
ChainInfoFetcher blockchain.ChainInfoFetcher
|
ChainInfoFetcher blockchain.ChainInfoFetcher
|
||||||
GenesisTimeFetcher blockchain.TimeFetcher
|
GenesisTimeFetcher blockchain.TimeFetcher
|
||||||
BlobStorage *filesystem.BlobStorage
|
BlobStorage *filesystem.BlobStorage
|
||||||
|
DataColumnStorage *filesystem.DataColumnStorage
|
||||||
}
|
}
|
||||||
|
|
||||||
// Block returns the beacon block for a given identifier. The identifier can be one of:
|
// Block returns the beacon block for a given identifier. The identifier can be one of:
|
||||||
@@ -129,6 +133,137 @@ func (p *BeaconDbBlocker) Block(ctx context.Context, id []byte) (interfaces.Read
|
|||||||
return blk, nil
|
return blk, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// blobsFromStoredBlobs retrieves blobs corresponding to `indices` and `root` from the store.
|
||||||
|
// This function expects blobs to be stored directly (aka. no data columns).
|
||||||
|
func (p *BeaconDbBlocker) blobsFromStoredBlobs(indices []int, root []byte, commitments [][]byte) ([]*blocks.VerifiedROBlob, *core.RpcError) {
|
||||||
|
sum := p.BlobStorage.Summary(bytesutil.ToBytes32(root))
|
||||||
|
|
||||||
|
if len(indices) == 0 {
|
||||||
|
for index := range commitments {
|
||||||
|
if sum.HasIndex(uint64(index)) {
|
||||||
|
indices = append(indices, index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, index := range indices {
|
||||||
|
if uint64(index) >= sum.MaxBlobsForEpoch() {
|
||||||
|
return nil, &core.RpcError{
|
||||||
|
Err: fmt.Errorf("requested index %d is bigger than the maximum possible blob count %d", index, sum.MaxBlobsForEpoch()),
|
||||||
|
Reason: core.BadRequest,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !sum.HasIndex(uint64(index)) {
|
||||||
|
return nil, &core.RpcError{
|
||||||
|
Err: fmt.Errorf("requested index %d not found", index),
|
||||||
|
Reason: core.NotFound,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
blobs := make([]*blocks.VerifiedROBlob, 0, len(indices))
|
||||||
|
for _, index := range indices {
|
||||||
|
vblob, err := p.BlobStorage.Get(bytesutil.ToBytes32(root), uint64(index))
|
||||||
|
if err != nil {
|
||||||
|
return nil, &core.RpcError{
|
||||||
|
Err: fmt.Errorf("could not retrieve blob for block root %#x at index %d", root, index),
|
||||||
|
Reason: core.Internal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
blobs = append(blobs, &vblob)
|
||||||
|
}
|
||||||
|
|
||||||
|
return blobs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// blobsFromStoredDataColumns retrieves data columns from the store, reconstruct the whole matrix if needed, convert the matrix to blobs,
|
||||||
|
// and then returns blobs corresponding to `indices` and `root` from the store,
|
||||||
|
// This function expects data columns to be stored (aka. no blobs).
|
||||||
|
// If not enough data columns are available to extract blobs from them (either directly or after reconstruction), an error is returned.
|
||||||
|
func (p *BeaconDbBlocker) blobsFromStoredDataColumns(block blocks.ROBlock, indices []int, rootBytes []byte) ([]*blocks.VerifiedROBlob, *core.RpcError) {
|
||||||
|
root := bytesutil.ToBytes32(rootBytes)
|
||||||
|
|
||||||
|
// Use all indices if none are provided.
|
||||||
|
if len(indices) == 0 {
|
||||||
|
commitments, err := block.Block().Body().BlobKzgCommitments()
|
||||||
|
if err != nil {
|
||||||
|
return nil, &core.RpcError{
|
||||||
|
Err: errors.Wrap(err, "could not retrieve blob commitments"),
|
||||||
|
Reason: core.Internal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for index := range commitments {
|
||||||
|
indices = append(indices, index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count how many columns we have in the store.
|
||||||
|
summary := p.DataColumnStorage.Summary(root)
|
||||||
|
stored := summary.Stored()
|
||||||
|
count := uint64(len(stored))
|
||||||
|
|
||||||
|
if count < peerdas.MinimumColumnsCountToReconstruct() {
|
||||||
|
// There is no way to reconstruct the data columns.
|
||||||
|
return nil, &core.RpcError{
|
||||||
|
Err: errors.Errorf("the node does not custody enough data columns to reconstruct blobs. Please start the beacon node with the `--%s` flag to ensure this call to success, or retry later if it is already the case.", flags.SubscribeAllDataSubnets.Name),
|
||||||
|
Reason: core.NotFound,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve from the database needed data columns.
|
||||||
|
verifiedRoDataColumnSidecars, err := p.neededDataColumnSidecars(root, stored)
|
||||||
|
if err != nil {
|
||||||
|
return nil, &core.RpcError{
|
||||||
|
Err: errors.Wrap(err, "needed data column sidecars"),
|
||||||
|
Reason: core.Internal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
verifiedRoBlobSidecars, err := peerdas.ReconstructBlobs(block, verifiedRoDataColumnSidecars, indices)
|
||||||
|
if err != nil {
|
||||||
|
return nil, &core.RpcError{
|
||||||
|
Err: errors.Wrap(err, "blobs from data columns"),
|
||||||
|
Reason: core.Internal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return verifiedRoBlobSidecars, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *BeaconDbBlocker) neededDataColumnSidecars(root [fieldparams.RootLength]byte, stored map[uint64]bool) ([]blocks.VerifiedRODataColumn, error) {
|
||||||
|
// Check if we have all the non-extended data columns.
|
||||||
|
cellsPerBlob := fieldparams.CellsPerBlob
|
||||||
|
blobIndices := make([]uint64, 0, cellsPerBlob)
|
||||||
|
hasAllBlobColumns := true
|
||||||
|
for i := range uint64(cellsPerBlob) {
|
||||||
|
if !stored[i] {
|
||||||
|
hasAllBlobColumns = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
blobIndices = append(blobIndices, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
if hasAllBlobColumns {
|
||||||
|
// Retrieve only the non-extended data columns.
|
||||||
|
verifiedRoSidecars, err := p.DataColumnStorage.Get(root, blobIndices)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "data columns storage get")
|
||||||
|
}
|
||||||
|
|
||||||
|
return verifiedRoSidecars, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve all the data columns.
|
||||||
|
verifiedRoSidecars, err := p.DataColumnStorage.Get(root, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "data columns storage get")
|
||||||
|
}
|
||||||
|
|
||||||
|
return verifiedRoSidecars, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Blobs returns the blobs for a given block id identifier and blob indices. The identifier can be one of:
|
// Blobs returns the blobs for a given block id identifier and blob indices. The identifier can be one of:
|
||||||
// - "head" (canonical head in node's view)
|
// - "head" (canonical head in node's view)
|
||||||
// - "genesis"
|
// - "genesis"
|
||||||
@@ -212,64 +347,55 @@ func (p *BeaconDbBlocker) Blobs(ctx context.Context, id string, indices []int) (
|
|||||||
|
|
||||||
root := bytesutil.ToBytes32(rootSlice)
|
root := bytesutil.ToBytes32(rootSlice)
|
||||||
|
|
||||||
b, err := p.BeaconDB.Block(ctx, root)
|
roSignedBlock, err := p.BeaconDB.Block(ctx, root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, &core.RpcError{Err: errors.Wrapf(err, "failed to retrieve block %#x from db", rootSlice), Reason: core.Internal}
|
return nil, &core.RpcError{Err: errors.Wrapf(err, "failed to retrieve block %#x from db", rootSlice), Reason: core.Internal}
|
||||||
}
|
}
|
||||||
if b == nil {
|
|
||||||
|
if roSignedBlock == nil {
|
||||||
return nil, &core.RpcError{Err: fmt.Errorf("block %#x not found in db", rootSlice), Reason: core.NotFound}
|
return nil, &core.RpcError{Err: fmt.Errorf("block %#x not found in db", rootSlice), Reason: core.NotFound}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if block is not in the retention window, return 200 w/ empty list
|
// If block is not in the retention window, return 200 w/ empty list
|
||||||
if !p.BlobStorage.WithinRetentionPeriod(slots.ToEpoch(b.Block().Slot()), slots.ToEpoch(p.GenesisTimeFetcher.CurrentSlot())) {
|
if !p.BlobStorage.WithinRetentionPeriod(slots.ToEpoch(roSignedBlock.Block().Slot()), slots.ToEpoch(p.GenesisTimeFetcher.CurrentSlot())) {
|
||||||
return make([]*blocks.VerifiedROBlob, 0), nil
|
return make([]*blocks.VerifiedROBlob, 0), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
commitments, err := b.Block().Body().BlobKzgCommitments()
|
roBlock := roSignedBlock.Block()
|
||||||
|
|
||||||
|
commitments, err := roBlock.Body().BlobKzgCommitments()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, &core.RpcError{Err: errors.Wrapf(err, "failed to retrieve kzg commitments from block %#x", rootSlice), Reason: core.Internal}
|
return nil, &core.RpcError{Err: errors.Wrapf(err, "failed to retrieve kzg commitments from block %#x", rootSlice), Reason: core.Internal}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there are no commitments return 200 w/ empty list
|
// if there are no commitments return 200 w/ empty list
|
||||||
if len(commitments) == 0 {
|
if len(commitments) == 0 {
|
||||||
return make([]*blocks.VerifiedROBlob, 0), nil
|
return make([]*blocks.VerifiedROBlob, 0), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
sum := p.BlobStorage.Summary(root)
|
// Get the slot of the block.
|
||||||
|
blockSlot := roBlock.Slot()
|
||||||
|
|
||||||
if len(indices) == 0 {
|
// Get the first peerDAS epoch.
|
||||||
for i := range commitments {
|
fuluForkEpoch := params.BeaconConfig().FuluForkEpoch
|
||||||
if sum.HasIndex(uint64(i)) {
|
|
||||||
indices = append(indices, i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for _, ix := range indices {
|
|
||||||
if uint64(ix) >= sum.MaxBlobsForEpoch() {
|
|
||||||
return nil, &core.RpcError{
|
|
||||||
Err: fmt.Errorf("requested index %d is bigger than the maximum possible blob count %d", ix, sum.MaxBlobsForEpoch()),
|
|
||||||
Reason: core.BadRequest,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !sum.HasIndex(uint64(ix)) {
|
|
||||||
return nil, &core.RpcError{
|
|
||||||
Err: fmt.Errorf("requested index %d not found", ix),
|
|
||||||
Reason: core.NotFound,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
blobs := make([]*blocks.VerifiedROBlob, len(indices))
|
// Compute the first peerDAS slot.
|
||||||
for i, index := range indices {
|
fuluForkSlot := primitives.Slot(math.MaxUint64)
|
||||||
vblob, err := p.BlobStorage.Get(root, uint64(index))
|
if fuluForkEpoch != primitives.Epoch(math.MaxUint64) {
|
||||||
|
fuluForkSlot, err = slots.EpochStart(fuluForkEpoch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, &core.RpcError{
|
return nil, &core.RpcError{Err: errors.Wrap(err, "could not calculate peerDAS start slot"), Reason: core.Internal}
|
||||||
Err: fmt.Errorf("could not retrieve blob for block root %#x at index %d", rootSlice, index),
|
|
||||||
Reason: core.Internal,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
blobs[i] = &vblob
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return blobs, nil
|
if blockSlot >= fuluForkSlot {
|
||||||
|
roBlock, err := blocks.NewROBlockWithRoot(roSignedBlock, root)
|
||||||
|
if err != nil {
|
||||||
|
return nil, &core.RpcError{Err: errors.Wrapf(err, "failed to create roBlock with root %#x", root), Reason: core.Internal}
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.blobsFromStoredDataColumns(roBlock, indices, rootSlice)
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.blobsFromStoredBlobs(indices, rootSlice, commitments)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package lookup
|
package lookup
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -8,6 +11,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/blockchain/kzg"
|
||||||
mockChain "github.com/OffchainLabs/prysm/v6/beacon-chain/blockchain/testing"
|
mockChain "github.com/OffchainLabs/prysm/v6/beacon-chain/blockchain/testing"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/db/filesystem"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/db/filesystem"
|
||||||
testDB "github.com/OffchainLabs/prysm/v6/beacon-chain/db/testing"
|
testDB "github.com/OffchainLabs/prysm/v6/beacon-chain/db/testing"
|
||||||
@@ -16,12 +20,16 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/verification"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/verification"
|
||||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/blocks"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/blocks"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/consensus-types/interfaces"
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
||||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/util"
|
"github.com/OffchainLabs/prysm/v6/testing/util"
|
||||||
|
"github.com/consensys/gnark-crypto/ecc/bls12-381/fr"
|
||||||
|
GoKZG "github.com/crate-crypto/go-kzg-4844"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetBlock(t *testing.T) {
|
func TestGetBlock(t *testing.T) {
|
||||||
@@ -157,6 +165,118 @@ func TestGetBlock(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func deterministicRandomness(seed int64) [32]byte {
|
||||||
|
// Converts an int64 to a byte slice
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
err := binary.Write(buf, binary.BigEndian, seed)
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Error("Failed to write int64 to bytes buffer")
|
||||||
|
return [32]byte{}
|
||||||
|
}
|
||||||
|
bytes := buf.Bytes()
|
||||||
|
|
||||||
|
return sha256.Sum256(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a serialized random field element in big-endian
|
||||||
|
func getRandFieldElement(seed int64) [32]byte {
|
||||||
|
bytes := deterministicRandomness(seed)
|
||||||
|
var r fr.Element
|
||||||
|
r.SetBytes(bytes[:])
|
||||||
|
|
||||||
|
return GoKZG.SerializeScalar(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a random blob using the passed seed as entropy
|
||||||
|
func getRandBlob(seed int64) kzg.Blob {
|
||||||
|
var blob kzg.Blob
|
||||||
|
for i := 0; i < len(blob); i += 32 {
|
||||||
|
fieldElementBytes := getRandFieldElement(seed + int64(i))
|
||||||
|
copy(blob[i:i+32], fieldElementBytes[:])
|
||||||
|
}
|
||||||
|
return blob
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateCommitmentAndProof(blob *kzg.Blob) (*kzg.Commitment, *kzg.Proof, error) {
|
||||||
|
commitment, err := kzg.BlobToKZGCommitment(blob)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
proof, err := kzg.ComputeBlobKZGProof(blob, commitment)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return &commitment, &proof, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateRandomBlocSignedBeaconBlockkAndVerifiedRoBlobs(t *testing.T, blobCount int) (interfaces.SignedBeaconBlock, []*blocks.VerifiedROBlob) {
|
||||||
|
// Create a protobuf signed beacon block.
|
||||||
|
signedBeaconBlockPb := util.NewBeaconBlockDeneb()
|
||||||
|
|
||||||
|
// Generate random blobs and their corresponding commitments and proofs.
|
||||||
|
blobs := make([]kzg.Blob, 0, blobCount)
|
||||||
|
blobKzgCommitments := make([]*kzg.Commitment, 0, blobCount)
|
||||||
|
blobKzgProofs := make([]*kzg.Proof, 0, blobCount)
|
||||||
|
|
||||||
|
for blobIndex := range blobCount {
|
||||||
|
// Create a random blob.
|
||||||
|
blob := getRandBlob(int64(blobIndex))
|
||||||
|
blobs = append(blobs, blob)
|
||||||
|
|
||||||
|
// Generate a blobKZGCommitment for the blob.
|
||||||
|
blobKZGCommitment, proof, err := generateCommitmentAndProof(&blob)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
blobKzgCommitments = append(blobKzgCommitments, blobKZGCommitment)
|
||||||
|
blobKzgProofs = append(blobKzgProofs, proof)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the commitments into the block.
|
||||||
|
blobZkgCommitmentsBytes := make([][]byte, 0, blobCount)
|
||||||
|
for _, blobKZGCommitment := range blobKzgCommitments {
|
||||||
|
blobZkgCommitmentsBytes = append(blobZkgCommitmentsBytes, blobKZGCommitment[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
signedBeaconBlockPb.Block.Body.BlobKzgCommitments = blobZkgCommitmentsBytes
|
||||||
|
|
||||||
|
// Generate verified RO blobs.
|
||||||
|
verifiedROBlobs := make([]*blocks.VerifiedROBlob, 0, blobCount)
|
||||||
|
|
||||||
|
// Create a signed beacon block from the protobuf.
|
||||||
|
signedBeaconBlock, err := blocks.NewSignedBeaconBlock(signedBeaconBlockPb)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
commitmentInclusionProof, err := blocks.MerkleProofKZGCommitments(signedBeaconBlock.Block().Body())
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
for blobIndex := range blobCount {
|
||||||
|
blob := blobs[blobIndex]
|
||||||
|
blobKZGCommitment := blobKzgCommitments[blobIndex]
|
||||||
|
blobKzgProof := blobKzgProofs[blobIndex]
|
||||||
|
|
||||||
|
// Get the signed beacon block header.
|
||||||
|
signedBeaconBlockHeader, err := signedBeaconBlock.Header()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
blobSidecar := ðpb.BlobSidecar{
|
||||||
|
Index: uint64(blobIndex),
|
||||||
|
Blob: blob[:],
|
||||||
|
KzgCommitment: blobKZGCommitment[:],
|
||||||
|
KzgProof: blobKzgProof[:],
|
||||||
|
SignedBlockHeader: signedBeaconBlockHeader,
|
||||||
|
CommitmentInclusionProof: commitmentInclusionProof,
|
||||||
|
}
|
||||||
|
|
||||||
|
roBlob, err := blocks.NewROBlob(blobSidecar)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
verifiedROBlob := blocks.NewVerifiedROBlob(roBlob)
|
||||||
|
verifiedROBlobs = append(verifiedROBlobs, &verifiedROBlob)
|
||||||
|
}
|
||||||
|
|
||||||
|
return signedBeaconBlock, verifiedROBlobs
|
||||||
|
}
|
||||||
|
|
||||||
func TestGetBlob(t *testing.T) {
|
func TestGetBlob(t *testing.T) {
|
||||||
params.SetupTestConfigCleanup(t)
|
params.SetupTestConfigCleanup(t)
|
||||||
cfg := params.BeaconConfig().Copy()
|
cfg := params.BeaconConfig().Copy()
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestServer_GetBeaconConfig(t *testing.T) {
|
func TestServer_GetBeaconConfig(t *testing.T) {
|
||||||
|
t.Skip("this is a weird test")
|
||||||
ctx := t.Context()
|
ctx := t.Context()
|
||||||
bs := &Server{}
|
bs := &Server{}
|
||||||
res, err := bs.GetBeaconConfig(ctx, &emptypb.Empty{})
|
res, err := bs.GetBeaconConfig(ctx, &emptypb.Empty{})
|
||||||
|
|||||||
@@ -109,6 +109,8 @@ func (ds *Server) getPeer(pid peer.ID) (*ethpb.DebugPeerResponse, error) {
|
|||||||
peerInfo.MetadataV0 = metadata.MetadataObjV0()
|
peerInfo.MetadataV0 = metadata.MetadataObjV0()
|
||||||
case metadata.MetadataObjV1() != nil:
|
case metadata.MetadataObjV1() != nil:
|
||||||
peerInfo.MetadataV1 = metadata.MetadataObjV1()
|
peerInfo.MetadataV1 = metadata.MetadataObjV1()
|
||||||
|
case metadata.MetadataObjV2() != nil:
|
||||||
|
peerInfo.MetadataV2 = metadata.MetadataObjV2()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addresses := peerStore.Addrs(pid)
|
addresses := peerStore.Addrs(pid)
|
||||||
@@ -127,7 +129,7 @@ func (ds *Server) getPeer(pid peer.ID) (*ethpb.DebugPeerResponse, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
// In the event chain state is non existent, we
|
// In the event chain state is non existent, we
|
||||||
// initialize with the zero value.
|
// initialize with the zero value.
|
||||||
pStatus = new(ethpb.Status)
|
pStatus = new(ethpb.StatusV2)
|
||||||
}
|
}
|
||||||
lastUpdated, err := peers.ChainStateLastUpdated(pid)
|
lastUpdated, err := peers.ChainStateLastUpdated(pid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -150,6 +152,17 @@ func (ds *Server) getPeer(pid peer.ID) (*ethpb.DebugPeerResponse, error) {
|
|||||||
BehaviourPenalty: float32(bPenalty),
|
BehaviourPenalty: float32(bPenalty),
|
||||||
ValidationError: errorToString(peers.Scorers().ValidationError(pid)),
|
ValidationError: errorToString(peers.Scorers().ValidationError(pid)),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convert statusV2 into status
|
||||||
|
// TODO: Should we do it this way or the other way around?
|
||||||
|
peerStatus := ðpb.Status{
|
||||||
|
ForkDigest: pStatus.ForkDigest,
|
||||||
|
FinalizedRoot: pStatus.FinalizedRoot,
|
||||||
|
FinalizedEpoch: pStatus.FinalizedEpoch,
|
||||||
|
HeadRoot: pStatus.HeadRoot,
|
||||||
|
HeadSlot: pStatus.HeadSlot,
|
||||||
|
}
|
||||||
|
|
||||||
return ðpb.DebugPeerResponse{
|
return ðpb.DebugPeerResponse{
|
||||||
ListeningAddresses: stringAddrs,
|
ListeningAddresses: stringAddrs,
|
||||||
Direction: pbDirection,
|
Direction: pbDirection,
|
||||||
@@ -157,7 +170,7 @@ func (ds *Server) getPeer(pid peer.ID) (*ethpb.DebugPeerResponse, error) {
|
|||||||
PeerId: pid.String(),
|
PeerId: pid.String(),
|
||||||
Enr: enr,
|
Enr: enr,
|
||||||
PeerInfo: peerInfo,
|
PeerInfo: peerInfo,
|
||||||
PeerStatus: pStatus,
|
PeerStatus: peerStatus,
|
||||||
LastUpdated: unixTime,
|
LastUpdated: unixTime,
|
||||||
ScoreInfo: scoreInfo,
|
ScoreInfo: scoreInfo,
|
||||||
}, nil
|
}, nil
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# gazelle:ignore
|
||||||
|
|
||||||
load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
||||||
|
|
||||||
go_library(
|
go_library(
|
||||||
@@ -37,6 +39,7 @@ go_library(
|
|||||||
"//api/client/builder:go_default_library",
|
"//api/client/builder: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/blockchain/kzg:go_default_library",
|
||||||
"//beacon-chain/builder:go_default_library",
|
"//beacon-chain/builder:go_default_library",
|
||||||
"//beacon-chain/cache:go_default_library",
|
"//beacon-chain/cache:go_default_library",
|
||||||
"//beacon-chain/cache/depositsnapshot:go_default_library",
|
"//beacon-chain/cache/depositsnapshot:go_default_library",
|
||||||
@@ -47,6 +50,7 @@ go_library(
|
|||||||
"//beacon-chain/core/feed/operation:go_default_library",
|
"//beacon-chain/core/feed/operation:go_default_library",
|
||||||
"//beacon-chain/core/feed/state:go_default_library",
|
"//beacon-chain/core/feed/state:go_default_library",
|
||||||
"//beacon-chain/core/helpers:go_default_library",
|
"//beacon-chain/core/helpers:go_default_library",
|
||||||
|
"//beacon-chain/core/peerdas:go_default_library",
|
||||||
"//beacon-chain/core/signing:go_default_library",
|
"//beacon-chain/core/signing:go_default_library",
|
||||||
"//beacon-chain/core/time:go_default_library",
|
"//beacon-chain/core/time:go_default_library",
|
||||||
"//beacon-chain/core/transition:go_default_library",
|
"//beacon-chain/core/transition:go_default_library",
|
||||||
@@ -84,7 +88,6 @@ go_library(
|
|||||||
"//math:go_default_library",
|
"//math:go_default_library",
|
||||||
"//monitoring/tracing:go_default_library",
|
"//monitoring/tracing:go_default_library",
|
||||||
"//monitoring/tracing/trace:go_default_library",
|
"//monitoring/tracing/trace:go_default_library",
|
||||||
"//network/forks:go_default_library",
|
|
||||||
"//proto/engine/v1:go_default_library",
|
"//proto/engine/v1:go_default_library",
|
||||||
"//proto/eth/v1:go_default_library",
|
"//proto/eth/v1:go_default_library",
|
||||||
"//proto/prysm/v1alpha1:go_default_library",
|
"//proto/prysm/v1alpha1:go_default_library",
|
||||||
@@ -180,7 +183,6 @@ common_deps = [
|
|||||||
"@org_golang_google_protobuf//types/known/emptypb:go_default_library",
|
"@org_golang_google_protobuf//types/known/emptypb:go_default_library",
|
||||||
]
|
]
|
||||||
|
|
||||||
# gazelle:ignore
|
|
||||||
go_test(
|
go_test(
|
||||||
name = "go_default_test",
|
name = "go_default_test",
|
||||||
timeout = "moderate",
|
timeout = "moderate",
|
||||||
|
|||||||
@@ -8,13 +8,18 @@ import (
|
|||||||
enginev1 "github.com/OffchainLabs/prysm/v6/proto/engine/v1"
|
enginev1 "github.com/OffchainLabs/prysm/v6/proto/engine/v1"
|
||||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||||
"github.com/OffchainLabs/prysm/v6/runtime/version"
|
"github.com/OffchainLabs/prysm/v6/runtime/version"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
// constructGenericBeaconBlock constructs a `GenericBeaconBlock` based on the block version and other parameters.
|
// constructGenericBeaconBlock constructs a `GenericBeaconBlock` based on the block version and other parameters.
|
||||||
func (vs *Server) constructGenericBeaconBlock(sBlk interfaces.SignedBeaconBlock, blobsBundle *enginev1.BlobsBundle, winningBid primitives.Wei) (*ethpb.GenericBeaconBlock, error) {
|
func (vs *Server) constructGenericBeaconBlock(
|
||||||
|
sBlk interfaces.SignedBeaconBlock,
|
||||||
|
blobsBundler enginev1.BlobsBundler,
|
||||||
|
winningBid primitives.Wei,
|
||||||
|
) (*ethpb.GenericBeaconBlock, error) {
|
||||||
if sBlk == nil || sBlk.Block() == nil {
|
if sBlk == nil || sBlk.Block() == nil {
|
||||||
return nil, fmt.Errorf("block cannot be nil")
|
return nil, errors.New("block cannot be nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
blockProto, err := sBlk.Block().Proto()
|
blockProto, err := sBlk.Block().Proto()
|
||||||
@@ -34,12 +39,21 @@ func (vs *Server) constructGenericBeaconBlock(sBlk interfaces.SignedBeaconBlock,
|
|||||||
return vs.constructBellatrixBlock(blockProto, isBlinded, bidStr), nil
|
return vs.constructBellatrixBlock(blockProto, isBlinded, bidStr), nil
|
||||||
case version.Capella:
|
case version.Capella:
|
||||||
return vs.constructCapellaBlock(blockProto, isBlinded, bidStr), nil
|
return vs.constructCapellaBlock(blockProto, isBlinded, bidStr), nil
|
||||||
case version.Deneb:
|
case version.Deneb, version.Electra:
|
||||||
return vs.constructDenebBlock(blockProto, isBlinded, bidStr, blobsBundle), nil
|
bundle, ok := blobsBundler.(*enginev1.BlobsBundle)
|
||||||
case version.Electra:
|
if blobsBundler != nil && !ok {
|
||||||
return vs.constructElectraBlock(blockProto, isBlinded, bidStr, blobsBundle), nil
|
return nil, fmt.Errorf("expected *BlobsBundler, got %T", blobsBundler)
|
||||||
|
}
|
||||||
|
if sBlk.Version() == version.Deneb {
|
||||||
|
return vs.constructDenebBlock(blockProto, isBlinded, bidStr, bundle), nil
|
||||||
|
}
|
||||||
|
return vs.constructElectraBlock(blockProto, isBlinded, bidStr, bundle), nil
|
||||||
case version.Fulu:
|
case version.Fulu:
|
||||||
return vs.constructFuluBlock(blockProto, isBlinded, bidStr, blobsBundle), nil
|
bundle, ok := blobsBundler.(*enginev1.BlobsBundleV2)
|
||||||
|
if blobsBundler != nil && !ok {
|
||||||
|
return nil, fmt.Errorf("expected *BlobsBundleV2, got %T", blobsBundler)
|
||||||
|
}
|
||||||
|
return vs.constructFuluBlock(blockProto, isBlinded, bidStr, bundle), nil
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unknown block version: %d", sBlk.Version())
|
return nil, fmt.Errorf("unknown block version: %d", sBlk.Version())
|
||||||
}
|
}
|
||||||
@@ -92,7 +106,7 @@ func (vs *Server) constructElectraBlock(blockProto proto.Message, isBlinded bool
|
|||||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Electra{Electra: electraContents}, IsBlinded: false, PayloadValue: payloadValue}
|
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Electra{Electra: electraContents}, IsBlinded: false, PayloadValue: payloadValue}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vs *Server) constructFuluBlock(blockProto proto.Message, isBlinded bool, payloadValue string, bundle *enginev1.BlobsBundle) *ethpb.GenericBeaconBlock {
|
func (vs *Server) constructFuluBlock(blockProto proto.Message, isBlinded bool, payloadValue string, bundle *enginev1.BlobsBundleV2) *ethpb.GenericBeaconBlock {
|
||||||
if isBlinded {
|
if isBlinded {
|
||||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_BlindedFulu{BlindedFulu: blockProto.(*ethpb.BlindedBeaconBlockFulu)}, IsBlinded: true, PayloadValue: payloadValue}
|
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_BlindedFulu{BlindedFulu: blockProto.(*ethpb.BlindedBeaconBlockFulu)}, IsBlinded: true, PayloadValue: payloadValue}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,12 +29,19 @@ func TestConstructGenericBeaconBlock(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
r1, err := eb.Block.HashTreeRoot()
|
r1, err := eb.Block.HashTreeRoot()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
result, err := vs.constructGenericBeaconBlock(b, nil, primitives.ZeroWei())
|
bundle := &enginev1.BlobsBundleV2{
|
||||||
|
KzgCommitments: [][]byte{{1, 2, 3}},
|
||||||
|
Proofs: [][]byte{{4, 5, 6}},
|
||||||
|
Blobs: [][]byte{{7, 8, 9}},
|
||||||
|
}
|
||||||
|
result, err := vs.constructGenericBeaconBlock(b, bundle, primitives.ZeroWei())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
r2, err := result.GetFulu().Block.HashTreeRoot()
|
r2, err := result.GetFulu().Block.HashTreeRoot()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, r1, r2)
|
require.Equal(t, r1, r2)
|
||||||
require.Equal(t, result.IsBlinded, false)
|
require.Equal(t, result.IsBlinded, false)
|
||||||
|
require.DeepEqual(t, bundle.Blobs, result.GetFulu().GetBlobs())
|
||||||
|
require.DeepEqual(t, bundle.Proofs, result.GetFulu().GetKzgProofs())
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test for Electra version
|
// Test for Electra version
|
||||||
|
|||||||
@@ -15,9 +15,13 @@ import (
|
|||||||
blockfeed "github.com/OffchainLabs/prysm/v6/beacon-chain/core/feed/block"
|
blockfeed "github.com/OffchainLabs/prysm/v6/beacon-chain/core/feed/block"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/feed/operation"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/feed/operation"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/helpers"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/helpers"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/peerdas"
|
||||||
|
coreTime "github.com/OffchainLabs/prysm/v6/beacon-chain/core/time"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/transition"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/transition"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/db/kv"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/db/kv"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/config/features"
|
||||||
|
fieldparams "github.com/OffchainLabs/prysm/v6/config/fieldparams"
|
||||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/blocks"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/blocks"
|
||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/interfaces"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/interfaces"
|
||||||
@@ -58,28 +62,31 @@ func (vs *Server) GetBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Error("Could not convert slot to time")
|
log.WithError(err).Error("Could not convert slot to time")
|
||||||
}
|
}
|
||||||
log.WithFields(logrus.Fields{
|
|
||||||
"slot": req.Slot,
|
log := log.WithField("slot", req.Slot)
|
||||||
"sinceSlotStartTime": time.Since(t),
|
log.WithField("sinceSlotStartTime", time.Since(t)).Info("Begin building block")
|
||||||
}).Info("Begin building block")
|
|
||||||
|
|
||||||
// A syncing validator should not produce a block.
|
// A syncing validator should not produce a block.
|
||||||
if vs.SyncChecker.Syncing() {
|
if vs.SyncChecker.Syncing() {
|
||||||
|
log.Error("Fail to build block: node is syncing")
|
||||||
return nil, status.Error(codes.Unavailable, "Syncing to latest head, not ready to respond")
|
return nil, status.Error(codes.Unavailable, "Syncing to latest head, not ready to respond")
|
||||||
}
|
}
|
||||||
// An optimistic validator MUST NOT produce a block (i.e., sign across the DOMAIN_BEACON_PROPOSER domain).
|
// An optimistic validator MUST NOT produce a block (i.e., sign across the DOMAIN_BEACON_PROPOSER domain).
|
||||||
if slots.ToEpoch(req.Slot) >= params.BeaconConfig().BellatrixForkEpoch {
|
if slots.ToEpoch(req.Slot) >= params.BeaconConfig().BellatrixForkEpoch {
|
||||||
if err := vs.optimisticStatus(ctx); err != nil {
|
if err := vs.optimisticStatus(ctx); err != nil {
|
||||||
|
log.WithError(err).Error("Fail to build block: node is optimistic")
|
||||||
return nil, status.Errorf(codes.Unavailable, "Validator is not ready to propose: %v", err)
|
return nil, status.Errorf(codes.Unavailable, "Validator is not ready to propose: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
head, parentRoot, err := vs.getParentState(ctx, req.Slot)
|
head, parentRoot, err := vs.getParentState(ctx, req.Slot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Fail to build block: could not get parent state")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
sBlk, err := getEmptyBlock(req.Slot)
|
sBlk, err := getEmptyBlock(req.Slot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Fail to build block: could not get empty block")
|
||||||
return nil, status.Errorf(codes.Internal, "Could not prepare block: %v", err)
|
return nil, status.Errorf(codes.Internal, "Could not prepare block: %v", err)
|
||||||
}
|
}
|
||||||
// Set slot, graffiti, randao reveal, and parent root.
|
// Set slot, graffiti, randao reveal, and parent root.
|
||||||
@@ -91,6 +98,7 @@ func (vs *Server) GetBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (
|
|||||||
// Set proposer index.
|
// Set proposer index.
|
||||||
idx, err := helpers.BeaconProposerIndex(ctx, head)
|
idx, err := helpers.BeaconProposerIndex(ctx, head)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Fail to build block: could not calculate proposer index")
|
||||||
return nil, fmt.Errorf("could not calculate proposer index %w", err)
|
return nil, fmt.Errorf("could not calculate proposer index %w", err)
|
||||||
}
|
}
|
||||||
sBlk.SetProposerIndex(idx)
|
sBlk.SetProposerIndex(idx)
|
||||||
@@ -101,7 +109,7 @@ func (vs *Server) GetBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
resp, err := vs.BuildBlockParallel(ctx, sBlk, head, req.SkipMevBoost, builderBoostFactor)
|
resp, err := vs.BuildBlockParallel(ctx, sBlk, head, req.SkipMevBoost, builderBoostFactor)
|
||||||
log := log.WithFields(logrus.Fields{
|
log = log.WithFields(logrus.Fields{
|
||||||
"slot": req.Slot,
|
"slot": req.Slot,
|
||||||
"sinceSlotStartTime": time.Since(t),
|
"sinceSlotStartTime": time.Since(t),
|
||||||
"validator": sBlk.Block().ProposerIndex(),
|
"validator": sBlk.Block().ProposerIndex(),
|
||||||
@@ -232,7 +240,7 @@ func (vs *Server) BuildBlockParallel(ctx context.Context, sBlk interfaces.Signed
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
winningBid := primitives.ZeroWei()
|
winningBid := primitives.ZeroWei()
|
||||||
var bundle *enginev1.BlobsBundle
|
var bundle enginev1.BlobsBundler
|
||||||
if sBlk.Version() >= version.Bellatrix {
|
if sBlk.Version() >= version.Bellatrix {
|
||||||
local, err := vs.getLocalPayload(ctx, sBlk.Block(), head)
|
local, err := vs.getLocalPayload(ctx, sBlk.Block(), head)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -274,7 +282,13 @@ func (vs *Server) BuildBlockParallel(ctx context.Context, sBlk interfaces.Signed
|
|||||||
// Deprecated: The gRPC API will remain the default and fully supported through v8 (expected in 2026) but will be eventually removed in favor of REST API.
|
// Deprecated: The gRPC API will remain the default and fully supported through v8 (expected in 2026) but will be eventually removed in favor of REST API.
|
||||||
//
|
//
|
||||||
// ProposeBeaconBlock handles the proposal of beacon blocks.
|
// ProposeBeaconBlock handles the proposal of beacon blocks.
|
||||||
|
// TODO: Add tests
|
||||||
func (vs *Server) ProposeBeaconBlock(ctx context.Context, req *ethpb.GenericSignedBeaconBlock) (*ethpb.ProposeResponse, error) {
|
func (vs *Server) ProposeBeaconBlock(ctx context.Context, req *ethpb.GenericSignedBeaconBlock) (*ethpb.ProposeResponse, error) {
|
||||||
|
var (
|
||||||
|
blobSidecars []*ethpb.BlobSidecar
|
||||||
|
dataColumnSideCars []*ethpb.DataColumnSidecar
|
||||||
|
)
|
||||||
|
|
||||||
ctx, span := trace.StartSpan(ctx, "ProposerServer.ProposeBeaconBlock")
|
ctx, span := trace.StartSpan(ctx, "ProposerServer.ProposeBeaconBlock")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
@@ -286,12 +300,12 @@ func (vs *Server) ProposeBeaconBlock(ctx context.Context, req *ethpb.GenericSign
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.Errorf(codes.InvalidArgument, "%s: %v", "decode block failed", err)
|
return nil, status.Errorf(codes.InvalidArgument, "%s: %v", "decode block failed", err)
|
||||||
}
|
}
|
||||||
|
isPeerDASEnabled := coreTime.PeerDASIsActive(block.Block().Slot())
|
||||||
|
|
||||||
var sidecars []*ethpb.BlobSidecar
|
|
||||||
if block.IsBlinded() {
|
if block.IsBlinded() {
|
||||||
block, sidecars, err = vs.handleBlindedBlock(ctx, block)
|
block, blobSidecars, dataColumnSideCars, err = vs.handleBlindedBlock(ctx, block, isPeerDASEnabled)
|
||||||
} else if block.Version() >= version.Deneb {
|
} else if block.Version() >= version.Deneb {
|
||||||
sidecars, err = vs.blobSidecarsFromUnblindedBlock(block, req)
|
blobSidecars, dataColumnSideCars, err = vs.handleUnblindedBlock(block, req, isPeerDASEnabled)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.Errorf(codes.Internal, "%s: %v", "handle block failed", err)
|
return nil, status.Errorf(codes.Internal, "%s: %v", "handle block failed", err)
|
||||||
@@ -302,9 +316,10 @@ func (vs *Server) ProposeBeaconBlock(ctx context.Context, req *ethpb.GenericSign
|
|||||||
return nil, status.Errorf(codes.Internal, "Could not hash tree root: %v", err)
|
return nil, status.Errorf(codes.Internal, "Could not hash tree root: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
slot := block.Block().Slot()
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
errChan := make(chan error, 1)
|
errChan := make(chan error, 1)
|
||||||
|
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
@@ -315,8 +330,14 @@ func (vs *Server) ProposeBeaconBlock(ctx context.Context, req *ethpb.GenericSign
|
|||||||
errChan <- nil
|
errChan <- nil
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if err := vs.broadcastAndReceiveBlobs(ctx, sidecars, root); err != nil {
|
if isPeerDASEnabled {
|
||||||
return nil, status.Errorf(codes.Internal, "Could not broadcast/receive blobs: %v", err)
|
if err := vs.broadcastAndReceiveDataColumns(ctx, dataColumnSideCars, root, slot); err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "Could not broadcast/receive data columns: %v", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := vs.broadcastAndReceiveBlobs(ctx, blobSidecars, root); err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "Could not broadcast/receive blobs: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
@@ -328,46 +349,75 @@ func (vs *Server) ProposeBeaconBlock(ctx context.Context, req *ethpb.GenericSign
|
|||||||
}
|
}
|
||||||
|
|
||||||
// handleBlindedBlock processes blinded beacon blocks.
|
// handleBlindedBlock processes blinded beacon blocks.
|
||||||
func (vs *Server) handleBlindedBlock(ctx context.Context, block interfaces.SignedBeaconBlock) (interfaces.SignedBeaconBlock, []*ethpb.BlobSidecar, error) {
|
func (vs *Server) handleBlindedBlock(ctx context.Context, block interfaces.SignedBeaconBlock, isPeerDASEnabled bool) (interfaces.SignedBeaconBlock, []*ethpb.BlobSidecar, []*ethpb.DataColumnSidecar, error) {
|
||||||
if block.Version() < version.Bellatrix {
|
if block.Version() < version.Bellatrix {
|
||||||
return nil, nil, errors.New("pre-Bellatrix blinded block")
|
return nil, nil, nil, errors.New("pre-Bellatrix blinded block")
|
||||||
}
|
}
|
||||||
|
|
||||||
if vs.BlockBuilder == nil || !vs.BlockBuilder.Configured() {
|
if vs.BlockBuilder == nil || !vs.BlockBuilder.Configured() {
|
||||||
return nil, nil, errors.New("unconfigured block builder")
|
return nil, nil, nil, errors.New("unconfigured block builder")
|
||||||
}
|
}
|
||||||
|
|
||||||
copiedBlock, err := block.Copy()
|
copiedBlock, err := block.Copy()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, nil, errors.Wrap(err, "block copy")
|
||||||
}
|
}
|
||||||
|
|
||||||
payload, bundle, err := vs.BlockBuilder.SubmitBlindedBlock(ctx, block)
|
payload, bundle, err := vs.BlockBuilder.SubmitBlindedBlock(ctx, block)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, errors.Wrap(err, "submit blinded block failed")
|
return nil, nil, nil, errors.Wrap(err, "submit blinded block")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := copiedBlock.Unblind(payload); err != nil {
|
if err := copiedBlock.Unblind(payload); err != nil {
|
||||||
return nil, nil, errors.Wrap(err, "unblind failed")
|
return nil, nil, nil, errors.Wrap(err, "unblind")
|
||||||
}
|
}
|
||||||
|
|
||||||
sidecars, err := unblindBlobsSidecars(copiedBlock, bundle)
|
if isPeerDASEnabled {
|
||||||
|
dataColumnSideCars, err := peerdas.ConstructDataColumnSidecars(block, bundle.GetBlobs(), bundle.GetProofs())
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, errors.Wrap(err, "construct data column sidecars")
|
||||||
|
}
|
||||||
|
|
||||||
|
return copiedBlock, nil, dataColumnSideCars, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
blobSidecars, err := unblindBlobsSidecars(copiedBlock, bundle)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, errors.Wrap(err, "unblind blobs sidecars: commitment value doesn't match block")
|
return nil, nil, nil, errors.Wrap(err, "unblind blobs sidecars: commitment value doesn't match block")
|
||||||
}
|
}
|
||||||
|
|
||||||
return copiedBlock, sidecars, nil
|
return copiedBlock, blobSidecars, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vs *Server) blobSidecarsFromUnblindedBlock(block interfaces.SignedBeaconBlock, req *ethpb.GenericSignedBeaconBlock) ([]*ethpb.BlobSidecar, error) {
|
func (vs *Server) handleUnblindedBlock(
|
||||||
|
block interfaces.SignedBeaconBlock,
|
||||||
|
req *ethpb.GenericSignedBeaconBlock,
|
||||||
|
isPeerDASEnabled bool,
|
||||||
|
) ([]*ethpb.BlobSidecar, []*ethpb.DataColumnSidecar, error) {
|
||||||
rawBlobs, proofs, err := blobsAndProofs(req)
|
rawBlobs, proofs, err := blobsAndProofs(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
return BuildBlobSidecars(block, rawBlobs, proofs)
|
|
||||||
|
if isPeerDASEnabled {
|
||||||
|
dataColumnSideCars, err := peerdas.ConstructDataColumnSidecars(block, rawBlobs, proofs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, errors.Wrap(err, "construct data column sidecars")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, dataColumnSideCars, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
blobSidecars, err := BuildBlobSidecars(block, rawBlobs, proofs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, errors.Wrap(err, "build blob sidecars")
|
||||||
|
}
|
||||||
|
|
||||||
|
return blobSidecars, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// broadcastReceiveBlock broadcasts a block and handles its reception.
|
// broadcastReceiveBlock broadcasts a block and handles its reception.
|
||||||
func (vs *Server) broadcastReceiveBlock(ctx context.Context, block interfaces.SignedBeaconBlock, root [32]byte) error {
|
func (vs *Server) broadcastReceiveBlock(ctx context.Context, block interfaces.SignedBeaconBlock, root [fieldparams.RootLength]byte) error {
|
||||||
protoBlock, err := block.Proto()
|
protoBlock, err := block.Proto()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "protobuf conversion failed")
|
return errors.Wrap(err, "protobuf conversion failed")
|
||||||
@@ -383,7 +433,7 @@ func (vs *Server) broadcastReceiveBlock(ctx context.Context, block interfaces.Si
|
|||||||
}
|
}
|
||||||
|
|
||||||
// broadcastAndReceiveBlobs handles the broadcasting and reception of blob sidecars.
|
// broadcastAndReceiveBlobs handles the broadcasting and reception of blob sidecars.
|
||||||
func (vs *Server) broadcastAndReceiveBlobs(ctx context.Context, sidecars []*ethpb.BlobSidecar, root [32]byte) error {
|
func (vs *Server) broadcastAndReceiveBlobs(ctx context.Context, sidecars []*ethpb.BlobSidecar, root [fieldparams.RootLength]byte) error {
|
||||||
eg, eCtx := errgroup.WithContext(ctx)
|
eg, eCtx := errgroup.WithContext(ctx)
|
||||||
for i, sc := range sidecars {
|
for i, sc := range sidecars {
|
||||||
// Copy the iteration instance to a local variable to give each go-routine its own copy to play with.
|
// Copy the iteration instance to a local variable to give each go-routine its own copy to play with.
|
||||||
@@ -412,6 +462,69 @@ func (vs *Server) broadcastAndReceiveBlobs(ctx context.Context, sidecars []*ethp
|
|||||||
return eg.Wait()
|
return eg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// broadcastAndReceiveDataColumns handles the broadcasting and reception of data columns sidecars.
|
||||||
|
func (vs *Server) broadcastAndReceiveDataColumns(
|
||||||
|
ctx context.Context,
|
||||||
|
sidecars []*ethpb.DataColumnSidecar,
|
||||||
|
root [fieldparams.RootLength]byte,
|
||||||
|
slot primitives.Slot,
|
||||||
|
) error {
|
||||||
|
dataColumnsWithholdCount := features.Get().DataColumnsWithholdCount
|
||||||
|
verifiedRODataColumns := make([]blocks.VerifiedRODataColumn, 0, len(sidecars))
|
||||||
|
|
||||||
|
eg, _ := errgroup.WithContext(ctx)
|
||||||
|
for _, sd := range sidecars {
|
||||||
|
roDataColumn, err := blocks.NewRODataColumnWithRoot(sd, root)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "new read-only data column with root")
|
||||||
|
}
|
||||||
|
|
||||||
|
// We build this block ourselves, so we can upgrade the read only data column sidecar into a verified one.
|
||||||
|
verifiedRODataColumn := blocks.NewVerifiedRODataColumn(roDataColumn)
|
||||||
|
verifiedRODataColumns = append(verifiedRODataColumns, verifiedRODataColumn)
|
||||||
|
|
||||||
|
// Copy the iteration instance to a local variable to give each go-routine its own copy to play with.
|
||||||
|
// See https://golang.org/doc/faq#closures_and_goroutines for more details.
|
||||||
|
sidecar := sd
|
||||||
|
eg.Go(func() error {
|
||||||
|
if sidecar.Index < dataColumnsWithholdCount {
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"root": fmt.Sprintf("%#x", root),
|
||||||
|
"slot": slot,
|
||||||
|
"index": sidecar.Index,
|
||||||
|
}).Warning("Withholding data column")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the subnet index based on the column index.
|
||||||
|
subnet := peerdas.ComputeSubnetForDataColumnSidecar(sidecar.Index)
|
||||||
|
|
||||||
|
if err := vs.P2P.BroadcastDataColumn(root, subnet, sidecar); err != nil {
|
||||||
|
return errors.Wrap(err, "broadcast data column")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := eg.Wait(); err != nil {
|
||||||
|
return errors.Wrap(err, "wait for data columns to be broadcasted")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := vs.DataColumnReceiver.ReceiveDataColumns(verifiedRODataColumns); err != nil {
|
||||||
|
return errors.Wrap(err, "receive data column")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, verifiedRODataColumn := range verifiedRODataColumns {
|
||||||
|
vs.OperationNotifier.OperationFeed().Send(&feed.Event{
|
||||||
|
Type: operation.DataColumnSidecarReceived,
|
||||||
|
Data: &operation.DataColumnSidecarReceivedData{DataColumn: &verifiedRODataColumn}, // #nosec G601
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Deprecated: The gRPC API will remain the default and fully supported through v8 (expected in 2026) but will be eventually removed in favor of REST API.
|
// Deprecated: The gRPC API will remain the default and fully supported through v8 (expected in 2026) but will be eventually removed in favor of REST API.
|
||||||
//
|
//
|
||||||
// PrepareBeaconProposer caches and updates the fee recipient for the given proposer.
|
// PrepareBeaconProposer caches and updates the fee recipient for the given proposer.
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/encoding/ssz"
|
"github.com/OffchainLabs/prysm/v6/encoding/ssz"
|
||||||
"github.com/OffchainLabs/prysm/v6/monitoring/tracing"
|
"github.com/OffchainLabs/prysm/v6/monitoring/tracing"
|
||||||
"github.com/OffchainLabs/prysm/v6/monitoring/tracing/trace"
|
"github.com/OffchainLabs/prysm/v6/monitoring/tracing/trace"
|
||||||
"github.com/OffchainLabs/prysm/v6/network/forks"
|
|
||||||
enginev1 "github.com/OffchainLabs/prysm/v6/proto/engine/v1"
|
enginev1 "github.com/OffchainLabs/prysm/v6/proto/engine/v1"
|
||||||
"github.com/OffchainLabs/prysm/v6/runtime/version"
|
"github.com/OffchainLabs/prysm/v6/runtime/version"
|
||||||
"github.com/OffchainLabs/prysm/v6/time/slots"
|
"github.com/OffchainLabs/prysm/v6/time/slots"
|
||||||
@@ -54,7 +53,7 @@ const blockBuilderTimeout = 1 * time.Second
|
|||||||
const gasLimitAdjustmentFactor = 1024
|
const gasLimitAdjustmentFactor = 1024
|
||||||
|
|
||||||
// Sets the execution data for the block. Execution data can come from local EL client or remote builder depends on validator registration and circuit breaker conditions.
|
// Sets the execution data for the block. Execution data can come from local EL client or remote builder depends on validator registration and circuit breaker conditions.
|
||||||
func setExecutionData(ctx context.Context, blk interfaces.SignedBeaconBlock, local *blocks.GetPayloadResponse, bid builder.Bid, builderBoostFactor primitives.Gwei) (primitives.Wei, *enginev1.BlobsBundle, error) {
|
func setExecutionData(ctx context.Context, blk interfaces.SignedBeaconBlock, local *blocks.GetPayloadResponse, bid builder.Bid, builderBoostFactor primitives.Gwei) (primitives.Wei, enginev1.BlobsBundler, error) {
|
||||||
_, span := trace.StartSpan(ctx, "ProposerServer.setExecutionData")
|
_, span := trace.StartSpan(ctx, "ProposerServer.setExecutionData")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
@@ -69,13 +68,13 @@ func setExecutionData(ctx context.Context, blk interfaces.SignedBeaconBlock, loc
|
|||||||
|
|
||||||
// Use local payload if builder payload is nil.
|
// Use local payload if builder payload is nil.
|
||||||
if bid == nil {
|
if bid == nil {
|
||||||
return local.Bid, local.BlobsBundle, setLocalExecution(blk, local)
|
return local.Bid, local.BlobsBundler, setLocalExecution(blk, local)
|
||||||
}
|
}
|
||||||
|
|
||||||
builderPayload, err := bid.Header()
|
builderPayload, err := bid.Header()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Warn("Proposer: failed to retrieve header from BuilderBid")
|
log.WithError(err).Warn("Proposer: failed to retrieve header from BuilderBid")
|
||||||
return local.Bid, local.BlobsBundle, setLocalExecution(blk, local)
|
return local.Bid, local.BlobsBundler, setLocalExecution(blk, local)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
@@ -84,7 +83,7 @@ func setExecutionData(ctx context.Context, blk interfaces.SignedBeaconBlock, loc
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
tracing.AnnotateError(span, err)
|
tracing.AnnotateError(span, err)
|
||||||
log.WithError(err).Warn("Proposer: failed to match withdrawals root")
|
log.WithError(err).Warn("Proposer: failed to match withdrawals root")
|
||||||
return local.Bid, local.BlobsBundle, setLocalExecution(blk, local)
|
return local.Bid, local.BlobsBundler, setLocalExecution(blk, local)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compare payload values between local and builder. Default to the local value if it is higher.
|
// Compare payload values between local and builder. Default to the local value if it is higher.
|
||||||
@@ -97,7 +96,7 @@ func setExecutionData(ctx context.Context, blk interfaces.SignedBeaconBlock, loc
|
|||||||
"minBuilderBid": minBid,
|
"minBuilderBid": minBid,
|
||||||
"builderGweiValue": builderValueGwei,
|
"builderGweiValue": builderValueGwei,
|
||||||
}).Warn("Proposer: using local execution payload because min bid not attained")
|
}).Warn("Proposer: using local execution payload because min bid not attained")
|
||||||
return local.Bid, local.BlobsBundle, setLocalExecution(blk, local)
|
return local.Bid, local.BlobsBundler, setLocalExecution(blk, local)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use local block if min difference is not attained
|
// Use local block if min difference is not attained
|
||||||
@@ -108,7 +107,7 @@ func setExecutionData(ctx context.Context, blk interfaces.SignedBeaconBlock, loc
|
|||||||
"minBidDiff": minDiff,
|
"minBidDiff": minDiff,
|
||||||
"builderGweiValue": builderValueGwei,
|
"builderGweiValue": builderValueGwei,
|
||||||
}).Warn("Proposer: using local execution payload because min difference with local value was not attained")
|
}).Warn("Proposer: using local execution payload because min difference with local value was not attained")
|
||||||
return local.Bid, local.BlobsBundle, setLocalExecution(blk, local)
|
return local.Bid, local.BlobsBundler, setLocalExecution(blk, local)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use builder payload if the following in true:
|
// Use builder payload if the following in true:
|
||||||
@@ -133,7 +132,7 @@ func setExecutionData(ctx context.Context, blk interfaces.SignedBeaconBlock, loc
|
|||||||
bidDeneb, ok := bid.(builder.BidDeneb)
|
bidDeneb, ok := bid.(builder.BidDeneb)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Warnf("bid type %T does not implement builder.BidDeneb", bid)
|
log.Warnf("bid type %T does not implement builder.BidDeneb", bid)
|
||||||
return local.Bid, local.BlobsBundle, setLocalExecution(blk, local)
|
return local.Bid, local.BlobsBundler, setLocalExecution(blk, local)
|
||||||
} else {
|
} else {
|
||||||
builderKzgCommitments = bidDeneb.BlobKzgCommitments()
|
builderKzgCommitments = bidDeneb.BlobKzgCommitments()
|
||||||
}
|
}
|
||||||
@@ -144,14 +143,14 @@ func setExecutionData(ctx context.Context, blk interfaces.SignedBeaconBlock, loc
|
|||||||
bidElectra, ok := bid.(builder.BidElectra)
|
bidElectra, ok := bid.(builder.BidElectra)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Warnf("bid type %T does not implement builder.BidElectra", bid)
|
log.Warnf("bid type %T does not implement builder.BidElectra", bid)
|
||||||
return local.Bid, local.BlobsBundle, setLocalExecution(blk, local)
|
return local.Bid, local.BlobsBundler, setLocalExecution(blk, local)
|
||||||
} else {
|
} else {
|
||||||
executionRequests = bidElectra.ExecutionRequests()
|
executionRequests = bidElectra.ExecutionRequests()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := setBuilderExecution(blk, builderPayload, builderKzgCommitments, executionRequests); err != nil {
|
if err := setBuilderExecution(blk, builderPayload, builderKzgCommitments, executionRequests); err != nil {
|
||||||
log.WithError(err).Warn("Proposer: failed to set builder payload")
|
log.WithError(err).Warn("Proposer: failed to set builder payload")
|
||||||
return local.Bid, local.BlobsBundle, setLocalExecution(blk, local)
|
return local.Bid, local.BlobsBundler, setLocalExecution(blk, local)
|
||||||
} else {
|
} else {
|
||||||
return bid.Value(), nil, nil
|
return bid.Value(), nil, nil
|
||||||
}
|
}
|
||||||
@@ -171,11 +170,11 @@ func setExecutionData(ctx context.Context, blk interfaces.SignedBeaconBlock, loc
|
|||||||
trace.Int64Attribute("builderGweiValue", int64(builderValueGwei)), // lint:ignore uintcast -- This is OK for tracing.
|
trace.Int64Attribute("builderGweiValue", int64(builderValueGwei)), // lint:ignore uintcast -- This is OK for tracing.
|
||||||
trace.Int64Attribute("builderBoostFactor", int64(builderBoostFactor)), // lint:ignore uintcast -- This is OK for tracing.
|
trace.Int64Attribute("builderBoostFactor", int64(builderBoostFactor)), // lint:ignore uintcast -- This is OK for tracing.
|
||||||
)
|
)
|
||||||
return local.Bid, local.BlobsBundle, setLocalExecution(blk, local)
|
return local.Bid, local.BlobsBundler, setLocalExecution(blk, local)
|
||||||
default: // Bellatrix case.
|
default: // Bellatrix case.
|
||||||
if err := setBuilderExecution(blk, builderPayload, nil, nil); err != nil {
|
if err := setBuilderExecution(blk, builderPayload, nil, nil); err != nil {
|
||||||
log.WithError(err).Warn("Proposer: failed to set builder payload")
|
log.WithError(err).Warn("Proposer: failed to set builder payload")
|
||||||
return local.Bid, local.BlobsBundle, setLocalExecution(blk, local)
|
return local.Bid, local.BlobsBundler, setLocalExecution(blk, local)
|
||||||
} else {
|
} else {
|
||||||
return bid.Value(), nil, nil
|
return bid.Value(), nil, nil
|
||||||
}
|
}
|
||||||
@@ -220,14 +219,9 @@ func (vs *Server) getPayloadHeaderFromBuilder(
|
|||||||
if signedBid == nil || signedBid.IsNil() {
|
if signedBid == nil || signedBid.IsNil() {
|
||||||
return nil, errors.New("builder returned nil bid")
|
return nil, errors.New("builder returned nil bid")
|
||||||
}
|
}
|
||||||
fork, err := forks.Fork(slots.ToEpoch(slot))
|
epoch := slots.ToEpoch(slot)
|
||||||
if err != nil {
|
entry := params.GetNetworkScheduleEntry(epoch)
|
||||||
return nil, errors.Wrap(err, "unable to get fork information")
|
forkName := version.String(entry.VersionEnum)
|
||||||
}
|
|
||||||
forkName, ok := params.BeaconConfig().ForkVersionNames[bytesutil.ToBytes4(fork.CurrentVersion)]
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("unable to find current fork in schedule")
|
|
||||||
}
|
|
||||||
if !strings.EqualFold(version.String(signedBid.Version()), forkName) {
|
if !strings.EqualFold(version.String(signedBid.Version()), forkName) {
|
||||||
return nil, fmt.Errorf("builder bid response version: %d is different from head block version: %d for epoch %d", signedBid.Version(), b.Version(), slots.ToEpoch(slot))
|
return nil, fmt.Errorf("builder bid response version: %d is different from head block version: %d for epoch %d", signedBid.Version(), b.Version(), slots.ToEpoch(slot))
|
||||||
}
|
}
|
||||||
@@ -375,8 +369,8 @@ func matchingWithdrawalsRoot(local, builder interfaces.ExecutionData) (bool, err
|
|||||||
// It delegates to setExecution for the actual work.
|
// It delegates to setExecution for the actual work.
|
||||||
func setLocalExecution(blk interfaces.SignedBeaconBlock, local *blocks.GetPayloadResponse) error {
|
func setLocalExecution(blk interfaces.SignedBeaconBlock, local *blocks.GetPayloadResponse) error {
|
||||||
var kzgCommitments [][]byte
|
var kzgCommitments [][]byte
|
||||||
if local.BlobsBundle != nil {
|
if local.BlobsBundler != nil {
|
||||||
kzgCommitments = local.BlobsBundle.KzgCommitments
|
kzgCommitments = local.BlobsBundler.GetKzgCommitments()
|
||||||
}
|
}
|
||||||
if local.ExecutionRequests != nil {
|
if local.ExecutionRequests != nil {
|
||||||
if err := blk.SetExecutionRequests(local.ExecutionRequests); err != nil {
|
if err := blk.SetExecutionRequests(local.ExecutionRequests); err != nil {
|
||||||
|
|||||||
@@ -519,7 +519,7 @@ func TestServer_setExecutionData(t *testing.T) {
|
|||||||
PayloadIDBytes: id,
|
PayloadIDBytes: id,
|
||||||
GetPayloadResponse: &blocks.GetPayloadResponse{
|
GetPayloadResponse: &blocks.GetPayloadResponse{
|
||||||
ExecutionData: ed,
|
ExecutionData: ed,
|
||||||
BlobsBundle: blobsBundle,
|
BlobsBundler: blobsBundle,
|
||||||
Bid: primitives.ZeroWei(),
|
Bid: primitives.ZeroWei(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -527,7 +527,7 @@ func TestServer_setExecutionData(t *testing.T) {
|
|||||||
res, err := vs.getLocalPayload(ctx, blk.Block(), capellaTransitionState)
|
res, err := vs.getLocalPayload(ctx, blk.Block(), capellaTransitionState)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, uint64(4), res.ExecutionData.BlockNumber())
|
require.Equal(t, uint64(4), res.ExecutionData.BlockNumber())
|
||||||
require.DeepEqual(t, res.BlobsBundle, blobsBundle)
|
require.DeepEqual(t, res.BlobsBundler, blobsBundle)
|
||||||
})
|
})
|
||||||
t.Run("Can get builder payload and blobs in Deneb", func(t *testing.T) {
|
t.Run("Can get builder payload and blobs in Deneb", func(t *testing.T) {
|
||||||
cfg := params.BeaconConfig().Copy()
|
cfg := params.BeaconConfig().Copy()
|
||||||
|
|||||||
@@ -529,7 +529,7 @@ func TestServer_GetBeaconBlock_Deneb(t *testing.T) {
|
|||||||
PayloadIDBytes: &enginev1.PayloadIDBytes{1},
|
PayloadIDBytes: &enginev1.PayloadIDBytes{1},
|
||||||
GetPayloadResponse: &blocks.GetPayloadResponse{
|
GetPayloadResponse: &blocks.GetPayloadResponse{
|
||||||
ExecutionData: ed,
|
ExecutionData: ed,
|
||||||
BlobsBundle: bundle,
|
BlobsBundler: bundle,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/sync"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/sync"
|
||||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
||||||
"github.com/OffchainLabs/prysm/v6/network/forks"
|
|
||||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||||
"github.com/OffchainLabs/prysm/v6/runtime/version"
|
"github.com/OffchainLabs/prysm/v6/runtime/version"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
@@ -67,6 +66,7 @@ type Server struct {
|
|||||||
SyncCommitteePool synccommittee.Pool
|
SyncCommitteePool synccommittee.Pool
|
||||||
BlockReceiver blockchain.BlockReceiver
|
BlockReceiver blockchain.BlockReceiver
|
||||||
BlobReceiver blockchain.BlobReceiver
|
BlobReceiver blockchain.BlobReceiver
|
||||||
|
DataColumnReceiver blockchain.DataColumnReceiver
|
||||||
MockEth1Votes bool
|
MockEth1Votes bool
|
||||||
Eth1BlockFetcher execution.POWBlockFetcher
|
Eth1BlockFetcher execution.POWBlockFetcher
|
||||||
PendingDepositsFetcher depositsnapshot.PendingDepositsFetcher
|
PendingDepositsFetcher depositsnapshot.PendingDepositsFetcher
|
||||||
@@ -155,7 +155,7 @@ func (vs *Server) ValidatorIndex(ctx context.Context, req *ethpb.ValidatorIndexR
|
|||||||
//
|
//
|
||||||
// DomainData fetches the current domain version information from the beacon state.
|
// DomainData fetches the current domain version information from the beacon state.
|
||||||
func (vs *Server) DomainData(ctx context.Context, request *ethpb.DomainRequest) (*ethpb.DomainResponse, error) {
|
func (vs *Server) DomainData(ctx context.Context, request *ethpb.DomainRequest) (*ethpb.DomainResponse, error) {
|
||||||
fork, err := forks.Fork(request.Epoch)
|
fork, err := params.Fork(request.Epoch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/testing/mock"
|
"github.com/OffchainLabs/prysm/v6/testing/mock"
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/util"
|
"github.com/OffchainLabs/prysm/v6/testing/util"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
logTest "github.com/sirupsen/logrus/hooks/test"
|
logTest "github.com/sirupsen/logrus/hooks/test"
|
||||||
"go.uber.org/mock/gomock"
|
"go.uber.org/mock/gomock"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
@@ -318,23 +319,16 @@ func TestWaitForChainStart_NotStartedThenLogFired(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestServer_DomainData_Exits(t *testing.T) {
|
func TestServer_DomainData_Exits(t *testing.T) {
|
||||||
params.SetupTestConfigCleanup(t)
|
params.SetActiveTestCleanup(t, params.MainnetConfig())
|
||||||
cfg := params.BeaconConfig().Copy()
|
cfg := params.BeaconConfig()
|
||||||
cfg.ForkVersionSchedule = map[[4]byte]primitives.Epoch{
|
beaconState := ðpb.BeaconStateDeneb{
|
||||||
[4]byte(cfg.GenesisForkVersion): primitives.Epoch(0),
|
Slot: 1 + primitives.Slot(cfg.DenebForkEpoch)*cfg.SlotsPerEpoch,
|
||||||
[4]byte(cfg.AltairForkVersion): primitives.Epoch(5),
|
GenesisValidatorsRoot: cfg.GenesisValidatorsRoot[:],
|
||||||
[4]byte(cfg.BellatrixForkVersion): primitives.Epoch(10),
|
|
||||||
[4]byte(cfg.CapellaForkVersion): primitives.Epoch(15),
|
|
||||||
[4]byte(cfg.DenebForkVersion): primitives.Epoch(20),
|
|
||||||
}
|
|
||||||
params.OverrideBeaconConfig(cfg)
|
|
||||||
beaconState := ðpb.BeaconStateBellatrix{
|
|
||||||
Slot: 4000,
|
|
||||||
}
|
}
|
||||||
block := util.NewBeaconBlock()
|
block := util.NewBeaconBlock()
|
||||||
genesisRoot, err := block.Block.HashTreeRoot()
|
genesisRoot, err := block.Block.HashTreeRoot()
|
||||||
require.NoError(t, err, "Could not get signing root")
|
require.NoError(t, err, "Could not get signing root")
|
||||||
s, err := state_native.InitializeFromProtoUnsafeBellatrix(beaconState)
|
s, err := state_native.InitializeFromProtoUnsafeDeneb(beaconState)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
vs := &Server{
|
vs := &Server{
|
||||||
Ctx: t.Context(),
|
Ctx: t.Context(),
|
||||||
@@ -342,14 +336,19 @@ func TestServer_DomainData_Exits(t *testing.T) {
|
|||||||
HeadFetcher: &mockChain.ChainService{State: s, Root: genesisRoot[:]},
|
HeadFetcher: &mockChain.ChainService{State: s, Root: genesisRoot[:]},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
epoch := cfg.DenebForkEpoch
|
||||||
reqDomain, err := vs.DomainData(t.Context(), ðpb.DomainRequest{
|
reqDomain, err := vs.DomainData(t.Context(), ðpb.DomainRequest{
|
||||||
Epoch: 100,
|
Epoch: epoch,
|
||||||
Domain: params.BeaconConfig().DomainDeposit[:],
|
Domain: cfg.DomainDeposit[:],
|
||||||
})
|
})
|
||||||
|
entry := params.GetNetworkScheduleEntry(epoch)
|
||||||
|
require.Equal(t, entry.ForkVersion, [4]byte(cfg.DenebForkVersion))
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
wantedDomain, err := signing.ComputeDomain(params.BeaconConfig().DomainDeposit, params.BeaconConfig().DenebForkVersion, make([]byte, 32))
|
gvr := cfg.GenesisValidatorsRoot
|
||||||
|
wantedDomain, err := signing.ComputeDomain(cfg.DomainDeposit, entry.ForkVersion[:], gvr[:])
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.DeepEqual(t, reqDomain.SignatureDomain, wantedDomain)
|
assert.Equal(t, true, hexutil.Encode(reqDomain.SignatureDomain), hexutil.Encode(wantedDomain))
|
||||||
|
|
||||||
beaconStateNew := ðpb.BeaconStateDeneb{
|
beaconStateNew := ðpb.BeaconStateDeneb{
|
||||||
Slot: 4000,
|
Slot: 4000,
|
||||||
@@ -360,11 +359,11 @@ func TestServer_DomainData_Exits(t *testing.T) {
|
|||||||
|
|
||||||
reqDomain, err = vs.DomainData(t.Context(), ðpb.DomainRequest{
|
reqDomain, err = vs.DomainData(t.Context(), ðpb.DomainRequest{
|
||||||
Epoch: 100,
|
Epoch: 100,
|
||||||
Domain: params.BeaconConfig().DomainVoluntaryExit[:],
|
Domain: cfg.DomainVoluntaryExit[:],
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
wantedDomain, err = signing.ComputeDomain(params.BeaconConfig().DomainVoluntaryExit, params.BeaconConfig().CapellaForkVersion, make([]byte, 32))
|
wantedDomain, err = signing.ComputeDomain(cfg.DomainVoluntaryExit, cfg.CapellaForkVersion, make([]byte, 32))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.DeepEqual(t, reqDomain.SignatureDomain, wantedDomain)
|
assert.DeepEqual(t, reqDomain.SignatureDomain, wantedDomain)
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ type Config struct {
|
|||||||
AttestationReceiver blockchain.AttestationReceiver
|
AttestationReceiver blockchain.AttestationReceiver
|
||||||
BlockReceiver blockchain.BlockReceiver
|
BlockReceiver blockchain.BlockReceiver
|
||||||
BlobReceiver blockchain.BlobReceiver
|
BlobReceiver blockchain.BlobReceiver
|
||||||
|
DataColumnReceiver blockchain.DataColumnReceiver
|
||||||
ExecutionChainService execution.Chain
|
ExecutionChainService execution.Chain
|
||||||
ChainStartFetcher execution.ChainStartFetcher
|
ChainStartFetcher execution.ChainStartFetcher
|
||||||
ExecutionChainInfoFetcher execution.ChainInfoFetcher
|
ExecutionChainInfoFetcher execution.ChainInfoFetcher
|
||||||
@@ -120,6 +121,7 @@ type Config struct {
|
|||||||
Router *http.ServeMux
|
Router *http.ServeMux
|
||||||
ClockWaiter startup.ClockWaiter
|
ClockWaiter startup.ClockWaiter
|
||||||
BlobStorage *filesystem.BlobStorage
|
BlobStorage *filesystem.BlobStorage
|
||||||
|
DataColumnStorage *filesystem.DataColumnStorage
|
||||||
TrackedValidatorsCache *cache.TrackedValidatorsCache
|
TrackedValidatorsCache *cache.TrackedValidatorsCache
|
||||||
PayloadIDCache *cache.PayloadIDCache
|
PayloadIDCache *cache.PayloadIDCache
|
||||||
LCStore *lightClient.Store
|
LCStore *lightClient.Store
|
||||||
@@ -196,6 +198,7 @@ func NewService(ctx context.Context, cfg *Config) *Service {
|
|||||||
ChainInfoFetcher: s.cfg.ChainInfoFetcher,
|
ChainInfoFetcher: s.cfg.ChainInfoFetcher,
|
||||||
GenesisTimeFetcher: s.cfg.GenesisTimeFetcher,
|
GenesisTimeFetcher: s.cfg.GenesisTimeFetcher,
|
||||||
BlobStorage: s.cfg.BlobStorage,
|
BlobStorage: s.cfg.BlobStorage,
|
||||||
|
DataColumnStorage: s.cfg.DataColumnStorage,
|
||||||
}
|
}
|
||||||
rewardFetcher := &rewards.BlockRewardService{Replayer: ch, DB: s.cfg.BeaconDB}
|
rewardFetcher := &rewards.BlockRewardService{Replayer: ch, DB: s.cfg.BeaconDB}
|
||||||
coreService := &core.Service{
|
coreService := &core.Service{
|
||||||
@@ -236,6 +239,7 @@ func NewService(ctx context.Context, cfg *Config) *Service {
|
|||||||
P2P: s.cfg.Broadcaster,
|
P2P: s.cfg.Broadcaster,
|
||||||
BlockReceiver: s.cfg.BlockReceiver,
|
BlockReceiver: s.cfg.BlockReceiver,
|
||||||
BlobReceiver: s.cfg.BlobReceiver,
|
BlobReceiver: s.cfg.BlobReceiver,
|
||||||
|
DataColumnReceiver: s.cfg.DataColumnReceiver,
|
||||||
MockEth1Votes: s.cfg.MockEth1Votes,
|
MockEth1Votes: s.cfg.MockEth1Votes,
|
||||||
Eth1BlockFetcher: s.cfg.ExecutionChainService,
|
Eth1BlockFetcher: s.cfg.ExecutionChainService,
|
||||||
PendingDepositsFetcher: s.cfg.PendingDepositFetcher,
|
PendingDepositsFetcher: s.cfg.PendingDepositFetcher,
|
||||||
|
|||||||
@@ -35,12 +35,21 @@ func (g *Clock) GenesisValidatorsRoot() [32]byte {
|
|||||||
return g.vr
|
return g.vr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GenesisValidatorsRoot returns the genesis state validator root as a slice for convenience.
|
||||||
|
func (g *Clock) GenesisValidatorsRootSlice() []byte {
|
||||||
|
return g.vr[:]
|
||||||
|
}
|
||||||
|
|
||||||
// CurrentSlot returns the current slot relative to the time.Time value that Clock embeds.
|
// CurrentSlot returns the current slot relative to the time.Time value that Clock embeds.
|
||||||
func (g *Clock) CurrentSlot() types.Slot {
|
func (g *Clock) CurrentSlot() types.Slot {
|
||||||
now := g.now()
|
now := g.now()
|
||||||
return slots.Duration(g.t, now)
|
return slots.Duration(g.t, now)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *Clock) CurrentEpoch() types.Epoch {
|
||||||
|
return slots.ToEpoch(g.CurrentSlot())
|
||||||
|
}
|
||||||
|
|
||||||
// SlotStart computes the time the given slot begins.
|
// SlotStart computes the time the given slot begins.
|
||||||
func (g *Clock) SlotStart(slot types.Slot) time.Time {
|
func (g *Clock) SlotStart(slot types.Slot) time.Time {
|
||||||
return slots.BeginsAt(slot, g.t)
|
return slots.BeginsAt(slot, g.t)
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
package genesis
|
|
||||||
|
|
||||||
import (
|
|
||||||
_ "embed"
|
|
||||||
|
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
|
|
||||||
state_native "github.com/OffchainLabs/prysm/v6/beacon-chain/state/state-native"
|
|
||||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
|
||||||
"github.com/golang/snappy"
|
|
||||||
)
|
|
||||||
|
|
||||||
var embeddedStates = map[string]*[]byte{}
|
|
||||||
|
|
||||||
// State returns a copy of the genesis state from a hardcoded value.
|
|
||||||
func State(name string) (state.BeaconState, error) {
|
|
||||||
sb, exists := embeddedStates[name]
|
|
||||||
if exists {
|
|
||||||
return load(*sb)
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// load a compressed ssz state file into a beacon state struct.
|
|
||||||
func load(b []byte) (state.BeaconState, error) {
|
|
||||||
st := ðpb.BeaconState{}
|
|
||||||
b, err := snappy.Decode(nil /*dst*/, b)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := st.UnmarshalSSZ(b); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return state_native.InitializeFromProtoUnsafePhase0(st)
|
|
||||||
}
|
|
||||||
@@ -350,3 +350,7 @@ type WriteOnlyDeposits interface {
|
|||||||
type WriteOnlyProposerLookahead interface {
|
type WriteOnlyProposerLookahead interface {
|
||||||
SetProposerLookahead([]primitives.ValidatorIndex) error
|
SetProposerLookahead([]primitives.ValidatorIndex) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsNil(s BeaconState) bool {
|
||||||
|
return s == nil || s.IsNil()
|
||||||
|
}
|
||||||
|
|||||||
@@ -34,3 +34,7 @@ var fieldMap map[types.FieldIndex]types.DataType
|
|||||||
func errNotSupported(funcName string, ver int) error {
|
func errNotSupported(funcName string, ver int) error {
|
||||||
return fmt.Errorf("%s is not supported for %s", funcName, version.String(ver))
|
return fmt.Errorf("%s is not supported for %s", funcName, version.String(ver))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsNil(s state.BeaconState) bool {
|
||||||
|
return s == nil || s.IsNil()
|
||||||
|
}
|
||||||
|
|||||||
@@ -259,7 +259,7 @@ func (s *State) latestAncestor(ctx context.Context, blockRoot [32]byte) (state.B
|
|||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
if s.isFinalizedRoot(blockRoot) {
|
if s.isFinalizedRoot(blockRoot) {
|
||||||
finalizedState := s.finalizedState()
|
finalizedState := s.FinalizedState()
|
||||||
if finalizedState != nil {
|
if finalizedState != nil {
|
||||||
return finalizedState, nil
|
return finalizedState, nil
|
||||||
}
|
}
|
||||||
@@ -297,7 +297,7 @@ func (s *State) latestAncestor(ctx context.Context, blockRoot [32]byte) (state.B
|
|||||||
|
|
||||||
// Does the state exist in finalized info cache.
|
// Does the state exist in finalized info cache.
|
||||||
if s.isFinalizedRoot(parentRoot) {
|
if s.isFinalizedRoot(parentRoot) {
|
||||||
return s.finalizedState(), nil
|
return s.FinalizedState(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Does the state exist in epoch boundary cache.
|
// Does the state exist in epoch boundary cache.
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ func (s *State) isFinalizedRoot(r [32]byte) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns the cached and copied finalized state.
|
// Returns the cached and copied finalized state.
|
||||||
func (s *State) finalizedState() state.BeaconState {
|
func (s *State) FinalizedState() state.BeaconState {
|
||||||
s.finalizedInfo.lock.RLock()
|
s.finalizedInfo.lock.RLock()
|
||||||
defer s.finalizedInfo.lock.RUnlock()
|
defer s.finalizedInfo.lock.RUnlock()
|
||||||
return s.finalizedInfo.state.Copy()
|
return s.finalizedInfo.state.Copy()
|
||||||
|
|||||||
@@ -32,5 +32,5 @@ func TestResume(t *testing.T) {
|
|||||||
require.DeepSSZEqual(t, beaconState.ToProtoUnsafe(), resumeState.ToProtoUnsafe())
|
require.DeepSSZEqual(t, beaconState.ToProtoUnsafe(), resumeState.ToProtoUnsafe())
|
||||||
assert.Equal(t, params.BeaconConfig().SlotsPerEpoch, service.finalizedInfo.slot, "Did not get watned slot")
|
assert.Equal(t, params.BeaconConfig().SlotsPerEpoch, service.finalizedInfo.slot, "Did not get watned slot")
|
||||||
assert.Equal(t, service.finalizedInfo.root, root, "Did not get wanted root")
|
assert.Equal(t, service.finalizedInfo.root, root, "Did not get wanted root")
|
||||||
assert.NotNil(t, service.finalizedState(), "Wanted a non nil finalized state")
|
assert.NotNil(t, service.FinalizedState(), "Wanted a non nil finalized state")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ go_library(
|
|||||||
"block_batcher.go",
|
"block_batcher.go",
|
||||||
"broadcast_bls_changes.go",
|
"broadcast_bls_changes.go",
|
||||||
"context.go",
|
"context.go",
|
||||||
|
"data_columns.go",
|
||||||
|
"data_columns_reconstruct.go",
|
||||||
|
"data_columns_sampling.go",
|
||||||
"deadlines.go",
|
"deadlines.go",
|
||||||
"decode_pubsub.go",
|
"decode_pubsub.go",
|
||||||
"doc.go",
|
"doc.go",
|
||||||
@@ -34,12 +37,14 @@ go_library(
|
|||||||
"rpc_send_request.go",
|
"rpc_send_request.go",
|
||||||
"rpc_status.go",
|
"rpc_status.go",
|
||||||
"service.go",
|
"service.go",
|
||||||
|
"slot_aware_cache.go",
|
||||||
"subscriber.go",
|
"subscriber.go",
|
||||||
"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_blob_sidecar.go",
|
"subscriber_blob_sidecar.go",
|
||||||
"subscriber_bls_to_execution_change.go",
|
"subscriber_bls_to_execution_change.go",
|
||||||
|
"subscriber_data_column_sidecar.go",
|
||||||
"subscriber_handlers.go",
|
"subscriber_handlers.go",
|
||||||
"subscriber_light_client.go",
|
"subscriber_light_client.go",
|
||||||
"subscriber_sync_committee_message.go",
|
"subscriber_sync_committee_message.go",
|
||||||
@@ -57,6 +62,7 @@ go_library(
|
|||||||
"validate_sync_committee_message.go",
|
"validate_sync_committee_message.go",
|
||||||
"validate_sync_contribution_proof.go",
|
"validate_sync_contribution_proof.go",
|
||||||
"validate_voluntary_exit.go",
|
"validate_voluntary_exit.go",
|
||||||
|
"validators_custody.go",
|
||||||
],
|
],
|
||||||
importpath = "github.com/OffchainLabs/prysm/v6/beacon-chain/sync",
|
importpath = "github.com/OffchainLabs/prysm/v6/beacon-chain/sync",
|
||||||
visibility = [
|
visibility = [
|
||||||
@@ -78,6 +84,7 @@ go_library(
|
|||||||
"//beacon-chain/core/feed/state:go_default_library",
|
"//beacon-chain/core/feed/state:go_default_library",
|
||||||
"//beacon-chain/core/helpers:go_default_library",
|
"//beacon-chain/core/helpers:go_default_library",
|
||||||
"//beacon-chain/core/light-client:go_default_library",
|
"//beacon-chain/core/light-client:go_default_library",
|
||||||
|
"//beacon-chain/core/peerdas:go_default_library",
|
||||||
"//beacon-chain/core/signing:go_default_library",
|
"//beacon-chain/core/signing:go_default_library",
|
||||||
"//beacon-chain/core/transition:go_default_library",
|
"//beacon-chain/core/transition:go_default_library",
|
||||||
"//beacon-chain/core/transition/interop:go_default_library",
|
"//beacon-chain/core/transition/interop:go_default_library",
|
||||||
@@ -121,7 +128,6 @@ go_library(
|
|||||||
"//math:go_default_library",
|
"//math:go_default_library",
|
||||||
"//monitoring/tracing:go_default_library",
|
"//monitoring/tracing:go_default_library",
|
||||||
"//monitoring/tracing/trace:go_default_library",
|
"//monitoring/tracing/trace:go_default_library",
|
||||||
"//network/forks: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",
|
||||||
@@ -132,6 +138,7 @@ go_library(
|
|||||||
"//time:go_default_library",
|
"//time:go_default_library",
|
||||||
"//time/slots:go_default_library",
|
"//time/slots:go_default_library",
|
||||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||||
|
"@com_github_ethereum_go_ethereum//p2p/enode:go_default_library",
|
||||||
"@com_github_hashicorp_golang_lru//:go_default_library",
|
"@com_github_hashicorp_golang_lru//: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/host:go_default_library",
|
"@com_github_libp2p_go_libp2p//core/host:go_default_library",
|
||||||
@@ -155,13 +162,15 @@ go_library(
|
|||||||
|
|
||||||
go_test(
|
go_test(
|
||||||
name = "go_default_test",
|
name = "go_default_test",
|
||||||
size = "small",
|
size = "medium",
|
||||||
srcs = [
|
srcs = [
|
||||||
"batch_verifier_test.go",
|
"batch_verifier_test.go",
|
||||||
"blobs_test.go",
|
"blobs_test.go",
|
||||||
"block_batcher_test.go",
|
"block_batcher_test.go",
|
||||||
"broadcast_bls_changes_test.go",
|
"broadcast_bls_changes_test.go",
|
||||||
"context_test.go",
|
"context_test.go",
|
||||||
|
"data_columns_sampling_test.go",
|
||||||
|
"data_columns_test.go",
|
||||||
"decode_pubsub_test.go",
|
"decode_pubsub_test.go",
|
||||||
"error_test.go",
|
"error_test.go",
|
||||||
"fork_watcher_test.go",
|
"fork_watcher_test.go",
|
||||||
@@ -183,6 +192,7 @@ go_test(
|
|||||||
"rpc_status_test.go",
|
"rpc_status_test.go",
|
||||||
"rpc_test.go",
|
"rpc_test.go",
|
||||||
"service_test.go",
|
"service_test.go",
|
||||||
|
"slot_aware_cache_test.go",
|
||||||
"subscriber_beacon_aggregate_proof_test.go",
|
"subscriber_beacon_aggregate_proof_test.go",
|
||||||
"subscriber_beacon_blocks_test.go",
|
"subscriber_beacon_blocks_test.go",
|
||||||
"subscriber_test.go",
|
"subscriber_test.go",
|
||||||
@@ -201,19 +211,23 @@ go_test(
|
|||||||
"validate_sync_committee_message_test.go",
|
"validate_sync_committee_message_test.go",
|
||||||
"validate_sync_contribution_proof_test.go",
|
"validate_sync_contribution_proof_test.go",
|
||||||
"validate_voluntary_exit_test.go",
|
"validate_voluntary_exit_test.go",
|
||||||
|
"validators_custody_test.go",
|
||||||
],
|
],
|
||||||
embed = [":go_default_library"],
|
embed = [":go_default_library"],
|
||||||
shard_count = 4,
|
shard_count = 4,
|
||||||
deps = [
|
deps = [
|
||||||
"//async/abool:go_default_library",
|
"//async/abool:go_default_library",
|
||||||
"//beacon-chain/blockchain:go_default_library",
|
"//beacon-chain/blockchain:go_default_library",
|
||||||
|
"//beacon-chain/blockchain/kzg:go_default_library",
|
||||||
"//beacon-chain/blockchain/testing:go_default_library",
|
"//beacon-chain/blockchain/testing:go_default_library",
|
||||||
"//beacon-chain/cache:go_default_library",
|
"//beacon-chain/cache:go_default_library",
|
||||||
"//beacon-chain/core/altair:go_default_library",
|
"//beacon-chain/core/altair:go_default_library",
|
||||||
"//beacon-chain/core/feed:go_default_library",
|
"//beacon-chain/core/feed:go_default_library",
|
||||||
"//beacon-chain/core/feed/operation:go_default_library",
|
"//beacon-chain/core/feed/operation:go_default_library",
|
||||||
|
"//beacon-chain/core/feed/state:go_default_library",
|
||||||
"//beacon-chain/core/helpers:go_default_library",
|
"//beacon-chain/core/helpers:go_default_library",
|
||||||
"//beacon-chain/core/light-client:go_default_library",
|
"//beacon-chain/core/light-client:go_default_library",
|
||||||
|
"//beacon-chain/core/peerdas:go_default_library",
|
||||||
"//beacon-chain/core/signing:go_default_library",
|
"//beacon-chain/core/signing:go_default_library",
|
||||||
"//beacon-chain/core/time:go_default_library",
|
"//beacon-chain/core/time:go_default_library",
|
||||||
"//beacon-chain/core/transition:go_default_library",
|
"//beacon-chain/core/transition:go_default_library",
|
||||||
@@ -251,10 +265,10 @@ go_test(
|
|||||||
"//container/leaky-bucket:go_default_library",
|
"//container/leaky-bucket:go_default_library",
|
||||||
"//container/slice:go_default_library",
|
"//container/slice:go_default_library",
|
||||||
"//crypto/bls:go_default_library",
|
"//crypto/bls:go_default_library",
|
||||||
|
"//crypto/ecdsa:go_default_library",
|
||||||
"//crypto/rand:go_default_library",
|
"//crypto/rand:go_default_library",
|
||||||
"//encoding/bytesutil:go_default_library",
|
"//encoding/bytesutil:go_default_library",
|
||||||
"//encoding/ssz/equality:go_default_library",
|
"//encoding/ssz/equality:go_default_library",
|
||||||
"//network/forks:go_default_library",
|
|
||||||
"//proto/engine/v1: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",
|
||||||
@@ -265,13 +279,17 @@ go_test(
|
|||||||
"//testing/util:go_default_library",
|
"//testing/util:go_default_library",
|
||||||
"//time:go_default_library",
|
"//time:go_default_library",
|
||||||
"//time/slots:go_default_library",
|
"//time/slots:go_default_library",
|
||||||
|
"@com_github_consensys_gnark_crypto//ecc/bls12-381/fr:go_default_library",
|
||||||
|
"@com_github_crate_crypto_go_kzg_4844//:go_default_library",
|
||||||
"@com_github_d4l3k_messagediff//:go_default_library",
|
"@com_github_d4l3k_messagediff//:go_default_library",
|
||||||
"@com_github_ethereum_go_ethereum//common:go_default_library",
|
"@com_github_ethereum_go_ethereum//common:go_default_library",
|
||||||
"@com_github_ethereum_go_ethereum//core/types:go_default_library",
|
"@com_github_ethereum_go_ethereum//core/types:go_default_library",
|
||||||
|
"@com_github_ethereum_go_ethereum//p2p/enode:go_default_library",
|
||||||
"@com_github_ethereum_go_ethereum//p2p/enr:go_default_library",
|
"@com_github_ethereum_go_ethereum//p2p/enr:go_default_library",
|
||||||
"@com_github_golang_snappy//:go_default_library",
|
"@com_github_golang_snappy//:go_default_library",
|
||||||
"@com_github_libp2p_go_libp2p//:go_default_library",
|
"@com_github_libp2p_go_libp2p//: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/crypto: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",
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ go_library(
|
|||||||
"//consensus-types/primitives:go_default_library",
|
"//consensus-types/primitives:go_default_library",
|
||||||
"//crypto/bls:go_default_library",
|
"//crypto/bls:go_default_library",
|
||||||
"//encoding/bytesutil:go_default_library",
|
"//encoding/bytesutil:go_default_library",
|
||||||
"//network/forks:go_default_library",
|
|
||||||
"//proto/dbval:go_default_library",
|
"//proto/dbval:go_default_library",
|
||||||
"//proto/prysm/v1alpha1:go_default_library",
|
"//proto/prysm/v1alpha1:go_default_library",
|
||||||
"//runtime:go_default_library",
|
"//runtime:go_default_library",
|
||||||
@@ -80,7 +79,6 @@ go_test(
|
|||||||
"//consensus-types/primitives:go_default_library",
|
"//consensus-types/primitives:go_default_library",
|
||||||
"//crypto/bls:go_default_library",
|
"//crypto/bls:go_default_library",
|
||||||
"//encoding/bytesutil:go_default_library",
|
"//encoding/bytesutil:go_default_library",
|
||||||
"//network/forks:go_default_library",
|
|
||||||
"//proto/dbval:go_default_library",
|
"//proto/dbval:go_default_library",
|
||||||
"//runtime/interop:go_default_library",
|
"//runtime/interop:go_default_library",
|
||||||
"//testing/require:go_default_library",
|
"//testing/require:go_default_library",
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ func (s batchState) String() string {
|
|||||||
return "import_complete"
|
return "import_complete"
|
||||||
case batchEndSequence:
|
case batchEndSequence:
|
||||||
return "end_sequence"
|
return "end_sequence"
|
||||||
case batchBlobSync:
|
case batchSidecarSync:
|
||||||
return "blob_sync"
|
return "sidecar_sync"
|
||||||
default:
|
default:
|
||||||
return "unknown"
|
return "unknown"
|
||||||
}
|
}
|
||||||
@@ -50,7 +50,7 @@ const (
|
|||||||
batchInit
|
batchInit
|
||||||
batchSequenced
|
batchSequenced
|
||||||
batchErrRetryable
|
batchErrRetryable
|
||||||
batchBlobSync
|
batchSidecarSync
|
||||||
batchImportable
|
batchImportable
|
||||||
batchImportComplete
|
batchImportComplete
|
||||||
batchEndSequence
|
batchEndSequence
|
||||||
@@ -140,7 +140,7 @@ func (b batch) withResults(results verifiedROBlocks, bs *blobSync) batch {
|
|||||||
b.results = results
|
b.results = results
|
||||||
b.bs = bs
|
b.bs = bs
|
||||||
if bs.blobsNeeded() > 0 {
|
if bs.blobsNeeded() > 0 {
|
||||||
return b.withState(batchBlobSync)
|
return b.withState(batchSidecarSync)
|
||||||
}
|
}
|
||||||
return b.withState(batchImportable)
|
return b.withState(batchImportable)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ func (p *p2pBatchWorkerPool) batchRouter(pa PeerAssigner) {
|
|||||||
case b := <-p.fromWorkers:
|
case b := <-p.fromWorkers:
|
||||||
pid := b.busy
|
pid := b.busy
|
||||||
busy[pid] = false
|
busy[pid] = false
|
||||||
if b.state == batchBlobSync {
|
if b.state == batchSidecarSync {
|
||||||
todo = append(todo, b)
|
todo = append(todo, b)
|
||||||
sortBatchDesc(todo)
|
sortBatchDesc(todo)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
||||||
"github.com/OffchainLabs/prysm/v6/crypto/bls"
|
"github.com/OffchainLabs/prysm/v6/crypto/bls"
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
||||||
"github.com/OffchainLabs/prysm/v6/network/forks"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/runtime/version"
|
"github.com/OffchainLabs/prysm/v6/runtime/version"
|
||||||
"github.com/OffchainLabs/prysm/v6/time/slots"
|
"github.com/OffchainLabs/prysm/v6/time/slots"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@@ -107,8 +106,7 @@ func (vr verifier) blockSignatureBatch(b blocks.ROBlock) (*bls.SignatureBatch, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newBackfillVerifier(vr []byte, keys [][fieldparams.BLSPubkeyLength]byte) (*verifier, error) {
|
func newBackfillVerifier(vr []byte, keys [][fieldparams.BLSPubkeyLength]byte) (*verifier, error) {
|
||||||
dc, err := newDomainCache(vr, params.BeaconConfig().DomainBeaconProposer,
|
dc, err := newDomainCache(vr, params.BeaconConfig().DomainBeaconProposer)
|
||||||
forks.NewOrderedSchedule(params.BeaconConfig()))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -122,33 +120,31 @@ func newBackfillVerifier(vr []byte, keys [][fieldparams.BLSPubkeyLength]byte) (*
|
|||||||
|
|
||||||
// domainCache provides a fast signing domain lookup by epoch.
|
// domainCache provides a fast signing domain lookup by epoch.
|
||||||
type domainCache struct {
|
type domainCache struct {
|
||||||
fsched forks.OrderedSchedule
|
|
||||||
forkDomains map[[4]byte][]byte
|
forkDomains map[[4]byte][]byte
|
||||||
dType [bls.DomainByteLength]byte
|
dType [bls.DomainByteLength]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDomainCache(vRoot []byte, dType [bls.DomainByteLength]byte, fsched forks.OrderedSchedule) (*domainCache, error) {
|
func newDomainCache(vRoot []byte, dType [bls.DomainByteLength]byte) (*domainCache, error) {
|
||||||
dc := &domainCache{
|
dc := &domainCache{
|
||||||
fsched: fsched,
|
|
||||||
forkDomains: make(map[[4]byte][]byte),
|
forkDomains: make(map[[4]byte][]byte),
|
||||||
dType: dType,
|
dType: dType,
|
||||||
}
|
}
|
||||||
for _, entry := range fsched {
|
for _, entry := range params.SortedForkSchedule() {
|
||||||
d, err := signing.ComputeDomain(dc.dType, entry.Version[:], vRoot)
|
d, err := signing.ComputeDomain(dc.dType, entry.ForkVersion[:], vRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to pre-compute signing domain for fork version=%#x", entry.Version)
|
return nil, errors.Wrapf(err, "failed to pre-compute signing domain for fork version=%#x", entry.ForkVersion)
|
||||||
}
|
}
|
||||||
dc.forkDomains[entry.Version] = d
|
dc.forkDomains[entry.ForkVersion] = d
|
||||||
}
|
}
|
||||||
return dc, nil
|
return dc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dc *domainCache) forEpoch(e primitives.Epoch) ([]byte, error) {
|
func (dc *domainCache) forEpoch(e primitives.Epoch) ([]byte, error) {
|
||||||
fork, err := dc.fsched.VersionForEpoch(e)
|
fork, err := params.Fork(e)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
d, ok := dc.forkDomains[fork]
|
d, ok := dc.forkDomains[[4]byte(fork.CurrentVersion)]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.Wrapf(errUnknownDomain, "fork version=%#x, epoch=%d", fork, e)
|
return nil, errors.Wrapf(errUnknownDomain, "fork version=%#x, epoch=%d", fork, e)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
||||||
"github.com/OffchainLabs/prysm/v6/crypto/bls"
|
"github.com/OffchainLabs/prysm/v6/crypto/bls"
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
||||||
"github.com/OffchainLabs/prysm/v6/network/forks"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/runtime/interop"
|
"github.com/OffchainLabs/prysm/v6/runtime/interop"
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/util"
|
"github.com/OffchainLabs/prysm/v6/testing/util"
|
||||||
@@ -30,18 +29,17 @@ func TestDomainCache(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
vRoot, err := hexutil.Decode("0x0011223344556677889900112233445566778899001122334455667788990011")
|
vRoot, err := hexutil.Decode("0x0011223344556677889900112233445566778899001122334455667788990011")
|
||||||
|
require.NoError(t, err)
|
||||||
dType := cfg.DomainBeaconProposer
|
dType := cfg.DomainBeaconProposer
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, 32, len(vRoot))
|
require.Equal(t, 32, len(vRoot))
|
||||||
fsched := forks.NewOrderedSchedule(cfg)
|
dc, err := newDomainCache(vRoot, dType)
|
||||||
dc, err := newDomainCache(vRoot, dType, fsched)
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, len(fsched), len(dc.forkDomains))
|
schedule := params.SortedForkSchedule()
|
||||||
for i := range fsched {
|
require.Equal(t, len(schedule), len(dc.forkDomains))
|
||||||
e := fsched[i].Epoch
|
for _, entry := range schedule {
|
||||||
ad, err := dc.forEpoch(e)
|
ad, err := dc.forEpoch(entry.Epoch)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
ed, err := signing.ComputeDomain(dType, fsched[i].Version[:], vRoot)
|
ed, err := signing.ComputeDomain(dType, entry.ForkVersion[:], vRoot)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.DeepEqual(t, ed, ad)
|
require.DeepEqual(t, ed, ad)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ func (w *p2pWorker) run(ctx context.Context) {
|
|||||||
select {
|
select {
|
||||||
case b := <-w.todo:
|
case b := <-w.todo:
|
||||||
log.WithFields(b.logFields()).WithField("backfillWorker", w.id).Debug("Backfill worker received batch")
|
log.WithFields(b.logFields()).WithField("backfillWorker", w.id).Debug("Backfill worker received batch")
|
||||||
if b.state == batchBlobSync {
|
if b.state == batchSidecarSync {
|
||||||
w.done <- w.handleBlobs(ctx, b)
|
w.done <- w.handleSidecars(ctx, b)
|
||||||
} else {
|
} else {
|
||||||
w.done <- w.handleBlocks(ctx, b)
|
w.done <- w.handleBlocks(ctx, b)
|
||||||
}
|
}
|
||||||
@@ -80,7 +80,7 @@ func (w *p2pWorker) handleBlocks(ctx context.Context, b batch) batch {
|
|||||||
return b.withResults(vb, bs)
|
return b.withResults(vb, bs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *p2pWorker) handleBlobs(ctx context.Context, b batch) batch {
|
func (w *p2pWorker) handleSidecars(ctx context.Context, b batch) batch {
|
||||||
b.blobPid = b.busy
|
b.blobPid = b.busy
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
// we don't need to use the response for anything other than metrics, because blobResponseValidation
|
// we don't need to use the response for anything other than metrics, because blobResponseValidation
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import (
|
|||||||
types "github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
types "github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
||||||
leakybucket "github.com/OffchainLabs/prysm/v6/container/leaky-bucket"
|
leakybucket "github.com/OffchainLabs/prysm/v6/container/leaky-bucket"
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
||||||
"github.com/OffchainLabs/prysm/v6/network/forks"
|
|
||||||
enginev1 "github.com/OffchainLabs/prysm/v6/proto/engine/v1"
|
enginev1 "github.com/OffchainLabs/prysm/v6/proto/engine/v1"
|
||||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||||
@@ -156,11 +155,7 @@ func (r *expectedBlobChunk) requireExpected(t *testing.T, s *Service, stream net
|
|||||||
|
|
||||||
c, err := readContextFromStream(stream)
|
c, err := readContextFromStream(stream)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, params.ForkDigest(slots.ToEpoch(r.sidecar.Slot())), bytesutil.ToBytes4(c))
|
||||||
valRoot := s.cfg.chain.GenesisValidatorsRoot()
|
|
||||||
ctxBytes, err := forks.ForkDigestFromEpoch(slots.ToEpoch(r.sidecar.Slot()), valRoot[:])
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, ctxBytes, bytesutil.ToBytes4(c))
|
|
||||||
|
|
||||||
sc := ðpb.BlobSidecar{}
|
sc := ðpb.BlobSidecar{}
|
||||||
require.NoError(t, encoding.DecodeWithMaxLength(stream, sc))
|
require.NoError(t, encoding.DecodeWithMaxLength(stream, sc))
|
||||||
@@ -180,7 +175,7 @@ func (c *blobsTestCase) setup(t *testing.T) (*Service, []blocks.ROBlob, func())
|
|||||||
params.OverrideBeaconConfig(cfg)
|
params.OverrideBeaconConfig(cfg)
|
||||||
}
|
}
|
||||||
maxBlobs := int(params.BeaconConfig().MaxBlobsPerBlock(0))
|
maxBlobs := int(params.BeaconConfig().MaxBlobsPerBlock(0))
|
||||||
chain, clock := defaultMockChain(t)
|
chain, clock := defaultMockChain(t, 0)
|
||||||
if c.chain == nil {
|
if c.chain == nil {
|
||||||
c.chain = chain
|
c.chain = chain
|
||||||
}
|
}
|
||||||
@@ -278,9 +273,9 @@ func repositionFutureEpochs(cfg *params.BeaconChainConfig) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func defaultMockChain(t *testing.T) (*mock.ChainService, *startup.Clock) {
|
func defaultMockChain(t *testing.T, currentSlot uint64) (*mock.ChainService, *startup.Clock) {
|
||||||
de := params.BeaconConfig().DenebForkEpoch
|
de := params.BeaconConfig().DenebForkEpoch
|
||||||
df, err := forks.Fork(de)
|
df, err := params.Fork(de)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
denebBuffer := params.BeaconConfig().MinEpochsForBlobsSidecarsRequest + 1000
|
denebBuffer := params.BeaconConfig().MinEpochsForBlobsSidecarsRequest + 1000
|
||||||
ce := de + denebBuffer
|
ce := de + denebBuffer
|
||||||
@@ -289,8 +284,14 @@ func defaultMockChain(t *testing.T) (*mock.ChainService, *startup.Clock) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
genOffset := types.Slot(params.BeaconConfig().SecondsPerSlot) * cs
|
genOffset := types.Slot(params.BeaconConfig().SecondsPerSlot) * cs
|
||||||
genesis := now.Add(-1 * time.Second * time.Duration(int64(genOffset)))
|
genesisTime := now.Add(-1 * time.Second * time.Duration(int64(genOffset)))
|
||||||
clock := startup.NewClock(genesis, [32]byte{})
|
|
||||||
|
clock := startup.NewClock(genesisTime, [32]byte{}, startup.WithNower(
|
||||||
|
func() time.Time {
|
||||||
|
return genesisTime.Add(time.Duration(currentSlot*params.BeaconConfig().SecondsPerSlot) * time.Second)
|
||||||
|
},
|
||||||
|
))
|
||||||
|
|
||||||
chain := &mock.ChainService{
|
chain := &mock.ChainService{
|
||||||
FinalizedCheckPoint: ðpb.Checkpoint{Epoch: fe},
|
FinalizedCheckPoint: ðpb.Checkpoint{Epoch: fe},
|
||||||
Fork: df,
|
Fork: df,
|
||||||
|
|||||||
@@ -78,9 +78,10 @@ func (bb *blockRangeBatcher) next(ctx context.Context, stream libp2pcore.Stream)
|
|||||||
if !more {
|
if !more {
|
||||||
return blockBatch{}, false
|
return blockBatch{}, false
|
||||||
}
|
}
|
||||||
if err := bb.limiter.validateRequest(stream, bb.size); err != nil {
|
// TODO: Uncomment out of devnet.
|
||||||
return blockBatch{err: errors.Wrap(err, "throttled by rate limiter")}, false
|
// if err := bb.limiter.validateRequest(stream, bb.size); err != nil {
|
||||||
}
|
// return blockBatch{err: errors.Wrap(err, "throttled by rate limiter")}, false
|
||||||
|
// }
|
||||||
|
|
||||||
// Wait for the ticker before doing anything expensive, unless this is the first batch.
|
// Wait for the ticker before doing anything expensive, unless this is the first batch.
|
||||||
if bb.ticker != nil && bb.current != nil {
|
if bb.ticker != nil && bb.current != nil {
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ go_test(
|
|||||||
"//consensus-types/blocks/testing:go_default_library",
|
"//consensus-types/blocks/testing:go_default_library",
|
||||||
"//consensus-types/primitives:go_default_library",
|
"//consensus-types/primitives:go_default_library",
|
||||||
"//encoding/ssz/detect:go_default_library",
|
"//encoding/ssz/detect:go_default_library",
|
||||||
"//network/forks:go_default_library",
|
|
||||||
"//proto/prysm/v1alpha1:go_default_library",
|
"//proto/prysm/v1alpha1:go_default_library",
|
||||||
"//runtime/version:go_default_library",
|
"//runtime/version:go_default_library",
|
||||||
"//testing/require:go_default_library",
|
"//testing/require:go_default_library",
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/blocks"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/blocks"
|
||||||
blocktest "github.com/OffchainLabs/prysm/v6/consensus-types/blocks/testing"
|
blocktest "github.com/OffchainLabs/prysm/v6/consensus-types/blocks/testing"
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/ssz/detect"
|
"github.com/OffchainLabs/prysm/v6/encoding/ssz/detect"
|
||||||
"github.com/OffchainLabs/prysm/v6/network/forks"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/util"
|
"github.com/OffchainLabs/prysm/v6/testing/util"
|
||||||
"github.com/OffchainLabs/prysm/v6/time/slots"
|
"github.com/OffchainLabs/prysm/v6/time/slots"
|
||||||
@@ -22,6 +21,7 @@ import (
|
|||||||
func TestDownloadFinalizedData(t *testing.T) {
|
func TestDownloadFinalizedData(t *testing.T) {
|
||||||
ctx := t.Context()
|
ctx := t.Context()
|
||||||
cfg := params.MainnetConfig()
|
cfg := params.MainnetConfig()
|
||||||
|
cfg.InitializeForkSchedule()
|
||||||
|
|
||||||
// avoid the altair zone because genesis tests are easier to set up
|
// avoid the altair zone because genesis tests are easier to set up
|
||||||
epoch := cfg.AltairForkEpoch - 1
|
epoch := cfg.AltairForkEpoch - 1
|
||||||
@@ -30,7 +30,7 @@ func TestDownloadFinalizedData(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
st, err := util.NewBeaconState()
|
st, err := util.NewBeaconState()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
fork, err := forks.ForkForEpochFromConfig(cfg, epoch)
|
fork := params.ForkFromConfig(cfg, epoch)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NoError(t, st.SetFork(fork))
|
require.NoError(t, st.SetFork(fork))
|
||||||
require.NoError(t, st.SetSlot(slot))
|
require.NoError(t, st.SetSlot(slot))
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import (
|
|||||||
blocktest "github.com/OffchainLabs/prysm/v6/consensus-types/blocks/testing"
|
blocktest "github.com/OffchainLabs/prysm/v6/consensus-types/blocks/testing"
|
||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/ssz/detect"
|
"github.com/OffchainLabs/prysm/v6/encoding/ssz/detect"
|
||||||
"github.com/OffchainLabs/prysm/v6/network/forks"
|
|
||||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||||
"github.com/OffchainLabs/prysm/v6/runtime/version"
|
"github.com/OffchainLabs/prysm/v6/runtime/version"
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||||
@@ -83,7 +82,7 @@ func TestDownloadWeakSubjectivityCheckpoint(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
wst, err := util.NewBeaconState()
|
wst, err := util.NewBeaconState()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
fork, err := forkForEpoch(cfg, epoch)
|
fork, err := params.Fork(epoch)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NoError(t, wst.SetFork(fork))
|
require.NoError(t, wst.SetFork(fork))
|
||||||
|
|
||||||
@@ -182,7 +181,7 @@ func TestDownloadBackwardsCompatibleCombined(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
wst, err := util.NewBeaconState()
|
wst, err := util.NewBeaconState()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
fork, err := forkForEpoch(cfg, cfg.GenesisEpoch)
|
fork, err := params.Fork(cfg.GenesisEpoch)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NoError(t, wst.SetFork(fork))
|
require.NoError(t, wst.SetFork(fork))
|
||||||
|
|
||||||
@@ -279,33 +278,11 @@ func TestGetWeakSubjectivityEpochFromHead(t *testing.T) {
|
|||||||
require.Equal(t, expectedEpoch, actualEpoch)
|
require.Equal(t, expectedEpoch, actualEpoch)
|
||||||
}
|
}
|
||||||
|
|
||||||
func forkForEpoch(cfg *params.BeaconChainConfig, epoch primitives.Epoch) (*ethpb.Fork, error) {
|
|
||||||
os := forks.NewOrderedSchedule(cfg)
|
|
||||||
currentVersion, err := os.VersionForEpoch(epoch)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
prevVersion, err := os.Previous(currentVersion)
|
|
||||||
if err != nil {
|
|
||||||
if !errors.Is(err, forks.ErrNoPreviousVersion) {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// use same version for both in the case of genesis
|
|
||||||
prevVersion = currentVersion
|
|
||||||
}
|
|
||||||
forkEpoch := cfg.ForkVersionSchedule[currentVersion]
|
|
||||||
return ðpb.Fork{
|
|
||||||
PreviousVersion: prevVersion[:],
|
|
||||||
CurrentVersion: currentVersion[:],
|
|
||||||
Epoch: forkEpoch,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func defaultTestHeadState(t *testing.T, cfg *params.BeaconChainConfig) (state.BeaconState, primitives.Epoch) {
|
func defaultTestHeadState(t *testing.T, cfg *params.BeaconChainConfig) (state.BeaconState, primitives.Epoch) {
|
||||||
st, err := util.NewBeaconStateAltair()
|
st, err := util.NewBeaconStateAltair()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
fork, err := forkForEpoch(cfg, cfg.AltairForkEpoch)
|
fork, err := params.Fork(cfg.AltairForkEpoch)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NoError(t, st.SetFork(fork))
|
require.NoError(t, st.SetFork(fork))
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package sync
|
|||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/signing"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p"
|
||||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
"github.com/libp2p/go-libp2p/core/network"
|
"github.com/libp2p/go-libp2p/core/network"
|
||||||
@@ -87,12 +86,8 @@ type ContextByteVersions map[[4]byte]int
|
|||||||
// and the runtime/version identifier for the corresponding fork.
|
// and the runtime/version identifier for the corresponding fork.
|
||||||
func ContextByteVersionsForValRoot(valRoot [32]byte) (ContextByteVersions, error) {
|
func ContextByteVersionsForValRoot(valRoot [32]byte) (ContextByteVersions, error) {
|
||||||
m := make(ContextByteVersions)
|
m := make(ContextByteVersions)
|
||||||
for fv, v := range params.ConfigForkVersions(params.BeaconConfig()) {
|
for _, entry := range params.SortedNetworkScheduleEntries() {
|
||||||
digest, err := signing.ComputeForkDigest(fv[:], valRoot[:])
|
m[entry.ForkDigest] = entry.VersionEnum
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "unable to compute fork digest for fork version %#x", fv)
|
|
||||||
}
|
|
||||||
m[digest] = v
|
|
||||||
}
|
}
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user