mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 13:58:09 -05:00
Compare commits
18 Commits
hackSync
...
verify-see
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
947a1efb3a | ||
|
|
071e6ca099 | ||
|
|
a9fe459c63 | ||
|
|
863eee7b40 | ||
|
|
6d89373583 | ||
|
|
9a421a2feb | ||
|
|
4e41d5c610 | ||
|
|
0b6bea43a8 | ||
|
|
f89afb0fbd | ||
|
|
3cd2973c92 | ||
|
|
d3e5710a63 | ||
|
|
f40b4f16c2 | ||
|
|
7fd4f746d6 | ||
|
|
2362d9f3c2 | ||
|
|
6b84f8c6b1 | ||
|
|
997a9112d1 | ||
|
|
d46ca97680 | ||
|
|
417bbf8a9e |
2
.github/actions/gomodtidy/Dockerfile
vendored
2
.github/actions/gomodtidy/Dockerfile
vendored
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.23-alpine
|
||||
FROM golang:1.24-alpine
|
||||
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
|
||||
|
||||
16
.github/workflows/go.yml
vendored
16
.github/workflows/go.yml
vendored
@@ -28,15 +28,15 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up Go 1.23
|
||||
- name: Set up Go 1.24
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '1.23.5'
|
||||
go-version: '1.24.0'
|
||||
- name: Run Gosec Security Scanner
|
||||
run: | # https://github.com/securego/gosec/issues/469
|
||||
export PATH=$PATH:$(go env GOPATH)/bin
|
||||
go install github.com/securego/gosec/v2/cmd/gosec@v2.19.0
|
||||
gosec -exclude-generated -exclude=G307 -exclude-dir=crypto/bls/herumi ./...
|
||||
go install github.com/securego/gosec/v2/cmd/gosec@v2.22.1
|
||||
gosec -exclude-generated -exclude=G307,G115 -exclude-dir=crypto/bls/herumi ./...
|
||||
|
||||
lint:
|
||||
name: Lint
|
||||
@@ -45,16 +45,16 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go 1.23
|
||||
- name: Set up Go 1.24
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '1.23.5'
|
||||
go-version: '1.24.0'
|
||||
id: go
|
||||
|
||||
- name: Golangci-lint
|
||||
uses: golangci/golangci-lint-action@v5
|
||||
with:
|
||||
version: v1.63.4
|
||||
version: v1.64.5
|
||||
args: --config=.golangci.yml --out-${NO_FUTURE}format colored-line-number
|
||||
|
||||
build:
|
||||
@@ -64,7 +64,7 @@ jobs:
|
||||
- name: Set up Go 1.x
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '1.23.5'
|
||||
go-version: '1.24.0'
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
|
||||
@@ -75,6 +75,7 @@ linters:
|
||||
- tagliatelle
|
||||
- thelper
|
||||
- unparam
|
||||
- usetesting
|
||||
- varnamelen
|
||||
- wrapcheck
|
||||
- wsl
|
||||
|
||||
@@ -165,7 +165,7 @@ STATICCHECK_ANALYZERS = [
|
||||
"sa6006",
|
||||
"sa9001",
|
||||
"sa9002",
|
||||
#"sa9003", # Doesn't build. See https://github.com/dominikh/go-tools/pull/1483
|
||||
"sa9003",
|
||||
"sa9004",
|
||||
"sa9005",
|
||||
"sa9006",
|
||||
|
||||
10
WORKSPACE
10
WORKSPACE
@@ -160,15 +160,15 @@ oci_register_toolchains(
|
||||
|
||||
http_archive(
|
||||
name = "io_bazel_rules_go",
|
||||
integrity = "sha256-JD8o94crTb2DFiJJR8nMAGdBAW95zIENB4cbI+JnrI4=",
|
||||
patch_args = ["-p1"],
|
||||
patches = [
|
||||
# Expose internals of go_test for custom build transitions.
|
||||
"//third_party:io_bazel_rules_go_test.patch",
|
||||
],
|
||||
sha256 = "b2038e2de2cace18f032249cb4bb0048abf583a36369fa98f687af1b3f880b26",
|
||||
strip_prefix = "rules_go-cf3c3af34bd869b864f5f2b98e2f41c2b220d6c9",
|
||||
urls = [
|
||||
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.48.1/rules_go-v0.48.1.zip",
|
||||
"https://github.com/bazelbuild/rules_go/releases/download/v0.48.1/rules_go-v0.48.1.zip",
|
||||
"https://github.com/bazel-contrib/rules_go/archive/cf3c3af34bd869b864f5f2b98e2f41c2b220d6c9.tar.gz",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -210,7 +210,7 @@ load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_depe
|
||||
go_rules_dependencies()
|
||||
|
||||
go_register_toolchains(
|
||||
go_version = "1.23.5",
|
||||
go_version = "1.24.0",
|
||||
nogo = "@//:nogo",
|
||||
)
|
||||
|
||||
@@ -431,7 +431,7 @@ gometalinter_dependencies()
|
||||
|
||||
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies")
|
||||
|
||||
gazelle_dependencies()
|
||||
gazelle_dependencies(go_sdk = "go_sdk")
|
||||
|
||||
load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps")
|
||||
|
||||
|
||||
@@ -97,6 +97,7 @@ go_library(
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prometheus_client_golang//prometheus:go_default_library",
|
||||
"@com_github_prometheus_client_golang//prometheus/promauto:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@org_golang_x_sync//errgroup:go_default_library",
|
||||
],
|
||||
@@ -127,6 +128,7 @@ go_test(
|
||||
"receive_block_test.go",
|
||||
"service_norace_test.go",
|
||||
"service_test.go",
|
||||
"setup_forkchoice_test.go",
|
||||
"setup_test.go",
|
||||
"weak_subjectivity_checks_test.go",
|
||||
],
|
||||
@@ -155,6 +157,7 @@ go_test(
|
||||
"//beacon-chain/forkchoice/doubly-linked-tree:go_default_library",
|
||||
"//beacon-chain/forkchoice/types:go_default_library",
|
||||
"//beacon-chain/operations/attestations:go_default_library",
|
||||
"//beacon-chain/operations/attestations/kv:go_default_library",
|
||||
"//beacon-chain/operations/blstoexec:go_default_library",
|
||||
"//beacon-chain/operations/slashings:go_default_library",
|
||||
"//beacon-chain/operations/voluntaryexits:go_default_library",
|
||||
@@ -186,6 +189,7 @@ go_test(
|
||||
"@com_github_ethereum_go_ethereum//core/types:go_default_library",
|
||||
"@com_github_holiman_uint256//:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
|
||||
@@ -582,6 +582,7 @@ func TestService_IsOptimisticForRoot_StateSummaryRecovered(t *testing.T) {
|
||||
br, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
util.SaveBlock(t, context.Background(), beaconDB, b)
|
||||
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, [32]byte{}))
|
||||
_, err = c.IsOptimisticForRoot(ctx, br)
|
||||
assert.NoError(t, err)
|
||||
summ, err := beaconDB.StateSummary(ctx, br)
|
||||
|
||||
@@ -72,7 +72,6 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *fcuConfig) (*
|
||||
if arg.attributes == nil {
|
||||
arg.attributes = payloadattribute.EmptyWithVersion(headBlk.Version())
|
||||
}
|
||||
go firePayloadAttributesEvent(ctx, s.cfg.StateNotifier.StateFeed(), arg)
|
||||
payloadID, lastValidHash, err := s.cfg.ExecutionEngineCaller.ForkchoiceUpdated(ctx, fcs, arg.attributes)
|
||||
if err != nil {
|
||||
switch {
|
||||
@@ -159,6 +158,7 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *fcuConfig) (*
|
||||
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)
|
||||
@@ -166,40 +166,19 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *fcuConfig) (*
|
||||
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 firePayloadAttributesEvent(ctx context.Context, f event.SubscriberSender, cfg *fcuConfig) {
|
||||
pidx, err := helpers.BeaconProposerIndex(ctx, cfg.headState)
|
||||
if err != nil {
|
||||
log.WithError(err).
|
||||
WithField("head_root", cfg.headRoot[:]).
|
||||
Error("Could not get proposer index for PayloadAttributes event")
|
||||
return
|
||||
}
|
||||
evd := payloadattribute.EventData{
|
||||
ProposerIndex: pidx,
|
||||
ProposalSlot: cfg.headState.Slot(),
|
||||
ParentBlockRoot: cfg.headRoot[:],
|
||||
Attributer: cfg.attributes,
|
||||
HeadRoot: cfg.headRoot,
|
||||
HeadState: cfg.headState,
|
||||
HeadBlock: cfg.headBlock,
|
||||
}
|
||||
if cfg.headBlock != nil && !cfg.headBlock.IsNil() {
|
||||
headPayload, err := cfg.headBlock.Block().Body().Execution()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not get execution payload for head block")
|
||||
return
|
||||
}
|
||||
evd.ParentBlockHash = headPayload.BlockHash()
|
||||
evd.ParentBlockNumber = headPayload.BlockNumber()
|
||||
}
|
||||
func firePayloadAttributesEvent(_ context.Context, f event.SubscriberSender, nextSlot primitives.Slot) {
|
||||
// the fcu args have differing amounts of completeness based on the code path,
|
||||
// and there is work we only want to do if a client is actually listening to the events beacon api endpoint.
|
||||
// temporary solution: just fire a blank event and fill in the details in the api handler.
|
||||
f.Send(&feed.Event{
|
||||
Type: statefeed.PayloadAttributes,
|
||||
Data: evd,
|
||||
Data: payloadattribute.EventData{ProposalSlot: nextSlot},
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -102,8 +102,10 @@ func (s *Service) forkchoiceUpdateWithExecution(ctx context.Context, args *fcuCo
|
||||
log.WithError(err).Error("could not save head")
|
||||
}
|
||||
|
||||
go firePayloadAttributesEvent(ctx, s.cfg.StateNotifier.StateFeed(), s.CurrentSlot()+1)
|
||||
|
||||
// Only need to prune attestations from pool if the head has changed.
|
||||
if err := s.pruneAttsFromPool(args.headBlock); err != nil {
|
||||
if err := s.pruneAttsFromPool(s.ctx, args.headState, args.headBlock); err != nil {
|
||||
log.WithError(err).Error("could not prune attestations from pool")
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -3,6 +3,7 @@ package blockchain
|
||||
import (
|
||||
"testing"
|
||||
|
||||
mock "github.com/prysmaticlabs/prysm/v5/beacon-chain/blockchain/testing"
|
||||
testDB "github.com/prysmaticlabs/prysm/v5/beacon-chain/db/testing"
|
||||
doublylinkedtree "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice/doubly-linked-tree"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/startup"
|
||||
@@ -18,6 +19,7 @@ func testServiceOptsWithDB(t *testing.T) []Option {
|
||||
WithStateGen(stategen.New(beaconDB, fcs)),
|
||||
WithForkChoiceStore(fcs),
|
||||
WithClockSynchronizer(cs),
|
||||
WithStateNotifier(&mock.MockStateNotifier{RecordEvents: true}),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ func (s *Service) OnAttestation(ctx context.Context, a ethpb.Att, disparity time
|
||||
}
|
||||
|
||||
// Use the target state to verify attesting indices are valid.
|
||||
committees, err := helpers.AttestationCommittees(ctx, baseState, a)
|
||||
committees, err := helpers.AttestationCommitteesFromState(ctx, baseState, a)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
|
||||
coreTime "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time"
|
||||
@@ -15,6 +16,7 @@ import (
|
||||
forkchoicetypes "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice/types"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/features"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
consensusblocks "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
@@ -368,7 +370,7 @@ func (s *Service) handleEpochBoundary(ctx context.Context, slot primitives.Slot,
|
||||
func (s *Service) handleBlockAttestations(ctx context.Context, blk interfaces.ReadOnlyBeaconBlock, st state.BeaconState) error {
|
||||
// Feed in block's attestations to fork choice store.
|
||||
for _, a := range blk.Body().Attestations() {
|
||||
committees, err := helpers.AttestationCommittees(ctx, st, a)
|
||||
committees, err := helpers.AttestationCommitteesFromState(ctx, st, a)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -419,27 +421,102 @@ func (s *Service) savePostStateInfo(ctx context.Context, r [32]byte, b interface
|
||||
return nil
|
||||
}
|
||||
|
||||
// This removes the attestations in block `b` from the attestation mem pool.
|
||||
func (s *Service) pruneAttsFromPool(headBlock interfaces.ReadOnlySignedBeaconBlock) error {
|
||||
atts := headBlock.Block().Body().Attestations()
|
||||
for _, att := range atts {
|
||||
if features.Get().EnableExperimentalAttestationPool {
|
||||
if err := s.cfg.AttestationCache.DeleteCovered(att); err != nil {
|
||||
return errors.Wrap(err, "could not delete attestation")
|
||||
}
|
||||
} else if att.IsAggregated() {
|
||||
if err := s.cfg.AttPool.DeleteAggregatedAttestation(att); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := s.cfg.AttPool.DeleteUnaggregatedAttestation(att); err != nil {
|
||||
return err
|
||||
}
|
||||
// pruneAttsFromPool removes these attestations from the attestation pool
|
||||
// which are covered by attestations from the received block.
|
||||
func (s *Service) pruneAttsFromPool(ctx context.Context, headState state.BeaconState, headBlock interfaces.ReadOnlySignedBeaconBlock) error {
|
||||
for _, att := range headBlock.Block().Body().Attestations() {
|
||||
if err := s.pruneCoveredAttsFromPool(ctx, headState, att); err != nil {
|
||||
log.WithError(err).Warn("Could not prune attestations covered by a received block's attestation")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) pruneCoveredAttsFromPool(ctx context.Context, headState state.BeaconState, att ethpb.Att) error {
|
||||
switch {
|
||||
case !att.IsAggregated():
|
||||
return s.cfg.AttPool.DeleteUnaggregatedAttestation(att)
|
||||
case att.Version() == version.Phase0:
|
||||
if features.Get().EnableExperimentalAttestationPool {
|
||||
return errors.Wrap(s.cfg.AttestationCache.DeleteCovered(att), "could not delete covered attestation")
|
||||
}
|
||||
return errors.Wrap(s.cfg.AttPool.DeleteAggregatedAttestation(att), "could not delete aggregated attestation")
|
||||
default:
|
||||
return s.pruneCoveredElectraAttsFromPool(ctx, headState, att)
|
||||
}
|
||||
}
|
||||
|
||||
// pruneCoveredElectraAttsFromPool handles removing aggregated Electra attestations from the pool after receiving a block.
|
||||
// Because in Electra block attestations can combine aggregates for multiple committees, comparing attestation bits
|
||||
// of a block attestation with attestations bits of an aggregate can cause unexpected results, leading to covered
|
||||
// aggregates not being removed from the pool.
|
||||
//
|
||||
// To make sure aggregates are removed, we decompose the block attestation into dummy aggregates, with each
|
||||
// aggregate accounting for one committee. This allows us to compare aggregates in the same way it's done for
|
||||
// Phase0. Even though we can't provide a valid signature for the dummy aggregate, it does not matter because
|
||||
// signatures play no part in pruning attestations.
|
||||
func (s *Service) pruneCoveredElectraAttsFromPool(ctx context.Context, headState state.BeaconState, att ethpb.Att) error {
|
||||
if att.Version() == version.Phase0 {
|
||||
log.Error("Called pruneCoveredElectraAttsFromPool with a Phase0 attestation")
|
||||
return nil
|
||||
}
|
||||
|
||||
// We don't want to recompute committees. If they are not cached already,
|
||||
// we allow attestations to stay in the pool. If these attestations are
|
||||
// included in a later block, they will be redundant. But given that
|
||||
// they were not cached in the first place, it's unlikely that they
|
||||
// will be chosen into a block.
|
||||
ok, committees, err := helpers.AttestationCommitteesFromCache(ctx, headState, att)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get attestation committees")
|
||||
}
|
||||
if !ok {
|
||||
log.Debug("Attestation committees are not cached. Skipping attestation pruning.")
|
||||
return nil
|
||||
}
|
||||
|
||||
committeeIndices := att.CommitteeBitsVal().BitIndices()
|
||||
offset := uint64(0)
|
||||
|
||||
// Sanity check as this should never happen
|
||||
if len(committeeIndices) != len(committees) {
|
||||
return errors.New("committee indices and committees have different lengths")
|
||||
}
|
||||
|
||||
for i, c := range committees {
|
||||
ab := bitfield.NewBitlist(uint64(len(c)))
|
||||
for j := uint64(0); j < uint64(len(c)); j++ {
|
||||
ab.SetBitAt(j, att.GetAggregationBits().BitAt(j+offset))
|
||||
}
|
||||
|
||||
cb := primitives.NewAttestationCommitteeBits()
|
||||
cb.SetBitAt(uint64(committeeIndices[i]), true)
|
||||
|
||||
a := ðpb.AttestationElectra{
|
||||
AggregationBits: ab,
|
||||
Data: att.GetData(),
|
||||
CommitteeBits: cb,
|
||||
Signature: make([]byte, fieldparams.BLSSignatureLength),
|
||||
}
|
||||
|
||||
if features.Get().EnableExperimentalAttestationPool {
|
||||
if err = s.cfg.AttestationCache.DeleteCovered(a); err != nil {
|
||||
return errors.Wrap(err, "could not delete covered attestation")
|
||||
}
|
||||
} else if !a.IsAggregated() {
|
||||
if err = s.cfg.AttPool.DeleteUnaggregatedAttestation(a); err != nil {
|
||||
return errors.Wrap(err, "could not delete unaggregated attestation")
|
||||
}
|
||||
} else if err = s.cfg.AttPool.DeleteAggregatedAttestation(a); err != nil {
|
||||
return errors.Wrap(err, "could not delete aggregated attestation")
|
||||
}
|
||||
|
||||
offset += uint64(len(c))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateMergeTransitionBlock validates the merge transition block.
|
||||
func (s *Service) validateMergeTransitionBlock(ctx context.Context, stateVersion int, stateHeader interfaces.ExecutionData, blk interfaces.ReadOnlySignedBeaconBlock) error {
|
||||
// Skip validation if block is older than Bellatrix.
|
||||
@@ -650,13 +727,9 @@ func (s *Service) lateBlockTasks(ctx context.Context) {
|
||||
attribute := s.getPayloadAttribute(ctx, headState, s.CurrentSlot()+1, headRoot[:])
|
||||
// return early if we are not proposing next slot
|
||||
if attribute.IsEmpty() {
|
||||
fcuArgs := &fcuConfig{
|
||||
headState: headState,
|
||||
headRoot: headRoot,
|
||||
headBlock: nil,
|
||||
attributes: attribute,
|
||||
}
|
||||
go firePayloadAttributesEvent(ctx, s.cfg.StateNotifier.StateFeed(), fcuArgs)
|
||||
// notifyForkchoiceUpdate fires the payload attribute event. But in this case, we won't
|
||||
// call notifyForkchoiceUpdate, so the event is fired here.
|
||||
go firePayloadAttributesEvent(ctx, s.cfg.StateNotifier.StateFeed(), s.CurrentSlot()+1)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,10 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
gethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/cache"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
|
||||
lightClient "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/light-client"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/signing"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/transition"
|
||||
@@ -25,6 +27,7 @@ import (
|
||||
mockExecution "github.com/prysmaticlabs/prysm/v5/beacon-chain/execution/testing"
|
||||
doublylinkedtree "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice/doubly-linked-tree"
|
||||
forkchoicetypes "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice/types"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/operations/attestations/kv"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/features"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
|
||||
@@ -45,6 +48,95 @@ import (
|
||||
logTest "github.com/sirupsen/logrus/hooks/test"
|
||||
)
|
||||
|
||||
func Test_pruneAttsFromPool_Electra(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
logHook := logTest.NewGlobal()
|
||||
|
||||
params.SetupTestConfigCleanup(t)
|
||||
cfg := params.BeaconConfig().Copy()
|
||||
cfg.TargetCommitteeSize = 8
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
s := Service{
|
||||
cfg: &config{
|
||||
AttPool: kv.NewAttCaches(),
|
||||
},
|
||||
}
|
||||
|
||||
data := ðpb.AttestationData{
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
Source: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
Target: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
}
|
||||
|
||||
cb := primitives.NewAttestationCommitteeBits()
|
||||
cb.SetBitAt(0, true)
|
||||
att1 := ðpb.AttestationElectra{
|
||||
AggregationBits: bitfield.Bitlist{0b10000000, 0b00000001},
|
||||
Data: data,
|
||||
Signature: make([]byte, 96),
|
||||
CommitteeBits: cb,
|
||||
}
|
||||
|
||||
cb = primitives.NewAttestationCommitteeBits()
|
||||
cb.SetBitAt(1, true)
|
||||
att2 := ðpb.AttestationElectra{
|
||||
AggregationBits: bitfield.Bitlist{0b11110111, 0b00000001},
|
||||
Data: data,
|
||||
Signature: make([]byte, 96),
|
||||
CommitteeBits: cb,
|
||||
}
|
||||
|
||||
cb = primitives.NewAttestationCommitteeBits()
|
||||
cb.SetBitAt(3, true)
|
||||
att3 := ðpb.AttestationElectra{
|
||||
AggregationBits: bitfield.Bitlist{0b11110111, 0b00000001},
|
||||
Data: data,
|
||||
Signature: make([]byte, 96),
|
||||
CommitteeBits: cb,
|
||||
}
|
||||
|
||||
require.NoError(t, s.cfg.AttPool.SaveUnaggregatedAttestation(att1))
|
||||
require.NoError(t, s.cfg.AttPool.SaveAggregatedAttestation(att2))
|
||||
require.NoError(t, s.cfg.AttPool.SaveAggregatedAttestation(att3))
|
||||
|
||||
cb = primitives.NewAttestationCommitteeBits()
|
||||
cb.SetBitAt(0, true)
|
||||
cb.SetBitAt(1, true)
|
||||
onChainAtt := ðpb.AttestationElectra{
|
||||
AggregationBits: bitfield.Bitlist{0b10000000, 0b11110111, 0b00000001},
|
||||
Data: data,
|
||||
Signature: make([]byte, 96),
|
||||
CommitteeBits: cb,
|
||||
}
|
||||
bl := ðpb.SignedBeaconBlockElectra{
|
||||
Block: ðpb.BeaconBlockElectra{
|
||||
Body: ðpb.BeaconBlockBodyElectra{
|
||||
Attestations: []*ethpb.AttestationElectra{onChainAtt},
|
||||
},
|
||||
},
|
||||
Signature: make([]byte, 96),
|
||||
}
|
||||
rob, err := consensusblocks.NewSignedBeaconBlock(bl)
|
||||
require.NoError(t, err)
|
||||
st, _ := util.DeterministicGenesisStateElectra(t, 1024)
|
||||
committees, err := helpers.BeaconCommittees(ctx, st, 0)
|
||||
require.NoError(t, err)
|
||||
// Sanity check to make sure the on-chain att will be decomposed
|
||||
// into the correct number of aggregates.
|
||||
require.Equal(t, 4, len(committees))
|
||||
|
||||
require.NoError(t, s.pruneAttsFromPool(ctx, st, rob))
|
||||
require.LogsDoNotContain(t, logHook, "Could not prune attestations")
|
||||
|
||||
attsInPool, err := s.cfg.AttPool.UnaggregatedAttestations()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, len(attsInPool))
|
||||
attsInPool = s.cfg.AttPool.AggregatedAttestations()
|
||||
require.Equal(t, 1, len(attsInPool))
|
||||
assert.DeepEqual(t, att3, attsInPool[0])
|
||||
}
|
||||
|
||||
func TestStore_OnBlockBatch(t *testing.T) {
|
||||
service, tr := minimalTestService(t)
|
||||
ctx := tr.ctx
|
||||
@@ -821,6 +913,8 @@ func TestInsertFinalizedDeposits_MultipleFinalizedRoutines(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRemoveBlockAttestationsInPool(t *testing.T) {
|
||||
logHook := logTest.NewGlobal()
|
||||
|
||||
genesis, keys := util.DeterministicGenesisState(t, 64)
|
||||
b, err := util.GenerateFullBlock(genesis, keys, util.DefaultBlockGenConfig(), 1)
|
||||
assert.NoError(t, err)
|
||||
@@ -840,7 +934,8 @@ func TestRemoveBlockAttestationsInPool(t *testing.T) {
|
||||
require.NoError(t, service.cfg.AttPool.SaveAggregatedAttestations(atts))
|
||||
wsb, err := consensusblocks.NewSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.pruneAttsFromPool(wsb))
|
||||
require.NoError(t, service.pruneAttsFromPool(context.Background(), nil /* state not needed pre-Electra */, wsb))
|
||||
require.LogsDoNotContain(t, logHook, "Could not prune attestations")
|
||||
require.Equal(t, 0, service.cfg.AttPool.AggregatedAttestationCount())
|
||||
}
|
||||
|
||||
@@ -1896,6 +1991,7 @@ func TestNoViableHead_Reboot(t *testing.T) {
|
||||
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, genesisState, genesisRoot), "Could not save genesis state")
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveHeadBlockRoot(ctx, genesisRoot), "Could not save genesis state")
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveGenesisBlockRoot(ctx, genesisRoot), "Could not save genesis state")
|
||||
|
||||
for i := 1; i < 6; i++ {
|
||||
driftGenesisTime(service, int64(i), 0)
|
||||
@@ -2030,6 +2126,7 @@ func TestNoViableHead_Reboot(t *testing.T) {
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, genesisState, jroot))
|
||||
service.cfg.ForkChoiceStore.SetBalancesByRooter(service.cfg.StateGen.ActiveNonSlashedBalancesByRoot)
|
||||
require.NoError(t, service.StartFromSavedState(genesisState))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveGenesisBlockRoot(ctx, genesisRoot))
|
||||
|
||||
// Forkchoice has the genesisRoot loaded at startup
|
||||
require.Equal(t, genesisRoot, service.ensureRootNotZeros(service.cfg.ForkChoiceStore.CachedHeadRoot()))
|
||||
@@ -2039,7 +2136,7 @@ func TestNoViableHead_Reboot(t *testing.T) {
|
||||
require.Equal(t, genesisRoot, bytesutil.ToBytes32(headRoot))
|
||||
optimistic, err := service.IsOptimistic(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, optimistic)
|
||||
require.Equal(t, false, optimistic)
|
||||
|
||||
// Check that the node's justified checkpoint does not agree with the
|
||||
// last valid state's justified checkpoint
|
||||
|
||||
@@ -547,7 +547,7 @@ func (s *Service) sendBlockAttestationsToSlasher(signed interfaces.ReadOnlySigne
|
||||
// is done in the background to avoid adding more load to this critical code path.
|
||||
ctx := context.TODO()
|
||||
for _, att := range signed.Block().Body().Attestations() {
|
||||
committees, err := helpers.AttestationCommittees(ctx, preState, att)
|
||||
committees, err := helpers.AttestationCommitteesFromState(ctx, preState, att)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not get attestation committees")
|
||||
return
|
||||
|
||||
@@ -39,6 +39,7 @@ import (
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
prysmTime "github.com/prysmaticlabs/prysm/v5/time"
|
||||
"github.com/prysmaticlabs/prysm/v5/time/slots"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Service represents a service that handles the internal
|
||||
@@ -316,32 +317,36 @@ func (s *Service) originRootFromSavedState(ctx context.Context) ([32]byte, error
|
||||
return genesisBlkRoot, nil
|
||||
}
|
||||
|
||||
// initializeHeadFromDB uses the finalized checkpoint and head block found in the database to set the current head.
|
||||
// initializeHeadFromDB uses the finalized checkpoint and head block root from forkchoice to set the current head.
|
||||
// Note that this may block until stategen replays blocks between the finalized and head blocks
|
||||
// if the head sync flag was specified and the gap between the finalized and head blocks is at least 128 epochs long.
|
||||
func (s *Service) initializeHeadFromDB(ctx context.Context, finalizedState state.BeaconState) error {
|
||||
func (s *Service) initializeHead(ctx context.Context, st state.BeaconState) error {
|
||||
cp := s.FinalizedCheckpt()
|
||||
fRoot := [32]byte(cp.Root)
|
||||
finalizedRoot := s.ensureRootNotZeros(fRoot)
|
||||
|
||||
if finalizedState == nil || finalizedState.IsNil() {
|
||||
fRoot := s.ensureRootNotZeros([32]byte(cp.Root))
|
||||
if st == nil || st.IsNil() {
|
||||
return errors.New("finalized state can't be nil")
|
||||
}
|
||||
|
||||
finalizedBlock, err := s.getBlock(ctx, finalizedRoot)
|
||||
s.cfg.ForkChoiceStore.RLock()
|
||||
root := s.cfg.ForkChoiceStore.HighestReceivedBlockRoot()
|
||||
s.cfg.ForkChoiceStore.RUnlock()
|
||||
blk, err := s.cfg.BeaconDB.Block(ctx, root)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get finalized block")
|
||||
return errors.Wrap(err, "could not get head block")
|
||||
}
|
||||
if err := s.setHead(&head{
|
||||
finalizedRoot,
|
||||
finalizedBlock,
|
||||
finalizedState,
|
||||
finalizedBlock.Block().Slot(),
|
||||
false,
|
||||
}); err != nil {
|
||||
if root != fRoot {
|
||||
st, err = s.cfg.StateGen.StateByRoot(ctx, root)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get head state")
|
||||
}
|
||||
}
|
||||
if err := s.setHead(&head{root, blk, st, blk.Block().Slot(), false}); err != nil {
|
||||
return errors.Wrap(err, "could not set head")
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"root": fmt.Sprintf("%#x", root),
|
||||
"slot": blk.Block().Slot(),
|
||||
}).Info("Initialized head block from DB")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -2,28 +2,119 @@ package blockchain
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
forkchoicetypes "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice/types"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/features"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/v5/time/slots"
|
||||
)
|
||||
|
||||
func (s *Service) setupForkchoice(st state.BeaconState) error {
|
||||
if err := s.setupForkchoiceCheckpoints(); err != nil {
|
||||
return errors.Wrap(err, "could not set up forkchoice checkpoints")
|
||||
}
|
||||
if err := s.setupForkchoiceRoot(st); err != nil {
|
||||
if err := s.setupForkchoiceTree(st); err != nil {
|
||||
return errors.Wrap(err, "could not set up forkchoice root")
|
||||
}
|
||||
if err := s.initializeHeadFromDB(s.ctx, st); err != nil {
|
||||
if err := s.initializeHead(s.ctx, st); err != nil {
|
||||
return errors.Wrap(err, "could not initialize head from db")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) startupHeadRoot() [32]byte {
|
||||
headStr := features.Get().ForceHead
|
||||
cp := s.FinalizedCheckpt()
|
||||
fRoot := s.ensureRootNotZeros([32]byte(cp.Root))
|
||||
if headStr == "" {
|
||||
return fRoot
|
||||
}
|
||||
if headStr == "head" {
|
||||
root, err := s.cfg.BeaconDB.HeadBlockRoot()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("could not get head block root, starting with finalized block as head")
|
||||
return fRoot
|
||||
}
|
||||
log.Infof("Using Head root of %#x", root)
|
||||
return root
|
||||
}
|
||||
root, err := bytesutil.DecodeHexWithLength(headStr, 32)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("could not parse head root, starting with finalized block as head")
|
||||
return fRoot
|
||||
}
|
||||
return [32]byte(root)
|
||||
}
|
||||
|
||||
func (s *Service) setupForkchoiceTree(st state.BeaconState) error {
|
||||
headRoot := s.startupHeadRoot()
|
||||
cp := s.FinalizedCheckpt()
|
||||
fRoot := s.ensureRootNotZeros([32]byte(cp.Root))
|
||||
if err := s.setupForkchoiceRoot(st); err != nil {
|
||||
return errors.Wrap(err, "could not set up forkchoice root")
|
||||
}
|
||||
if headRoot == fRoot {
|
||||
return nil
|
||||
}
|
||||
blk, err := s.cfg.BeaconDB.Block(s.ctx, headRoot)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("could not get head block, starting with finalized block as head")
|
||||
return nil
|
||||
}
|
||||
if slots.ToEpoch(blk.Block().Slot()) < cp.Epoch {
|
||||
log.WithField("headRoot", fmt.Sprintf("%#x", headRoot)).Error("head block is older than finalized block, starting with finalized block as head")
|
||||
return nil
|
||||
}
|
||||
chain, err := s.buildForkchoiceChain(s.ctx, blk)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("could not build forkchoice chain, starting with finalized block as head")
|
||||
return nil
|
||||
}
|
||||
s.cfg.ForkChoiceStore.Lock()
|
||||
defer s.cfg.ForkChoiceStore.Unlock()
|
||||
return s.cfg.ForkChoiceStore.InsertChain(s.ctx, chain)
|
||||
}
|
||||
|
||||
func (s *Service) buildForkchoiceChain(ctx context.Context, head interfaces.ReadOnlySignedBeaconBlock) ([]*forkchoicetypes.BlockAndCheckpoints, error) {
|
||||
chain := []*forkchoicetypes.BlockAndCheckpoints{}
|
||||
cp := s.FinalizedCheckpt()
|
||||
fRoot := s.ensureRootNotZeros([32]byte(cp.Root))
|
||||
jp := s.CurrentJustifiedCheckpt()
|
||||
root, err := head.Block().HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get head block root")
|
||||
}
|
||||
for {
|
||||
roblock, err := blocks.NewROBlockWithRoot(head, root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// This chain sets the justified checkpoint for every block, including some that are older than jp.
|
||||
// This should be however safe for forkchoice at startup. An alternative would be to hook during the
|
||||
// block processing pipeline when setting the head state, to compute the right states for the justified
|
||||
// checkpoint.
|
||||
chain = append(chain, &forkchoicetypes.BlockAndCheckpoints{Block: roblock, JustifiedCheckpoint: jp, FinalizedCheckpoint: cp})
|
||||
root = head.Block().ParentRoot()
|
||||
if root == fRoot {
|
||||
break
|
||||
}
|
||||
head, err = s.cfg.BeaconDB.Block(s.ctx, root)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get block")
|
||||
}
|
||||
if slots.ToEpoch(head.Block().Slot()) < cp.Epoch {
|
||||
return nil, errors.New("head block is not a descendant of the finalized checkpoint")
|
||||
}
|
||||
}
|
||||
return chain, nil
|
||||
}
|
||||
|
||||
func (s *Service) setupForkchoiceRoot(st state.BeaconState) error {
|
||||
cp := s.FinalizedCheckpt()
|
||||
fRoot := s.ensureRootNotZeros([32]byte(cp.Root))
|
||||
|
||||
128
beacon-chain/blockchain/setup_forkchoice_test.go
Normal file
128
beacon-chain/blockchain/setup_forkchoice_test.go
Normal file
@@ -0,0 +1,128 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/features"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
consensusblocks "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
logTest "github.com/sirupsen/logrus/hooks/test"
|
||||
)
|
||||
|
||||
func Test_startupHeadRoot(t *testing.T) {
|
||||
service, tr := minimalTestService(t)
|
||||
ctx := tr.ctx
|
||||
hook := logTest.NewGlobal()
|
||||
cp := service.FinalizedCheckpt()
|
||||
require.DeepEqual(t, cp.Root, params.BeaconConfig().ZeroHash[:])
|
||||
gr := [32]byte{'r', 'o', 'o', 't'}
|
||||
service.originBlockRoot = gr
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveGenesisBlockRoot(ctx, gr))
|
||||
t.Run("start from finalized", func(t *testing.T) {
|
||||
require.Equal(t, service.startupHeadRoot(), gr)
|
||||
})
|
||||
t.Run("head requested, error path", func(t *testing.T) {
|
||||
resetCfg := features.InitWithReset(&features.Flags{
|
||||
ForceHead: "head",
|
||||
})
|
||||
defer resetCfg()
|
||||
require.Equal(t, service.startupHeadRoot(), gr)
|
||||
require.LogsContain(t, hook, "could not get head block root, starting with finalized block as head")
|
||||
})
|
||||
|
||||
st, _ := util.DeterministicGenesisState(t, 64)
|
||||
hr := [32]byte{'h', 'e', 'a', 'd'}
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, st, hr), "Could not save genesis state")
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveHeadBlockRoot(ctx, hr), "Could not save genesis state")
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveHeadBlockRoot(ctx, hr))
|
||||
|
||||
t.Run("start from head", func(t *testing.T) {
|
||||
resetCfg := features.InitWithReset(&features.Flags{
|
||||
ForceHead: "head",
|
||||
})
|
||||
defer resetCfg()
|
||||
require.Equal(t, service.startupHeadRoot(), hr)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_setupForkchoiceTree_Finalized(t *testing.T) {
|
||||
service, tr := minimalTestService(t)
|
||||
ctx := tr.ctx
|
||||
|
||||
st, _ := util.DeterministicGenesisState(t, 64)
|
||||
stateRoot, err := st.HashTreeRoot(ctx)
|
||||
require.NoError(t, err, "Could not hash genesis state")
|
||||
|
||||
require.NoError(t, service.saveGenesisData(ctx, st))
|
||||
|
||||
genesis := blocks.NewGenesisBlock(stateRoot[:])
|
||||
wsb, err := consensusblocks.NewSignedBeaconBlock(genesis)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveBlock(ctx, wsb), "Could not save genesis block")
|
||||
parentRoot, err := genesis.Block.HashTreeRoot()
|
||||
require.NoError(t, err, "Could not get signing root")
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, st, parentRoot), "Could not save genesis state")
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveHeadBlockRoot(ctx, parentRoot), "Could not save genesis state")
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveJustifiedCheckpoint(ctx, ðpb.Checkpoint{Root: parentRoot[:]}))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveFinalizedCheckpoint(ctx, ðpb.Checkpoint{Root: parentRoot[:]}))
|
||||
require.NoError(t, service.setupForkchoiceTree(st))
|
||||
require.Equal(t, 1, service.cfg.ForkChoiceStore.NodeCount())
|
||||
}
|
||||
|
||||
func Test_setupForkchoiceTree_Head(t *testing.T) {
|
||||
service, tr := minimalTestService(t)
|
||||
ctx := tr.ctx
|
||||
resetCfg := features.InitWithReset(&features.Flags{
|
||||
ForceHead: "head",
|
||||
})
|
||||
defer resetCfg()
|
||||
|
||||
genesisState, keys := util.DeterministicGenesisState(t, 64)
|
||||
stateRoot, err := genesisState.HashTreeRoot(ctx)
|
||||
require.NoError(t, err, "Could not hash genesis state")
|
||||
genesis := blocks.NewGenesisBlock(stateRoot[:])
|
||||
wsb, err := consensusblocks.NewSignedBeaconBlock(genesis)
|
||||
require.NoError(t, err)
|
||||
genesisRoot, err := genesis.Block.HashTreeRoot()
|
||||
require.NoError(t, err, "Could not get signing root")
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveBlock(ctx, wsb), "Could not save genesis block")
|
||||
require.NoError(t, service.saveGenesisData(ctx, genesisState))
|
||||
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, genesisState, genesisRoot), "Could not save genesis state")
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveHeadBlockRoot(ctx, genesisRoot), "Could not save genesis state")
|
||||
|
||||
st, err := service.HeadState(ctx)
|
||||
require.NoError(t, err)
|
||||
b, err := util.GenerateFullBlock(st, keys, util.DefaultBlockGenConfig(), primitives.Slot(1))
|
||||
require.NoError(t, err)
|
||||
wsb, err = consensusblocks.NewSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
root, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
preState, err := service.getBlockPreState(ctx, wsb.Block())
|
||||
require.NoError(t, err)
|
||||
postState, err := service.validateStateTransition(ctx, preState, wsb)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.savePostStateInfo(ctx, root, wsb, postState))
|
||||
|
||||
b, err = util.GenerateFullBlock(postState, keys, util.DefaultBlockGenConfig(), primitives.Slot(2))
|
||||
require.NoError(t, err)
|
||||
wsb, err = consensusblocks.NewSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
root, err = b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.savePostStateInfo(ctx, root, wsb, preState))
|
||||
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveHeadBlockRoot(ctx, root))
|
||||
cp := service.FinalizedCheckpt()
|
||||
fRoot := service.ensureRootNotZeros([32]byte(cp.Root))
|
||||
require.NotEqual(t, fRoot, root)
|
||||
require.Equal(t, root, service.startupHeadRoot())
|
||||
require.NoError(t, service.setupForkchoiceTree(st))
|
||||
require.Equal(t, 2, service.cfg.ForkChoiceStore.NodeCount())
|
||||
}
|
||||
@@ -66,7 +66,7 @@ func ProcessAttestationNoVerifySignature(
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
committees, err := helpers.AttestationCommittees(ctx, beaconState, att)
|
||||
committees, err := helpers.AttestationCommitteesFromState(ctx, beaconState, att)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ func createAttestationSignatureBatch(
|
||||
descs := make([]string, len(atts))
|
||||
for i, a := range atts {
|
||||
sigs[i] = a.GetSignature()
|
||||
committees, err := helpers.AttestationCommittees(ctx, beaconState, a)
|
||||
committees, err := helpers.AttestationCommitteesFromState(ctx, beaconState, a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -30,6 +30,13 @@ var (
|
||||
proposerIndicesCache = cache.NewProposerIndicesCache()
|
||||
)
|
||||
|
||||
type beaconCommitteeFunc = func(
|
||||
ctx context.Context,
|
||||
state state.ReadOnlyBeaconState,
|
||||
slot primitives.Slot,
|
||||
committeeIndex primitives.CommitteeIndex,
|
||||
) ([]primitives.ValidatorIndex, error)
|
||||
|
||||
// SlotCommitteeCount returns the number of beacon committees of a slot. The
|
||||
// active validator count is provided as an argument rather than an imported implementation
|
||||
// from the spec definition. Having the active validator count as an argument allows for
|
||||
@@ -59,21 +66,48 @@ func SlotCommitteeCount(activeValidatorCount uint64) uint64 {
|
||||
return committeesPerSlot
|
||||
}
|
||||
|
||||
// AttestationCommittees returns beacon state committees that reflect attestation's committee indices.
|
||||
func AttestationCommittees(ctx context.Context, st state.ReadOnlyBeaconState, att ethpb.Att) ([][]primitives.ValidatorIndex, error) {
|
||||
// AttestationCommitteesFromState returns beacon state committees that reflect attestation's committee indices.
|
||||
func AttestationCommitteesFromState(ctx context.Context, st state.ReadOnlyBeaconState, att ethpb.Att) ([][]primitives.ValidatorIndex, error) {
|
||||
return attestationCommittees(ctx, st, att, BeaconCommitteeFromState)
|
||||
}
|
||||
|
||||
// AttestationCommitteesFromCache has the same functionality as AttestationCommitteesFromState, but only returns a value
|
||||
// when all attestation committees are already cached.
|
||||
func AttestationCommitteesFromCache(ctx context.Context, st state.ReadOnlyBeaconState, att ethpb.Att) (bool, [][]primitives.ValidatorIndex, error) {
|
||||
committees, err := attestationCommittees(ctx, st, att, BeaconCommitteeFromCache)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
if len(committees) == 0 {
|
||||
return false, nil, nil
|
||||
}
|
||||
for _, c := range committees {
|
||||
if len(c) == 0 {
|
||||
return false, nil, nil
|
||||
}
|
||||
}
|
||||
return true, committees, nil
|
||||
}
|
||||
|
||||
func attestationCommittees(
|
||||
ctx context.Context,
|
||||
st state.ReadOnlyBeaconState,
|
||||
att ethpb.Att,
|
||||
committeeFunc beaconCommitteeFunc,
|
||||
) ([][]primitives.ValidatorIndex, error) {
|
||||
var committees [][]primitives.ValidatorIndex
|
||||
if att.Version() >= version.Electra {
|
||||
committeeIndices := att.CommitteeBitsVal().BitIndices()
|
||||
committees = make([][]primitives.ValidatorIndex, len(committeeIndices))
|
||||
for i, ci := range committeeIndices {
|
||||
committee, err := BeaconCommitteeFromState(ctx, st, att.GetData().Slot, primitives.CommitteeIndex(ci))
|
||||
committee, err := committeeFunc(ctx, st, att.GetData().Slot, primitives.CommitteeIndex(ci))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
committees[i] = committee
|
||||
}
|
||||
} else {
|
||||
committee, err := BeaconCommitteeFromState(ctx, st, att.GetData().Slot, att.GetData().CommitteeIndex)
|
||||
committee, err := committeeFunc(ctx, st, att.GetData().Slot, att.GetData().CommitteeIndex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -164,6 +198,27 @@ func BeaconCommitteeFromState(ctx context.Context, state state.ReadOnlyBeaconSta
|
||||
return BeaconCommittee(ctx, activeIndices, seed, slot, committeeIndex)
|
||||
}
|
||||
|
||||
// BeaconCommitteeFromCache has the same functionality as BeaconCommitteeFromState, but only returns a value
|
||||
// when the committee is already cached.
|
||||
func BeaconCommitteeFromCache(
|
||||
ctx context.Context,
|
||||
state state.ReadOnlyBeaconState,
|
||||
slot primitives.Slot,
|
||||
committeeIndex primitives.CommitteeIndex,
|
||||
) ([]primitives.ValidatorIndex, error) {
|
||||
epoch := slots.ToEpoch(slot)
|
||||
seed, err := Seed(state, epoch, params.BeaconConfig().DomainBeaconAttester)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get seed")
|
||||
}
|
||||
|
||||
committee, err := committeeCache.Committee(ctx, slot, seed, committeeIndex)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not interface with committee cache")
|
||||
}
|
||||
return committee, nil
|
||||
}
|
||||
|
||||
// BeaconCommittee returns the beacon committee of a given slot and committee index. The
|
||||
// validator indices and seed are provided as an argument rather than an imported implementation
|
||||
// from the spec definition. Having them as an argument allows for cheaper computation run time.
|
||||
|
||||
@@ -729,7 +729,9 @@ func TestCommitteeIndices(t *testing.T) {
|
||||
assert.DeepEqual(t, []primitives.CommitteeIndex{0, 1, 3}, indices)
|
||||
}
|
||||
|
||||
func TestAttestationCommittees(t *testing.T) {
|
||||
func TestAttestationCommitteesFromState(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
validators := make([]*ethpb.Validator, params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().TargetCommitteeSize))
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = ðpb.Validator{
|
||||
@@ -745,7 +747,7 @@ func TestAttestationCommittees(t *testing.T) {
|
||||
|
||||
t.Run("pre-Electra", func(t *testing.T) {
|
||||
att := ðpb.Attestation{Data: ðpb.AttestationData{CommitteeIndex: 0}}
|
||||
committees, err := helpers.AttestationCommittees(context.Background(), state, att)
|
||||
committees, err := helpers.AttestationCommitteesFromState(ctx, state, att)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(committees))
|
||||
assert.Equal(t, params.BeaconConfig().TargetCommitteeSize, uint64(len(committees[0])))
|
||||
@@ -755,7 +757,7 @@ func TestAttestationCommittees(t *testing.T) {
|
||||
bits.SetBitAt(0, true)
|
||||
bits.SetBitAt(1, true)
|
||||
att := ðpb.AttestationElectra{CommitteeBits: bits, Data: ðpb.AttestationData{}}
|
||||
committees, err := helpers.AttestationCommittees(context.Background(), state, att)
|
||||
committees, err := helpers.AttestationCommitteesFromState(ctx, state, att)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 2, len(committees))
|
||||
assert.Equal(t, params.BeaconConfig().TargetCommitteeSize, uint64(len(committees[0])))
|
||||
@@ -763,9 +765,58 @@ func TestAttestationCommittees(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestBeaconCommittees(t *testing.T) {
|
||||
prevConfig := params.BeaconConfig().Copy()
|
||||
defer params.OverrideBeaconConfig(prevConfig)
|
||||
func TestAttestationCommitteesFromCache(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
validators := make([]*ethpb.Validator, params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().TargetCommitteeSize))
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = ðpb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
|
||||
state, err := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{
|
||||
Validators: validators,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("pre-Electra", func(t *testing.T) {
|
||||
helpers.ClearCache()
|
||||
att := ðpb.Attestation{Data: ðpb.AttestationData{CommitteeIndex: 0}}
|
||||
ok, _, err := helpers.AttestationCommitteesFromCache(ctx, state, att)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, ok)
|
||||
require.NoError(t, helpers.UpdateCommitteeCache(ctx, state, 0))
|
||||
ok, committees, err := helpers.AttestationCommitteesFromCache(ctx, state, att)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, ok)
|
||||
require.Equal(t, 1, len(committees))
|
||||
assert.Equal(t, params.BeaconConfig().TargetCommitteeSize, uint64(len(committees[0])))
|
||||
})
|
||||
t.Run("post-Electra", func(t *testing.T) {
|
||||
helpers.ClearCache()
|
||||
bits := primitives.NewAttestationCommitteeBits()
|
||||
bits.SetBitAt(0, true)
|
||||
bits.SetBitAt(1, true)
|
||||
att := ðpb.AttestationElectra{CommitteeBits: bits, Data: ðpb.AttestationData{}}
|
||||
ok, _, err := helpers.AttestationCommitteesFromCache(ctx, state, att)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, ok)
|
||||
require.NoError(t, helpers.UpdateCommitteeCache(ctx, state, 0))
|
||||
ok, committees, err := helpers.AttestationCommitteesFromCache(ctx, state, att)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, ok)
|
||||
require.Equal(t, 2, len(committees))
|
||||
assert.Equal(t, params.BeaconConfig().TargetCommitteeSize, uint64(len(committees[0])))
|
||||
assert.Equal(t, params.BeaconConfig().TargetCommitteeSize, uint64(len(committees[1])))
|
||||
})
|
||||
}
|
||||
|
||||
func TestBeaconCommitteesFromState(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
params.SetupTestConfigCleanup(t)
|
||||
c := params.BeaconConfig().Copy()
|
||||
c.MinGenesisActiveValidatorCount = 128
|
||||
c.SlotsPerEpoch = 4
|
||||
@@ -774,15 +825,49 @@ func TestBeaconCommittees(t *testing.T) {
|
||||
|
||||
state, _ := util.DeterministicGenesisState(t, 256)
|
||||
|
||||
activeCount, err := helpers.ActiveValidatorCount(context.Background(), state, 0)
|
||||
activeCount, err := helpers.ActiveValidatorCount(ctx, state, 0)
|
||||
require.NoError(t, err)
|
||||
committeesPerSlot := helpers.SlotCommitteeCount(activeCount)
|
||||
committees, err := helpers.BeaconCommittees(context.Background(), state, 0)
|
||||
committees, err := helpers.BeaconCommittees(ctx, state, 0)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, committeesPerSlot, uint64(len(committees)))
|
||||
for idx := primitives.CommitteeIndex(0); idx < primitives.CommitteeIndex(len(committees)); idx++ {
|
||||
committee, err := helpers.BeaconCommitteeFromState(context.Background(), state, 0, idx)
|
||||
committee, err := helpers.BeaconCommitteeFromState(ctx, state, 0, idx)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, committees[idx], committee)
|
||||
assert.DeepEqual(t, committees[idx], committee)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBeaconCommitteesFromCache(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
params.SetupTestConfigCleanup(t)
|
||||
c := params.BeaconConfig().Copy()
|
||||
c.MinGenesisActiveValidatorCount = 128
|
||||
c.SlotsPerEpoch = 4
|
||||
c.TargetCommitteeSize = 16
|
||||
params.OverrideBeaconConfig(c)
|
||||
|
||||
state, _ := util.DeterministicGenesisState(t, 256)
|
||||
|
||||
activeCount, err := helpers.ActiveValidatorCount(ctx, state, 0)
|
||||
require.NoError(t, err)
|
||||
committeesPerSlot := helpers.SlotCommitteeCount(activeCount)
|
||||
committees, err := helpers.BeaconCommittees(ctx, state, 0)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, committeesPerSlot, uint64(len(committees)))
|
||||
|
||||
helpers.ClearCache()
|
||||
for idx := primitives.CommitteeIndex(0); idx < primitives.CommitteeIndex(len(committees)); idx++ {
|
||||
committee, err := helpers.BeaconCommitteeFromCache(ctx, state, 0, idx)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, len(committee))
|
||||
}
|
||||
|
||||
require.NoError(t, helpers.UpdateCommitteeCache(ctx, state, 0))
|
||||
for idx := primitives.CommitteeIndex(0); idx < primitives.CommitteeIndex(len(committees)); idx++ {
|
||||
committee, err := helpers.BeaconCommitteeFromCache(ctx, state, 0, idx)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, committees[idx], committee)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,6 +110,7 @@ type HeadAccessDatabase interface {
|
||||
|
||||
// Block related methods.
|
||||
HeadBlock(ctx context.Context) (interfaces.ReadOnlySignedBeaconBlock, error)
|
||||
HeadBlockRoot() ([32]byte, error)
|
||||
SaveHeadBlockRoot(ctx context.Context, blockRoot [32]byte) error
|
||||
|
||||
// Genesis operations.
|
||||
|
||||
@@ -30,22 +30,32 @@ var errInvalidSlotRange = errors.New("invalid end slot and start slot provided")
|
||||
func (s *Store) Block(ctx context.Context, blockRoot [32]byte) (interfaces.ReadOnlySignedBeaconBlock, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "BeaconDB.Block")
|
||||
defer span.End()
|
||||
// Return block from cache if it exists.
|
||||
blk, err := s.getBlock(ctx, blockRoot, nil)
|
||||
if errors.Is(err, ErrNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
return blk, err
|
||||
}
|
||||
|
||||
func (s *Store) getBlock(ctx context.Context, blockRoot [32]byte, tx *bolt.Tx) (interfaces.ReadOnlySignedBeaconBlock, error) {
|
||||
if v, ok := s.blockCache.Get(string(blockRoot[:])); v != nil && ok {
|
||||
return v.(interfaces.ReadOnlySignedBeaconBlock), nil
|
||||
}
|
||||
var blk interfaces.ReadOnlySignedBeaconBlock
|
||||
err := s.db.View(func(tx *bolt.Tx) error {
|
||||
bkt := tx.Bucket(blocksBucket)
|
||||
enc := bkt.Get(blockRoot[:])
|
||||
if enc == nil {
|
||||
return nil
|
||||
}
|
||||
// This method allows the caller to pass in its tx if one is already open.
|
||||
// Or if a nil value is used, a transaction will be managed intenally.
|
||||
if tx == nil {
|
||||
var err error
|
||||
blk, err = unmarshalBlock(ctx, enc)
|
||||
return err
|
||||
})
|
||||
return blk, err
|
||||
tx, err = s.db.Begin(false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
if err := tx.Rollback(); err != nil {
|
||||
log.WithError(err).Error("could not rollback read-only getBlock transaction")
|
||||
}
|
||||
}()
|
||||
}
|
||||
return unmarshalBlock(ctx, tx.Bucket(blocksBucket).Get(blockRoot[:]))
|
||||
}
|
||||
|
||||
// OriginCheckpointBlockRoot returns the value written to the db in SaveOriginCheckpointBlockRoot
|
||||
@@ -70,6 +80,21 @@ func (s *Store) OriginCheckpointBlockRoot(ctx context.Context) ([32]byte, error)
|
||||
return root, err
|
||||
}
|
||||
|
||||
// HeadBlockRoot returns the latest canonical block root in the Ethereum Beacon Chain.
|
||||
func (s *Store) HeadBlockRoot() ([32]byte, error) {
|
||||
var root [32]byte
|
||||
err := s.db.View(func(tx *bolt.Tx) error {
|
||||
bkt := tx.Bucket(blocksBucket)
|
||||
headRoot := bkt.Get(headBlockRootKey)
|
||||
if len(headRoot) == 0 {
|
||||
return errors.New("no head block root found")
|
||||
}
|
||||
copy(root[:], headRoot)
|
||||
return nil
|
||||
})
|
||||
return root, err
|
||||
}
|
||||
|
||||
// HeadBlock returns the latest canonical block in the Ethereum Beacon Chain.
|
||||
func (s *Store) HeadBlock(ctx context.Context) (interfaces.ReadOnlySignedBeaconBlock, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "BeaconDB.HeadBlock")
|
||||
@@ -227,6 +252,21 @@ func (s *Store) DeleteBlock(ctx context.Context, root [32]byte) error {
|
||||
return ErrDeleteJustifiedAndFinalized
|
||||
}
|
||||
|
||||
// Look up the block to find its slot; needed to remove the slot index entry.
|
||||
blk, err := s.getBlock(ctx, root, tx)
|
||||
if err != nil {
|
||||
// getBlock can return ErrNotFound, in which case we won't even try to delete it.
|
||||
if errors.Is(err, ErrNotFound) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
if err := s.deleteSlotIndexEntry(tx, blk.Block().Slot(), root); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.deleteMatchingParentIndex(tx, blk.Block().ParentRoot(), root); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.deleteBlock(tx, root[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -899,6 +939,9 @@ func createBlockIndicesFromFilters(ctx context.Context, f *filters.QueryFilter)
|
||||
|
||||
// unmarshal block from marshaled proto beacon block bytes to versioned beacon block struct type.
|
||||
func unmarshalBlock(_ context.Context, enc []byte) (interfaces.ReadOnlySignedBeaconBlock, error) {
|
||||
if len(enc) == 0 {
|
||||
return nil, errors.Wrap(ErrNotFound, "empty block bytes in db")
|
||||
}
|
||||
var err error
|
||||
enc, err = snappy.Decode(nil, enc)
|
||||
if err != nil {
|
||||
@@ -1050,6 +1093,47 @@ func (s *Store) deleteBlock(tx *bolt.Tx, root []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Store) deleteMatchingParentIndex(tx *bolt.Tx, parent, child [32]byte) error {
|
||||
bkt := tx.Bucket(blockParentRootIndicesBucket)
|
||||
if err := deleteRootIndexEntry(bkt, parent[:], child); err != nil {
|
||||
return errors.Wrap(err, "could not delete parent root index entry")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Store) deleteSlotIndexEntry(tx *bolt.Tx, slot primitives.Slot, root [32]byte) error {
|
||||
key := bytesutil.SlotToBytesBigEndian(slot)
|
||||
bkt := tx.Bucket(blockSlotIndicesBucket)
|
||||
if err := deleteRootIndexEntry(bkt, key, root); err != nil {
|
||||
return errors.Wrap(err, "could not delete slot index entry")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func deleteRootIndexEntry(bkt *bolt.Bucket, key []byte, root [32]byte) error {
|
||||
packed := bkt.Get(key)
|
||||
if len(packed) == 0 {
|
||||
return nil
|
||||
}
|
||||
updated, err := removeRoot(packed, root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Don't update the value if the root was not found.
|
||||
if bytes.Equal(updated, packed) {
|
||||
return nil
|
||||
}
|
||||
// If there are no other roots in the key, just delete it.
|
||||
if len(updated) == 0 {
|
||||
if err := bkt.Delete(key); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
// Update the key with the root removed.
|
||||
return bkt.Put(key, updated)
|
||||
}
|
||||
|
||||
func (s *Store) deleteValidatorHashes(tx *bolt.Tx, root []byte) error {
|
||||
ok, err := s.isStateValidatorMigrationOver()
|
||||
if err != nil {
|
||||
|
||||
@@ -196,9 +196,13 @@ func TestStore_BlocksCRUD(t *testing.T) {
|
||||
blockRoot, err := blk.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = db.getBlock(ctx, blockRoot, nil)
|
||||
require.ErrorIs(t, err, ErrNotFound)
|
||||
retrievedBlock, err := db.Block(ctx, blockRoot)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, nil, retrievedBlock, "Expected nil block")
|
||||
_, err = db.getBlock(ctx, blockRoot, nil)
|
||||
require.ErrorIs(t, err, ErrNotFound)
|
||||
|
||||
require.NoError(t, db.SaveBlock(ctx, blk))
|
||||
assert.Equal(t, true, db.HasBlock(ctx, blockRoot), "Expected block to exist in the db")
|
||||
@@ -214,10 +218,34 @@ func TestStore_BlocksCRUD(t *testing.T) {
|
||||
retrievedPb, err := retrievedBlock.Proto()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, proto.Equal(wantedPb, retrievedPb), "Wanted: %v, received: %v", wanted, retrievedBlock)
|
||||
// Check that the block is in the slot->block index
|
||||
found, roots, err := db.BlockRootsBySlot(ctx, blk.Block().Slot())
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, found)
|
||||
require.Equal(t, 1, len(roots))
|
||||
require.Equal(t, blockRoot, roots[0])
|
||||
// Delete the block, then check that it is no longer in the index.
|
||||
|
||||
parent := blk.Block().ParentRoot()
|
||||
testCheckParentIndices(t, db.db, parent, true)
|
||||
require.NoError(t, db.DeleteBlock(ctx, blockRoot))
|
||||
require.NoError(t, err)
|
||||
testCheckParentIndices(t, db.db, parent, false)
|
||||
found, roots, err = db.BlockRootsBySlot(ctx, blk.Block().Slot())
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, found)
|
||||
require.Equal(t, 0, len(roots))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testCheckParentIndices(t *testing.T, db *bolt.DB, parent [32]byte, expected bool) {
|
||||
require.NoError(t, db.View(func(tx *bolt.Tx) error {
|
||||
require.Equal(t, expected, tx.Bucket(blockParentRootIndicesBucket).Get(parent[:]) != nil)
|
||||
return nil
|
||||
}))
|
||||
}
|
||||
|
||||
func TestStore_BlocksHandleZeroCase(t *testing.T) {
|
||||
for _, tt := range blockTests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
@@ -114,3 +114,27 @@ func splitRoots(b []byte) ([][32]byte, error) {
|
||||
}
|
||||
return rl, nil
|
||||
}
|
||||
|
||||
func removeRoot(roots []byte, root [32]byte) ([]byte, error) {
|
||||
if len(roots) == 0 {
|
||||
return []byte{}, nil
|
||||
}
|
||||
if len(roots) == 32 && bytes.Equal(roots, root[:]) {
|
||||
return []byte{}, nil
|
||||
}
|
||||
if len(roots)%32 != 0 {
|
||||
return nil, errors.Wrapf(errMisalignedRootList, "root list len=%d", len(roots))
|
||||
}
|
||||
|
||||
search := root[:]
|
||||
for i := 0; i <= len(roots)-32; i += 32 {
|
||||
if bytes.Equal(roots[i:i+32], search) {
|
||||
result := make([]byte, len(roots)-32)
|
||||
copy(result, roots[:i])
|
||||
copy(result[i:], roots[i+32:])
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
|
||||
return roots, nil
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package kv
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"testing"
|
||||
@@ -195,3 +196,85 @@ func TestSplitRoots(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func tPad(p ...[]byte) []byte {
|
||||
r := make([]byte, 32*len(p))
|
||||
for i, b := range p {
|
||||
copy(r[i*32:], b)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func TestRemoveRoot(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
roots []byte
|
||||
root [32]byte
|
||||
expect []byte
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
roots: []byte{},
|
||||
root: [32]byte{0xde, 0xad, 0xbe, 0xef},
|
||||
expect: []byte{},
|
||||
},
|
||||
{
|
||||
name: "single",
|
||||
roots: tPad([]byte{0xde, 0xad, 0xbe, 0xef}),
|
||||
root: [32]byte{0xde, 0xad, 0xbe, 0xef},
|
||||
expect: []byte{},
|
||||
},
|
||||
{
|
||||
name: "single, different",
|
||||
roots: tPad([]byte{0xde, 0xad, 0xbe, 0xef}),
|
||||
root: [32]byte{0xde, 0xad, 0xbe, 0xee},
|
||||
expect: tPad([]byte{0xde, 0xad, 0xbe, 0xef}),
|
||||
},
|
||||
{
|
||||
name: "multi",
|
||||
roots: tPad([]byte{0xde, 0xad, 0xbe, 0xef}, []byte{0xac, 0x1d, 0xfa, 0xce}),
|
||||
root: [32]byte{0xac, 0x1d, 0xfa, 0xce},
|
||||
expect: tPad([]byte{0xde, 0xad, 0xbe, 0xef}),
|
||||
},
|
||||
{
|
||||
name: "multi, reordered",
|
||||
roots: tPad([]byte{0xac, 0x1d, 0xfa, 0xce}, []byte{0xde, 0xad, 0xbe, 0xef}),
|
||||
root: [32]byte{0xac, 0x1d, 0xfa, 0xce},
|
||||
expect: tPad([]byte{0xde, 0xad, 0xbe, 0xef}),
|
||||
},
|
||||
{
|
||||
name: "multi, 3",
|
||||
roots: tPad([]byte{0xac, 0x1d, 0xfa, 0xce}, []byte{0xbe, 0xef, 0xca, 0xb5}, []byte{0xde, 0xad, 0xbe, 0xef}),
|
||||
root: [32]byte{0xac, 0x1d, 0xfa, 0xce},
|
||||
expect: tPad([]byte{0xbe, 0xef, 0xca, 0xb5}, []byte{0xde, 0xad, 0xbe, 0xef}),
|
||||
},
|
||||
{
|
||||
name: "multi, different",
|
||||
roots: tPad([]byte{0xde, 0xad, 0xbe, 0xef}, []byte{0xac, 0x1d, 0xfa, 0xce}),
|
||||
root: [32]byte{0xac, 0x1d, 0xbe, 0xa7},
|
||||
expect: tPad([]byte{0xde, 0xad, 0xbe, 0xef}, []byte{0xac, 0x1d, 0xfa, 0xce}),
|
||||
},
|
||||
{
|
||||
name: "misaligned",
|
||||
roots: make([]byte, 61),
|
||||
root: [32]byte{0xac, 0x1d, 0xbe, 0xa7},
|
||||
err: errMisalignedRootList,
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
before := make([]byte, len(c.roots))
|
||||
copy(before, c.roots)
|
||||
r, err := removeRoot(c.roots, c.root)
|
||||
if c.err != nil {
|
||||
require.ErrorIs(t, err, c.err)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(c.expect), len(r))
|
||||
require.Equal(t, true, bytes.Equal(c.expect, r))
|
||||
require.Equal(t, true, bytes.Equal(before, c.roots))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package kv
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
bolt "go.etcd.io/bbolt"
|
||||
@@ -19,7 +21,17 @@ func (s *Store) LastValidatedCheckpoint(ctx context.Context) (*ethpb.Checkpoint,
|
||||
if enc == nil {
|
||||
var finErr error
|
||||
checkpoint, finErr = s.FinalizedCheckpoint(ctx)
|
||||
return finErr
|
||||
if finErr != nil {
|
||||
return finErr
|
||||
}
|
||||
if bytes.Equal(checkpoint.Root, params.BeaconConfig().ZeroHash[:]) {
|
||||
bkt = tx.Bucket(blocksBucket)
|
||||
r := bkt.Get(genesisBlockRootKey)
|
||||
if r != nil {
|
||||
checkpoint.Root = r
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
checkpoint = ðpb.Checkpoint{}
|
||||
return decode(ctx, enc, checkpoint)
|
||||
|
||||
@@ -252,6 +252,13 @@ func (s *Store) tips() ([][32]byte, []primitives.Slot) {
|
||||
return roots, slots
|
||||
}
|
||||
|
||||
func (f *ForkChoice) HighestReceivedBlockRoot() [32]byte {
|
||||
if f.store.highestReceivedNode == nil {
|
||||
return [32]byte{}
|
||||
}
|
||||
return f.store.highestReceivedNode.root
|
||||
}
|
||||
|
||||
// HighestReceivedBlockSlot returns the highest slot received by the forkchoice
|
||||
func (f *ForkChoice) HighestReceivedBlockSlot() primitives.Slot {
|
||||
if f.store.highestReceivedNode == nil {
|
||||
|
||||
@@ -65,6 +65,7 @@ type FastGetter interface {
|
||||
FinalizedPayloadBlockHash() [32]byte
|
||||
HasNode([32]byte) bool
|
||||
HighestReceivedBlockSlot() primitives.Slot
|
||||
HighestReceivedBlockRoot() [32]byte
|
||||
HighestReceivedBlockDelay() primitives.Slot
|
||||
IsCanonical(root [32]byte) bool
|
||||
IsOptimistic(root [32]byte) (bool, error)
|
||||
|
||||
@@ -114,6 +114,13 @@ func (ro *ROForkChoice) HighestReceivedBlockSlot() primitives.Slot {
|
||||
return ro.getter.HighestReceivedBlockSlot()
|
||||
}
|
||||
|
||||
// HighestReceivedBlockRoot delegates to the underlying forkchoice call, under a lock.
|
||||
func (ro *ROForkChoice) HighestReceivedBlockRoot() [32]byte {
|
||||
ro.l.RLock()
|
||||
defer ro.l.RUnlock()
|
||||
return ro.getter.HighestReceivedBlockRoot()
|
||||
}
|
||||
|
||||
// HighestReceivedBlockDelay delegates to the underlying forkchoice call, under a lock.
|
||||
func (ro *ROForkChoice) HighestReceivedBlockDelay() primitives.Slot {
|
||||
ro.l.RLock()
|
||||
|
||||
@@ -29,6 +29,7 @@ const (
|
||||
unrealizedJustifiedPayloadBlockHashCalled
|
||||
nodeCountCalled
|
||||
highestReceivedBlockSlotCalled
|
||||
highestReceivedBlockRootCalled
|
||||
highestReceivedBlockDelayCalled
|
||||
receivedBlocksLastEpochCalled
|
||||
weightCalled
|
||||
@@ -252,6 +253,11 @@ func (ro *mockROForkchoice) HighestReceivedBlockSlot() primitives.Slot {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (ro *mockROForkchoice) HighestReceivedBlockRoot() [32]byte {
|
||||
ro.calls = append(ro.calls, highestReceivedBlockRootCalled)
|
||||
return [32]byte{}
|
||||
}
|
||||
|
||||
func (ro *mockROForkchoice) HighestReceivedBlockDelay() primitives.Slot {
|
||||
ro.calls = append(ro.calls, highestReceivedBlockDelayCalled)
|
||||
return 0
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1/attestation"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// SaveUnaggregatedAttestation saves an unaggregated attestation in cache.
|
||||
@@ -60,7 +61,8 @@ func (c *AttCaches) UnaggregatedAttestations() ([]ethpb.Att, error) {
|
||||
for _, att := range unAggregatedAtts {
|
||||
seen, err := c.hasSeenBit(att)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
log.WithError(err).Debug("Could not check if unaggregated attestation's bit has been seen. Attestation will not be returned")
|
||||
continue
|
||||
}
|
||||
if !seen {
|
||||
atts = append(atts, att.Clone())
|
||||
@@ -137,7 +139,7 @@ func (c *AttCaches) DeleteUnaggregatedAttestation(att ethpb.Att) error {
|
||||
}
|
||||
|
||||
if err := c.insertSeenBit(att); err != nil {
|
||||
return err
|
||||
log.WithError(err).Debug("Could not insert seen bit of unaggregated attestation. Attestation will be deleted")
|
||||
}
|
||||
|
||||
id, err := attestation.NewId(att, attestation.Full)
|
||||
@@ -163,7 +165,12 @@ func (c *AttCaches) DeleteSeenUnaggregatedAttestations() (int, error) {
|
||||
if att == nil || att.IsNil() || att.IsAggregated() {
|
||||
continue
|
||||
}
|
||||
if seen, err := c.hasSeenBit(att); err == nil && seen {
|
||||
seen, err := c.hasSeenBit(att)
|
||||
if err != nil {
|
||||
log.WithError(err).Debug("Could not check if unaggregated attestation's bit has been seen. Attestation will be deleted")
|
||||
seen = true
|
||||
}
|
||||
if seen {
|
||||
delete(c.unAggregatedAtt, r)
|
||||
count++
|
||||
}
|
||||
|
||||
@@ -17,6 +17,24 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
)
|
||||
|
||||
func TestKV_Unaggregated_UnaggregatedAttestations(t *testing.T) {
|
||||
t.Run("not returned when hasSeenBit fails", func(t *testing.T) {
|
||||
att := util.HydrateAttestation(ðpb.Attestation{Data: ðpb.AttestationData{Slot: 1}, AggregationBits: bitfield.Bitlist{0b101}})
|
||||
id, err := attestation.NewId(att, attestation.Data)
|
||||
require.NoError(t, err)
|
||||
|
||||
cache := NewAttCaches()
|
||||
require.NoError(t, cache.SaveUnaggregatedAttestation(att))
|
||||
cache.seenAtt.Delete(id.String())
|
||||
// cache a bitlist whose length is different from the attestation bitlist's length
|
||||
cache.seenAtt.Set(id.String(), []bitfield.Bitlist{{0b1001}}, c.DefaultExpiration)
|
||||
|
||||
atts, err := cache.UnaggregatedAttestations()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, len(atts))
|
||||
})
|
||||
}
|
||||
|
||||
func TestKV_Unaggregated_SaveUnaggregatedAttestation(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -155,6 +173,21 @@ func TestKV_Unaggregated_DeleteUnaggregatedAttestation(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, []ethpb.Att{}, returned)
|
||||
})
|
||||
|
||||
t.Run("deleted when insertSeenBit fails", func(t *testing.T) {
|
||||
att := util.HydrateAttestation(ðpb.Attestation{Data: ðpb.AttestationData{Slot: 1}, AggregationBits: bitfield.Bitlist{0b101}})
|
||||
id, err := attestation.NewId(att, attestation.Data)
|
||||
require.NoError(t, err)
|
||||
|
||||
cache := NewAttCaches()
|
||||
require.NoError(t, cache.SaveUnaggregatedAttestation(att))
|
||||
cache.seenAtt.Delete(id.String())
|
||||
// cache a bitlist whose length is different from the attestation bitlist's length
|
||||
cache.seenAtt.Set(id.String(), []bitfield.Bitlist{{0b1001}}, c.DefaultExpiration)
|
||||
|
||||
require.NoError(t, cache.DeleteUnaggregatedAttestation(att))
|
||||
assert.Equal(t, 0, len(cache.unAggregatedAtt), "Attestation was not deleted")
|
||||
})
|
||||
}
|
||||
|
||||
func TestKV_Unaggregated_DeleteSeenUnaggregatedAttestations(t *testing.T) {
|
||||
@@ -232,6 +265,23 @@ func TestKV_Unaggregated_DeleteSeenUnaggregatedAttestations(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, []ethpb.Att{}, returned)
|
||||
})
|
||||
|
||||
t.Run("deleted when hasSeenBit fails", func(t *testing.T) {
|
||||
att := util.HydrateAttestation(ðpb.Attestation{Data: ðpb.AttestationData{Slot: 1}, AggregationBits: bitfield.Bitlist{0b101}})
|
||||
id, err := attestation.NewId(att, attestation.Data)
|
||||
require.NoError(t, err)
|
||||
|
||||
cache := NewAttCaches()
|
||||
require.NoError(t, cache.SaveUnaggregatedAttestation(att))
|
||||
cache.seenAtt.Delete(id.String())
|
||||
// cache a bitlist whose length is different from the attestation bitlist's length
|
||||
cache.seenAtt.Set(id.String(), []bitfield.Bitlist{{0b1001}}, c.DefaultExpiration)
|
||||
|
||||
count, err := cache.DeleteSeenUnaggregatedAttestations()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 1, count)
|
||||
assert.Equal(t, 0, len(cache.unAggregatedAtt), "Attestation was not deleted")
|
||||
})
|
||||
}
|
||||
|
||||
func TestKV_Unaggregated_UnaggregatedAttestationsBySlotIndex(t *testing.T) {
|
||||
|
||||
@@ -633,7 +633,7 @@ func (s *Server) SubmitBLSToExecutionChanges(w http.ResponseWriter, r *http.Requ
|
||||
toBroadcast = append(toBroadcast, sbls)
|
||||
}
|
||||
}
|
||||
go s.broadcastBLSChanges(ctx, toBroadcast)
|
||||
go s.broadcastBLSChanges(context.Background(), toBroadcast)
|
||||
if len(failures) > 0 {
|
||||
failuresErr := &server.IndexedVerificationFailureError{
|
||||
Code: http.StatusBadRequest,
|
||||
|
||||
@@ -160,6 +160,8 @@ func TestGetSpec(t *testing.T) {
|
||||
config.MaxTransactionsPerPayload = 99
|
||||
config.FieldElementsPerBlob = 100
|
||||
config.KzgCommitmentInclusionProofDepth = 101
|
||||
config.BlobsidecarSubnetCount = 102
|
||||
config.BlobsidecarSubnetCountElectra = 103
|
||||
|
||||
var dbp [4]byte
|
||||
copy(dbp[:], []byte{'0', '0', '0', '1'})
|
||||
@@ -198,7 +200,7 @@ func TestGetSpec(t *testing.T) {
|
||||
data, ok := resp.Data.(map[string]interface{})
|
||||
require.Equal(t, true, ok)
|
||||
|
||||
assert.Equal(t, 168, len(data))
|
||||
assert.Equal(t, 170, len(data))
|
||||
for k, v := range data {
|
||||
t.Run(k, func(t *testing.T) {
|
||||
switch k {
|
||||
@@ -559,6 +561,10 @@ func TestGetSpec(t *testing.T) {
|
||||
assert.Equal(t, "100", v)
|
||||
case "KZG_COMMITMENT_INCLUSION_PROOF_DEPTH":
|
||||
assert.Equal(t, "101", v)
|
||||
case "BLOB_SIDECAR_SUBNET_COUNT":
|
||||
assert.Equal(t, "102", v)
|
||||
case "BLOB_SIDECAR_SUBNET_COUNT_ELECTRA":
|
||||
assert.Equal(t, "103", v)
|
||||
default:
|
||||
t.Errorf("Incorrect key: %s", k)
|
||||
}
|
||||
|
||||
@@ -18,7 +18,8 @@ go_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/time:go_default_library",
|
||||
"//beacon-chain/core/transition:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//consensus-types/payload-attribute:go_default_library",
|
||||
@@ -58,6 +59,7 @@ go_test(
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//consensus-types/payload-attribute:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//proto/engine/v1:go_default_library",
|
||||
"//proto/eth/v1:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
@@ -20,7 +21,8 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/feed/operation"
|
||||
statefeed "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/feed/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
|
||||
chaintime "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/transition"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
payloadattribute "github.com/prysmaticlabs/prysm/v5/consensus-types/payload-attribute"
|
||||
@@ -352,9 +354,18 @@ func writeLazyReaderWithRecover(w *streamingResponseWriterController, lr lazyRea
|
||||
if r := recover(); r != nil {
|
||||
log.WithField("panic", r).Error("Recovered from panic while writing event to client.")
|
||||
err = errWriterUnusable
|
||||
debug.PrintStack()
|
||||
}
|
||||
}()
|
||||
if lr == nil {
|
||||
log.Warn("Event stream skipping a nil lazy event reader callback")
|
||||
return nil
|
||||
}
|
||||
r := lr()
|
||||
if r == nil {
|
||||
log.Warn("Event stream skipping a nil event reader")
|
||||
return nil
|
||||
}
|
||||
out, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -600,27 +611,14 @@ func (s *Server) lazyReaderForEvent(ctx context.Context, event *feed.Event, topi
|
||||
|
||||
var errUnsupportedPayloadAttribute = errors.New("cannot compute payload attributes pre-Bellatrix")
|
||||
|
||||
func (s *Server) computePayloadAttributes(ctx context.Context, ev payloadattribute.EventData) (payloadattribute.Attributer, error) {
|
||||
v := ev.HeadState.Version()
|
||||
func (s *Server) computePayloadAttributes(ctx context.Context, st state.ReadOnlyBeaconState, root [32]byte, proposer primitives.ValidatorIndex, timestamp uint64, randao []byte) (payloadattribute.Attributer, error) {
|
||||
v := st.Version()
|
||||
if v < version.Bellatrix {
|
||||
return nil, errors.Wrapf(errUnsupportedPayloadAttribute, "%s is not supported", version.String(v))
|
||||
}
|
||||
|
||||
t, err := slots.ToTime(ev.HeadState.GenesisTime(), ev.HeadState.Slot())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get head state slot time")
|
||||
}
|
||||
timestamp := uint64(t.Unix())
|
||||
prevRando, err := helpers.RandaoMix(ev.HeadState, chaintime.CurrentEpoch(ev.HeadState))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get head state randao mix")
|
||||
}
|
||||
proposerIndex, err := helpers.BeaconProposerIndex(ctx, ev.HeadState)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get head state proposer index")
|
||||
}
|
||||
feeRecpt := params.BeaconConfig().DefaultFeeRecipient.Bytes()
|
||||
tValidator, exists := s.TrackedValidatorsCache.Validator(proposerIndex)
|
||||
tValidator, exists := s.TrackedValidatorsCache.Validator(proposer)
|
||||
if exists {
|
||||
feeRecpt = tValidator.FeeRecipient[:]
|
||||
}
|
||||
@@ -628,34 +626,30 @@ func (s *Server) computePayloadAttributes(ctx context.Context, ev payloadattribu
|
||||
if v == version.Bellatrix {
|
||||
return payloadattribute.New(&engine.PayloadAttributes{
|
||||
Timestamp: timestamp,
|
||||
PrevRandao: prevRando,
|
||||
PrevRandao: randao,
|
||||
SuggestedFeeRecipient: feeRecpt,
|
||||
})
|
||||
}
|
||||
|
||||
w, _, err := ev.HeadState.ExpectedWithdrawals()
|
||||
w, _, err := st.ExpectedWithdrawals()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get withdrawals from head state")
|
||||
}
|
||||
if v == version.Capella {
|
||||
return payloadattribute.New(&engine.PayloadAttributesV2{
|
||||
Timestamp: timestamp,
|
||||
PrevRandao: prevRando,
|
||||
PrevRandao: randao,
|
||||
SuggestedFeeRecipient: feeRecpt,
|
||||
Withdrawals: w,
|
||||
})
|
||||
}
|
||||
|
||||
pr, err := ev.HeadBlock.Block().HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not compute head block root")
|
||||
}
|
||||
return payloadattribute.New(&engine.PayloadAttributesV3{
|
||||
Timestamp: timestamp,
|
||||
PrevRandao: prevRando,
|
||||
PrevRandao: randao,
|
||||
SuggestedFeeRecipient: feeRecpt,
|
||||
Withdrawals: w,
|
||||
ParentBeaconBlockRoot: pr[:],
|
||||
ParentBeaconBlockRoot: root[:],
|
||||
})
|
||||
}
|
||||
|
||||
@@ -665,37 +659,75 @@ type asyncPayloadAttrData struct {
|
||||
err error
|
||||
}
|
||||
|
||||
var zeroRoot [32]byte
|
||||
|
||||
// needsFill allows tests to provide filled EventData values. An ordinary event data value fired by the blockchain package will have
|
||||
// all of the checked fields empty, so the logical short circuit should hit immediately.
|
||||
func needsFill(ev payloadattribute.EventData) bool {
|
||||
return ev.HeadState == nil || ev.HeadState.IsNil() || ev.HeadState.LatestBlockHeader() == nil ||
|
||||
ev.HeadBlock == nil || ev.HeadBlock.IsNil() ||
|
||||
ev.HeadRoot == zeroRoot || len(ev.ParentBlockRoot) == 0 || len(ev.ParentBlockHash) == 0 ||
|
||||
ev.Attributer == nil || ev.Attributer.IsEmpty()
|
||||
}
|
||||
|
||||
func (s *Server) fillEventData(ctx context.Context, ev payloadattribute.EventData) (payloadattribute.EventData, error) {
|
||||
if ev.HeadBlock == nil || ev.HeadBlock.IsNil() {
|
||||
hb, err := s.HeadFetcher.HeadBlock(ctx)
|
||||
if err != nil {
|
||||
return ev, errors.Wrap(err, "Could not look up head block")
|
||||
}
|
||||
root, err := hb.Block().HashTreeRoot()
|
||||
if err != nil {
|
||||
return ev, errors.Wrap(err, "Could not compute head block root")
|
||||
}
|
||||
if ev.HeadRoot != root {
|
||||
return ev, errors.Wrap(err, "head root changed before payload attribute event handler execution")
|
||||
}
|
||||
ev.HeadBlock = hb
|
||||
payload, err := hb.Block().Body().Execution()
|
||||
if err != nil {
|
||||
return ev, errors.Wrap(err, "Could not get execution payload for head block")
|
||||
}
|
||||
ev.ParentBlockHash = payload.BlockHash()
|
||||
ev.ParentBlockNumber = payload.BlockNumber()
|
||||
var err error
|
||||
|
||||
if !needsFill(ev) {
|
||||
return ev, nil
|
||||
}
|
||||
|
||||
attr := ev.Attributer
|
||||
if attr == nil || attr.IsEmpty() {
|
||||
attr, err := s.computePayloadAttributes(ctx, ev)
|
||||
if err != nil {
|
||||
return ev, errors.Wrap(err, "Could not compute payload attributes")
|
||||
}
|
||||
ev.Attributer = attr
|
||||
ev.HeadState, err = s.HeadFetcher.HeadState(ctx)
|
||||
if err != nil {
|
||||
return ev, errors.Wrap(err, "could not get head state")
|
||||
}
|
||||
return ev, nil
|
||||
|
||||
ev.HeadBlock, err = s.HeadFetcher.HeadBlock(ctx)
|
||||
if err != nil {
|
||||
return ev, errors.Wrap(err, "could not look up head block")
|
||||
}
|
||||
ev.HeadRoot, err = ev.HeadBlock.Block().HashTreeRoot()
|
||||
if err != nil {
|
||||
return ev, errors.Wrap(err, "could not compute head block root")
|
||||
}
|
||||
pr := ev.HeadBlock.Block().ParentRoot()
|
||||
ev.ParentBlockRoot = pr[:]
|
||||
|
||||
hsr, err := ev.HeadState.LatestBlockHeader().HashTreeRoot()
|
||||
if err != nil {
|
||||
return ev, errors.Wrap(err, "could not compute latest block header root")
|
||||
}
|
||||
|
||||
pse := slots.ToEpoch(ev.ProposalSlot)
|
||||
st := ev.HeadState
|
||||
if slots.ToEpoch(st.Slot()) != pse {
|
||||
st, err = transition.ProcessSlotsUsingNextSlotCache(ctx, st, hsr[:], ev.ProposalSlot)
|
||||
if err != nil {
|
||||
return ev, errors.Wrap(err, "could not run process blocks on head state into the proposal slot epoch")
|
||||
}
|
||||
}
|
||||
ev.ProposerIndex, err = helpers.BeaconProposerIndexAtSlot(ctx, st, ev.ProposalSlot)
|
||||
if err != nil {
|
||||
return ev, errors.Wrap(err, "failed to compute proposer index")
|
||||
}
|
||||
randao, err := helpers.RandaoMix(st, pse)
|
||||
if err != nil {
|
||||
return ev, errors.Wrap(err, "could not get head state randado")
|
||||
}
|
||||
|
||||
payload, err := ev.HeadBlock.Block().Body().Execution()
|
||||
if err != nil {
|
||||
return ev, errors.Wrap(err, "could not get execution payload for head block")
|
||||
}
|
||||
ev.ParentBlockHash = payload.BlockHash()
|
||||
ev.ParentBlockNumber = payload.BlockNumber()
|
||||
|
||||
t, err := slots.ToTime(st.GenesisTime(), ev.ProposalSlot)
|
||||
if err != nil {
|
||||
return ev, errors.Wrap(err, "could not get head state slot time")
|
||||
}
|
||||
ev.Attributer, err = s.computePayloadAttributes(ctx, st, hsr, ev.ProposerIndex, uint64(t.Unix()), randao)
|
||||
return ev, err
|
||||
}
|
||||
|
||||
// This event stream is intended to be used by builders and relays.
|
||||
@@ -704,10 +736,7 @@ func (s *Server) payloadAttributesReader(ctx context.Context, ev payloadattribut
|
||||
ctx, cancel := context.WithTimeout(ctx, payloadAttributeTimeout)
|
||||
edc := make(chan asyncPayloadAttrData)
|
||||
go func() {
|
||||
d := asyncPayloadAttrData{
|
||||
version: version.String(ev.HeadState.Version()),
|
||||
}
|
||||
|
||||
d := asyncPayloadAttrData{}
|
||||
defer func() {
|
||||
edc <- d
|
||||
}()
|
||||
@@ -716,6 +745,7 @@ func (s *Server) payloadAttributesReader(ctx context.Context, ev payloadattribut
|
||||
d.err = errors.Wrap(err, "Could not fill event data")
|
||||
return
|
||||
}
|
||||
d.version = version.String(ev.HeadBlock.Version())
|
||||
attributesBytes, err := marshalAttributes(ev.Attributer)
|
||||
if err != nil {
|
||||
d.err = errors.Wrap(err, "errors marshaling payload attributes to json")
|
||||
|
||||
@@ -2,6 +2,7 @@ package events
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
@@ -24,6 +25,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
payloadattribute "github.com/prysmaticlabs/prysm/v5/consensus-types/payload-attribute"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/eth/v1"
|
||||
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
@@ -557,6 +559,110 @@ func TestStreamEvents_OperationsEvents(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestFillEventData(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
t.Run("AlreadyFilledData_ShouldShortCircuitWithoutError", func(t *testing.T) {
|
||||
st, err := util.NewBeaconStateBellatrix()
|
||||
require.NoError(t, err)
|
||||
b, err := blocks.NewSignedBeaconBlock(util.HydrateSignedBeaconBlockBellatrix(ð.SignedBeaconBlockBellatrix{}))
|
||||
require.NoError(t, err)
|
||||
attributor, err := payloadattribute.New(&enginev1.PayloadAttributes{
|
||||
Timestamp: uint64(time.Now().Unix()),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
alreadyFilled := payloadattribute.EventData{
|
||||
HeadState: st,
|
||||
HeadBlock: b,
|
||||
HeadRoot: [32]byte{1, 2, 3},
|
||||
Attributer: attributor,
|
||||
ParentBlockRoot: []byte{1, 2, 3},
|
||||
ParentBlockHash: []byte{4, 5, 6},
|
||||
}
|
||||
srv := &Server{} // No real HeadFetcher needed here since it won't be called.
|
||||
result, err := srv.fillEventData(ctx, alreadyFilled)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, alreadyFilled, result)
|
||||
})
|
||||
t.Run("Electra PartialData_ShouldFetchHeadStateAndBlock", func(t *testing.T) {
|
||||
st, err := util.NewBeaconStateElectra()
|
||||
require.NoError(t, err)
|
||||
valCount := 10
|
||||
setActiveValidators(t, st, valCount)
|
||||
inactivityScores := make([]uint64, valCount)
|
||||
for i := range inactivityScores {
|
||||
inactivityScores[i] = 10
|
||||
}
|
||||
require.NoError(t, st.SetInactivityScores(inactivityScores))
|
||||
b, err := blocks.NewSignedBeaconBlock(util.HydrateSignedBeaconBlockElectra(ð.SignedBeaconBlockElectra{}))
|
||||
require.NoError(t, err)
|
||||
attributor, err := payloadattribute.New(&enginev1.PayloadAttributes{
|
||||
Timestamp: uint64(time.Now().Unix()),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
// Create an event data object missing certain fields:
|
||||
partial := payloadattribute.EventData{
|
||||
// The presence of a nil HeadState, nil HeadBlock, zeroed HeadRoot, etc.
|
||||
// will cause fillEventData to try to fill the values.
|
||||
ProposalSlot: 42, // different epoch from current slot
|
||||
Attributer: attributor, // Must be Bellatrix or later
|
||||
}
|
||||
currentSlot := primitives.Slot(0)
|
||||
// to avoid slot processing
|
||||
require.NoError(t, st.SetSlot(currentSlot+1))
|
||||
mockChainService := &mockChain.ChainService{
|
||||
Root: make([]byte, 32),
|
||||
State: st,
|
||||
Block: b,
|
||||
Slot: ¤tSlot,
|
||||
}
|
||||
|
||||
stn := mockChain.NewEventFeedWrapper()
|
||||
opn := mockChain.NewEventFeedWrapper()
|
||||
srv := &Server{
|
||||
StateNotifier: &mockChain.SimpleNotifier{Feed: stn},
|
||||
OperationNotifier: &mockChain.SimpleNotifier{Feed: opn},
|
||||
HeadFetcher: mockChainService,
|
||||
ChainInfoFetcher: mockChainService,
|
||||
TrackedValidatorsCache: cache.NewTrackedValidatorsCache(),
|
||||
EventWriteTimeout: testEventWriteTimeout,
|
||||
}
|
||||
|
||||
filled, err := srv.fillEventData(ctx, partial)
|
||||
require.NoError(t, err, "expected successful fill of partial event data")
|
||||
|
||||
// Verify that fields have been updated from the mock data:
|
||||
require.NotNil(t, filled.HeadState, "HeadState should be assigned")
|
||||
require.NotNil(t, filled.HeadBlock, "HeadBlock should be assigned")
|
||||
require.NotEqual(t, [32]byte{}, filled.HeadRoot, "HeadRoot should no longer be zero")
|
||||
require.NotEmpty(t, filled.ParentBlockRoot, "ParentBlockRoot should be filled")
|
||||
require.NotEmpty(t, filled.ParentBlockHash, "ParentBlockHash should be filled")
|
||||
require.Equal(t, uint64(0), filled.ParentBlockNumber, "ParentBlockNumber must match mock block")
|
||||
|
||||
// Check that a valid Attributer was set:
|
||||
require.NotNil(t, filled.Attributer, "Should have a valid payload attributes object")
|
||||
require.Equal(t, false, filled.Attributer.IsEmpty(), "Attributer should not be empty after fill")
|
||||
})
|
||||
}
|
||||
|
||||
func setActiveValidators(t *testing.T, st state.BeaconState, count int) {
|
||||
balances := make([]uint64, count)
|
||||
validators := make([]*eth.Validator, 0, count)
|
||||
for i := 0; i < count; i++ {
|
||||
pubKey := make([]byte, params.BeaconConfig().BLSPubkeyLength)
|
||||
binary.LittleEndian.PutUint64(pubKey, uint64(i))
|
||||
balances[i] = uint64(i)
|
||||
validators = append(validators, ð.Validator{
|
||||
PublicKey: pubKey,
|
||||
ActivationEpoch: 0,
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
})
|
||||
}
|
||||
|
||||
require.NoError(t, st.SetValidators(validators))
|
||||
require.NoError(t, st.SetBalances(balances))
|
||||
}
|
||||
|
||||
func TestStuckReaderScenarios(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
|
||||
@@ -636,6 +636,16 @@ func (s *Server) ProduceSyncCommitteeContribution(w http.ResponseWriter, r *http
|
||||
ctx, span := trace.StartSpan(r.Context(), "validator.ProduceSyncCommitteeContribution")
|
||||
defer span.End()
|
||||
|
||||
isOptimistic, err := s.OptimisticModeFetcher.IsOptimistic(ctx)
|
||||
if err != nil {
|
||||
httputil.HandleError(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if isOptimistic {
|
||||
httputil.HandleError(w, "Beacon node is currently syncing and not serving request on that endpoint", http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
|
||||
_, index, ok := shared.UintFromQuery(w, r, "subcommittee_index", true)
|
||||
if !ok {
|
||||
return
|
||||
|
||||
@@ -1584,7 +1584,8 @@ func TestProduceSyncCommitteeContribution(t *testing.T) {
|
||||
SyncCommitteeIndices: []primitives.CommitteeIndex{0},
|
||||
},
|
||||
},
|
||||
SyncCommitteePool: syncCommitteePool,
|
||||
SyncCommitteePool: syncCommitteePool,
|
||||
OptimisticModeFetcher: &mockChain.ChainService{},
|
||||
}
|
||||
t.Run("ok", func(t *testing.T) {
|
||||
url := "http://example.com?slot=1&subcommittee_index=1&beacon_block_root=0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
|
||||
@@ -1672,7 +1673,8 @@ func TestProduceSyncCommitteeContribution(t *testing.T) {
|
||||
SyncCommitteeIndices: []primitives.CommitteeIndex{0},
|
||||
},
|
||||
},
|
||||
SyncCommitteePool: syncCommitteePool,
|
||||
SyncCommitteePool: syncCommitteePool,
|
||||
OptimisticModeFetcher: &mockChain.ChainService{},
|
||||
}
|
||||
server.ProduceSyncCommitteeContribution(writer, request)
|
||||
assert.Equal(t, http.StatusNotFound, writer.Code)
|
||||
@@ -1680,6 +1682,26 @@ func TestProduceSyncCommitteeContribution(t *testing.T) {
|
||||
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp2))
|
||||
require.ErrorContains(t, "No subcommittee messages found", errors.New(writer.Body.String()))
|
||||
})
|
||||
t.Run("Optimistic returns 503", func(t *testing.T) {
|
||||
url := "http://example.com?slot=1&subcommittee_index=1&beacon_block_root=0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
|
||||
request := httptest.NewRequest(http.MethodGet, url, nil)
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
syncCommitteePool = synccommittee.NewStore()
|
||||
server = Server{
|
||||
CoreService: &core.Service{
|
||||
HeadFetcher: &mockChain.ChainService{
|
||||
SyncCommitteeIndices: []primitives.CommitteeIndex{0},
|
||||
},
|
||||
},
|
||||
SyncCommitteePool: syncCommitteePool,
|
||||
OptimisticModeFetcher: &mockChain.ChainService{
|
||||
Optimistic: true,
|
||||
},
|
||||
}
|
||||
server.ProduceSyncCommitteeContribution(writer, request)
|
||||
assert.Equal(t, http.StatusServiceUnavailable, writer.Code)
|
||||
})
|
||||
}
|
||||
|
||||
func TestServer_RegisterValidator(t *testing.T) {
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
package sync
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/p2p/enr"
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
pubsubpb "github.com/libp2p/go-libp2p-pubsub/pb"
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"github.com/prysmaticlabs/prysm/v5/async/abool"
|
||||
@@ -20,6 +24,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/p2p/peers"
|
||||
p2ptest "github.com/prysmaticlabs/prysm/v5/beacon-chain/p2p/testing"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/startup"
|
||||
mockSync "github.com/prysmaticlabs/prysm/v5/beacon-chain/sync/initial-sync/testing"
|
||||
lruwrpr "github.com/prysmaticlabs/prysm/v5/cache/lru"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
@@ -258,6 +263,169 @@ func TestProcessPendingAtts_HasBlockSaveUnAggregatedAttElectra(t *testing.T) {
|
||||
cancel()
|
||||
}
|
||||
|
||||
func TestProcessPendingAtts_HasBlockSaveUnAggregatedAttElectra_VerifySeen(t *testing.T) {
|
||||
// Setup configuration and fork version schedule.
|
||||
params.SetupTestConfigCleanup(t)
|
||||
cfg := params.BeaconConfig()
|
||||
fvs := map[[fieldparams.VersionLength]byte]primitives.Epoch{
|
||||
bytesutil.ToBytes4(cfg.GenesisForkVersion): 1,
|
||||
bytesutil.ToBytes4(cfg.AltairForkVersion): 2,
|
||||
bytesutil.ToBytes4(cfg.BellatrixForkVersion): 3,
|
||||
bytesutil.ToBytes4(cfg.CapellaForkVersion): 4,
|
||||
bytesutil.ToBytes4(cfg.DenebForkVersion): 5,
|
||||
bytesutil.ToBytes4(cfg.FuluForkVersion): 6,
|
||||
bytesutil.ToBytes4(cfg.ElectraForkVersion): 0,
|
||||
}
|
||||
cfg.ForkVersionSchedule = fvs
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
// Initialize logging, database, and P2P components.
|
||||
hook := logTest.NewGlobal()
|
||||
db := dbtest.SetupDB(t)
|
||||
p1 := p2ptest.NewTestP2P(t)
|
||||
validators := uint64(256)
|
||||
|
||||
// Create genesis state and associated keys.
|
||||
beaconState, privKeys := util.DeterministicGenesisStateElectra(t, validators)
|
||||
require.NoError(t, beaconState.SetSlot(1))
|
||||
|
||||
// Create and save a new Beacon block.
|
||||
sb := util.NewBeaconBlockElectra()
|
||||
util.SaveBlock(t, context.Background(), db, sb)
|
||||
|
||||
// Save state with block root.
|
||||
root, err := sb.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Build a new attestation and its aggregate proof.
|
||||
att := ðpb.SingleAttestation{
|
||||
CommitteeId: 8, // choose a non 0
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 1,
|
||||
BeaconBlockRoot: root[:],
|
||||
Source: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, fieldparams.RootLength)},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: root[:]},
|
||||
CommitteeIndex: 0,
|
||||
},
|
||||
}
|
||||
aggregateAndProof := ðpb.AggregateAttestationAndProofSingle{
|
||||
Aggregate: att,
|
||||
}
|
||||
|
||||
// Retrieve the beacon committee and set the attester index.
|
||||
committee, err := helpers.BeaconCommitteeFromState(context.Background(), beaconState, att.Data.Slot, att.CommitteeId)
|
||||
assert.NoError(t, err)
|
||||
att.AttesterIndex = committee[0]
|
||||
|
||||
// Compute attester domain and signature.
|
||||
attesterDomain, err := signing.Domain(beaconState.Fork(), 0, params.BeaconConfig().DomainBeaconAttester, beaconState.GenesisValidatorsRoot())
|
||||
require.NoError(t, err)
|
||||
hashTreeRoot, err := signing.ComputeSigningRoot(att.Data, attesterDomain)
|
||||
assert.NoError(t, err)
|
||||
att.SetSignature(privKeys[committee[0]].Sign(hashTreeRoot[:]).Marshal())
|
||||
|
||||
// Set the genesis time.
|
||||
require.NoError(t, beaconState.SetGenesisTime(uint64(time.Now().Unix())))
|
||||
|
||||
// Setup the chain service mock.
|
||||
chain := &mock.ChainService{
|
||||
Genesis: time.Now(),
|
||||
State: beaconState,
|
||||
FinalizedCheckPoint: ðpb.Checkpoint{
|
||||
Root: aggregateAndProof.Aggregate.Data.BeaconBlockRoot,
|
||||
Epoch: 0,
|
||||
},
|
||||
}
|
||||
|
||||
// Setup event feed and subscription.
|
||||
done := make(chan *feed.Event, 1)
|
||||
defer close(done)
|
||||
opn := mock.NewEventFeedWrapper()
|
||||
sub := opn.Subscribe(done)
|
||||
defer sub.Unsubscribe()
|
||||
|
||||
// Create context and service configuration.
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
r := &Service{
|
||||
ctx: ctx,
|
||||
cfg: &config{
|
||||
initialSync: &mockSync.Sync{IsSyncing: false},
|
||||
p2p: p1,
|
||||
beaconDB: db,
|
||||
chain: chain,
|
||||
clock: startup.NewClock(chain.Genesis.Add(time.Duration(-1*int(params.BeaconConfig().SecondsPerSlot))*time.Second), chain.ValidatorsRoot),
|
||||
attPool: attestations.NewPool(),
|
||||
attestationNotifier: &mock.SimpleNotifier{Feed: opn},
|
||||
},
|
||||
blkRootToPendingAtts: make(map[[32]byte][]ethpb.SignedAggregateAttAndProof),
|
||||
seenUnAggregatedAttestationCache: lruwrpr.New(10),
|
||||
signatureChan: make(chan *signatureVerifier, verifierLimit),
|
||||
}
|
||||
go r.verifierRoutine()
|
||||
|
||||
// Save a new beacon state and link it with the block root.
|
||||
s, err := util.NewBeaconStateElectra()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, r.cfg.beaconDB.SaveState(context.Background(), s, root))
|
||||
|
||||
// Add the pending attestation.
|
||||
r.blkRootToPendingAtts[root] = []ethpb.SignedAggregateAttAndProof{
|
||||
ðpb.SignedAggregateAttestationAndProofSingle{Message: aggregateAndProof},
|
||||
}
|
||||
require.NoError(t, r.processPendingAtts(context.Background()))
|
||||
|
||||
// Verify that the event feed receives the expected attestation.
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for {
|
||||
select {
|
||||
case received := <-done:
|
||||
// Ensure a single attestation event was sent.
|
||||
require.Equal(t, operation.SingleAttReceived, int(received.Type))
|
||||
return
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Verify unaggregated attestations are saved correctly.
|
||||
atts, err := r.cfg.attPool.UnaggregatedAttestations()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(atts), "Did not save unaggregated att")
|
||||
assert.DeepEqual(t, att.ToAttestationElectra(committee), atts[0], "Incorrect saved att")
|
||||
assert.Equal(t, 0, len(r.cfg.attPool.AggregatedAttestations()), "Did save aggregated att")
|
||||
require.LogsContain(t, hook, "Verified and saved pending attestations to pool")
|
||||
|
||||
// Encode the attestation for pubsub and decode the message.
|
||||
buf := new(bytes.Buffer)
|
||||
_, err = p1.Encoding().EncodeGossip(buf, att)
|
||||
require.NoError(t, err)
|
||||
digest, err := r.currentForkDigest()
|
||||
require.NoError(t, err)
|
||||
topic := fmt.Sprintf("/eth2/%x/beacon_attestation_1", digest)
|
||||
m := &pubsub.Message{
|
||||
Message: &pubsubpb.Message{
|
||||
Data: buf.Bytes(),
|
||||
Topic: &topic,
|
||||
},
|
||||
}
|
||||
_, err = r.decodePubsubMessage(m)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Validate the pubsub message and ignore it as it should already been seen.
|
||||
res, err := r.validateCommitteeIndexBeaconAttestation(ctx, "", m)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, pubsub.ValidationIgnore, res)
|
||||
|
||||
// Wait for the event to complete.
|
||||
wg.Wait()
|
||||
cancel()
|
||||
}
|
||||
|
||||
func TestProcessPendingAtts_NoBroadcastWithBadSignature(t *testing.T) {
|
||||
db := dbtest.SetupDB(t)
|
||||
p1 := p2ptest.NewTestP2P(t)
|
||||
|
||||
@@ -92,11 +92,11 @@ func (s *Service) validateBlob(ctx context.Context, pid peer.ID, msg *pubsub.Mes
|
||||
return pubsub.ValidationIgnore, err
|
||||
}
|
||||
|
||||
if err := vf.ValidProposerSignature(ctx); err != nil {
|
||||
if err := vf.SidecarParentValid(s.hasBadBlock); err != nil {
|
||||
return pubsub.ValidationReject, err
|
||||
}
|
||||
|
||||
if err := vf.SidecarParentValid(s.hasBadBlock); err != nil {
|
||||
if err := vf.ValidProposerSignature(ctx); err != nil {
|
||||
return pubsub.ValidationReject, err
|
||||
}
|
||||
|
||||
|
||||
3
changelog/james-prysm_add-op-check-sync-committee.md
Normal file
3
changelog/james-prysm_add-op-check-sync-committee.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Fixed
|
||||
|
||||
- /eth/v1/validator/sync_committee_contribution should check for optimistic status and return a 503 if it's optimistic.
|
||||
3
changelog/james-prysm_fix-blobl-subnet-config.md
Normal file
3
changelog/james-prysm_fix-blobl-subnet-config.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Fixed
|
||||
|
||||
- fixed /eth/v1/config/spec displays BLOB_SIDECAR_SUBNET_COUNT,BLOB_SIDECAR_SUBNET_COUNT_ELECTRA
|
||||
4
changelog/james-prysm_fix-builder-e2e.md
Normal file
4
changelog/james-prysm_fix-builder-e2e.md
Normal file
@@ -0,0 +1,4 @@
|
||||
### Fixed
|
||||
|
||||
- Fixes printing superfluous response.WriteHeader call from error in builder.
|
||||
- Fixes e2e run with builder having wrong gaslimit header due to not being set on eth1 nodes.
|
||||
3
changelog/james-prysm_update-default-gas-limit.md
Normal file
3
changelog/james-prysm_update-default-gas-limit.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Changed
|
||||
|
||||
- Updated default gas limit from 30M to 36M
|
||||
3
changelog/james-prysm_verify-seen-att-test.md
Normal file
3
changelog/james-prysm_verify-seen-att-test.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Ignored
|
||||
|
||||
- add unit test for verify already seen attestation.
|
||||
2
changelog/kasey_delete-block-idx.md
Normal file
2
changelog/kasey_delete-block-idx.md
Normal file
@@ -0,0 +1,2 @@
|
||||
### Fixed
|
||||
- Ensure that deleting a block from the database clears its entry in the slot->root db index.
|
||||
2
changelog/kasey_event-slot-fix.md
Normal file
2
changelog/kasey_event-slot-fix.md
Normal file
@@ -0,0 +1,2 @@
|
||||
### Fixed
|
||||
- Fixed a bug in the event stream handler when processing payload attribute events where the timestamp and slot of the event would be based on the head rather than the current slot.
|
||||
3
changelog/potuz_last_validated.md
Normal file
3
changelog/potuz_last_validated.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Ignored
|
||||
|
||||
- When starting a node, check that the last validated checkpoint has zero as root and return the genesis block root
|
||||
3
changelog/potuz_sync_from_head.md
Normal file
3
changelog/potuz_sync_from_head.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Added
|
||||
|
||||
- Added a feature flag to sync from an arbitrary beacon block root at startup.
|
||||
3
changelog/pvl_bls-ctx.md
Normal file
3
changelog/pvl_bls-ctx.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Fixed
|
||||
|
||||
- Broadcasting BLS to execution changes should not use the request context in a go routine. Use context.Background() for the broadcasting go routine.
|
||||
11
changelog/pvl_go1.24.md
Normal file
11
changelog/pvl_go1.24.md
Normal file
@@ -0,0 +1,11 @@
|
||||
### Changed
|
||||
|
||||
- Updated go to go1.24.0.
|
||||
- Updated gosec to v2.22.1 and golangci to v1.64.5.
|
||||
- Updated github.com/trailofbits/go-mutexasserts.
|
||||
- Updated rules_go to cf3c3af34bd869b864f5f2b98e2f41c2b220d6c9 to support go1.24.0.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed use of deprecated rand.Seed.
|
||||
- Fixed build issue with SszGen where the go binary was not present in the $PATH.
|
||||
3
changelog/radek_electra-packing-fix.md
Normal file
3
changelog/radek_electra-packing-fix.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Fixed
|
||||
|
||||
- Decompose Electra block attestations to prevent redundant packing.
|
||||
3
changelog/radek_ignore-bit-error.md
Normal file
3
changelog/radek_ignore-bit-error.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Changed
|
||||
|
||||
- Ignore errors from `hasSeenBit` and don't pack unaggregated attestations.
|
||||
3
changelog/radek_minor-attestation-tweaks.md
Normal file
3
changelog/radek_minor-attestation-tweaks.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Fixed
|
||||
|
||||
- Handle unaggregated attestations when decomposing Electra block attestations.
|
||||
3
changelog/syjn99_cli-peer-address-format.md
Normal file
3
changelog/syjn99_cli-peer-address-format.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Added
|
||||
|
||||
- Add acceptable address types for static peers
|
||||
3
changelog/tt_validate_block.md
Normal file
3
changelog/tt_validate_block.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Changed
|
||||
|
||||
- Validate blob sidecar re-order signature and bad parent block.
|
||||
15
cmd/flags.go
15
cmd/flags.go
@@ -93,15 +93,20 @@ var (
|
||||
Name: "no-discovery",
|
||||
Usage: "Enable only local network p2p and do not connect to cloud bootstrap nodes",
|
||||
}
|
||||
// StaticPeers specifies a set of peers to connect to explicitly.
|
||||
// StaticPeers specifies a set of peers to connect to explicitly, accepting following format of addresses:
|
||||
// enode, multiaddr, enr.
|
||||
StaticPeers = &cli.StringSliceFlag{
|
||||
Name: "peer",
|
||||
Usage: "Connect with this peer, this flag may be used multiple times. This peer is recognized as a trusted peer.",
|
||||
Name: "peer",
|
||||
Usage: "Connect with this peer, this flag may be used multiple times. " +
|
||||
"This peer is recognized as a trusted peer." +
|
||||
"Accepts enode, multiaddr, and enr formats.",
|
||||
}
|
||||
// BootstrapNode tells the beacon node which bootstrap node to connect to
|
||||
BootstrapNode = &cli.StringSliceFlag{
|
||||
Name: "bootstrap-node",
|
||||
Usage: "The address of bootstrap node. Beacon node will connect for peer discovery via DHT. Multiple nodes can be passed by using the flag multiple times but not comma-separated. You can also pass YAML files containing multiple nodes.",
|
||||
Name: "bootstrap-node",
|
||||
Usage: "The enr/enode address of bootstrap node. Beacon node will connect for peer discovery via DHT. " +
|
||||
"Multiple nodes can be passed by using the flag multiple times but not comma-separated. " +
|
||||
"You can also pass YAML files containing multiple nodes.",
|
||||
Value: cli.NewStringSlice(params.BeaconNetworkConfig().BootstrapNodes...),
|
||||
}
|
||||
// RelayNode tells the beacon node which relay node to connect to.
|
||||
|
||||
@@ -86,6 +86,9 @@ type Flags struct {
|
||||
|
||||
// AggregateIntervals specifies the time durations at which we aggregate attestations preparing for forkchoice.
|
||||
AggregateIntervals [3]time.Duration
|
||||
|
||||
// Feature related flags (alignment forced in the end)
|
||||
ForceHead string // ForceHead forces the head block to be a specific block root, the last head block, or the last finalized block.
|
||||
}
|
||||
|
||||
var featureConfig *Flags
|
||||
@@ -268,6 +271,10 @@ func ConfigureBeaconChain(ctx *cli.Context) error {
|
||||
logEnabled(enableExperimentalAttestationPool)
|
||||
cfg.EnableExperimentalAttestationPool = true
|
||||
}
|
||||
if ctx.IsSet(forceHeadFlag.Name) {
|
||||
logEnabled(forceHeadFlag)
|
||||
cfg.ForceHead = ctx.String(forceHeadFlag.Name)
|
||||
}
|
||||
|
||||
cfg.AggregateIntervals = [3]time.Duration{aggregateFirstInterval.Value, aggregateSecondInterval.Value, aggregateThirdInterval.Value}
|
||||
Init(cfg)
|
||||
|
||||
@@ -174,6 +174,12 @@ var (
|
||||
Name: "enable-experimental-attestation-pool",
|
||||
Usage: "Enables an experimental attestation pool design.",
|
||||
}
|
||||
// forceHeadFlag is a flag to force the head of the beacon chain to a specific block.
|
||||
forceHeadFlag = &cli.StringFlag{
|
||||
Name: "sync-from",
|
||||
Usage: "Forces the head of the beacon chain to a specific block root. Values can be 'head' or a block root." +
|
||||
" The block root has to be known to the beacon node and correspond to a block newer than the current finalized checkpoint.",
|
||||
}
|
||||
)
|
||||
|
||||
// devModeFlags holds list of flags that are set when development mode is on.
|
||||
@@ -230,6 +236,7 @@ var BeaconChainFlags = combinedFlags([]cli.Flag{
|
||||
DisableCommitteeAwarePacking,
|
||||
EnableDiscoveryReboot,
|
||||
enableExperimentalAttestationPool,
|
||||
forceHeadFlag,
|
||||
}, deprecatedBeaconFlags, deprecatedFlags, upcomingDeprecation)
|
||||
|
||||
func combinedFlags(flags ...[]cli.Flag) []cli.Flag {
|
||||
|
||||
@@ -235,8 +235,8 @@ type BeaconChainConfig struct {
|
||||
ExecutionEngineTimeoutValue uint64 // ExecutionEngineTimeoutValue defines the seconds to wait before timing out engine endpoints with execution payload execution semantics (newPayload, forkchoiceUpdated).
|
||||
|
||||
// Subnet value
|
||||
BlobsidecarSubnetCount uint64 `yaml:"BLOB_SIDECAR_SUBNET_COUNT"` // BlobsidecarSubnetCount is the number of blobsidecar subnets used in the gossipsub protocol.
|
||||
BlobsidecarSubnetCountElectra uint64 `yaml:"BLOB_SIDECAR_SUBNET_COUNT_ELECTRA"` // BlobsidecarSubnetCountElectra is the number of blobsidecar subnets used in the gossipsub protocol post Electra hard fork.
|
||||
BlobsidecarSubnetCount uint64 `yaml:"BLOB_SIDECAR_SUBNET_COUNT" spec:"true"` // BlobsidecarSubnetCount is the number of blobsidecar subnets used in the gossipsub protocol.
|
||||
BlobsidecarSubnetCountElectra uint64 `yaml:"BLOB_SIDECAR_SUBNET_COUNT_ELECTRA" spec:"true"` // BlobsidecarSubnetCountElectra is the number of blobsidecar subnets used in the gossipsub protocol post Electra hard fork.
|
||||
|
||||
// Values introduced in Deneb hard fork
|
||||
MaxPerEpochActivationChurnLimit uint64 `yaml:"MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT" spec:"true"` // MaxPerEpochActivationChurnLimit is the maximum amount of churn allotted for validator activation.
|
||||
|
||||
@@ -267,7 +267,7 @@ var mainnetBeaconConfig = &BeaconChainConfig{
|
||||
BytesPerLogsBloom: 256,
|
||||
MaxExtraDataBytes: 32,
|
||||
EthBurnAddressHex: "0x0000000000000000000000000000000000000000",
|
||||
DefaultBuilderGasLimit: uint64(30000000),
|
||||
DefaultBuilderGasLimit: uint64(36000000),
|
||||
|
||||
// Mevboost circuit breaker
|
||||
MaxBuilderConsecutiveMissedSlots: 3,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"fee_recipient": "0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3",
|
||||
"builder": {
|
||||
"enabled": true,
|
||||
"gas_limit": "30000000"
|
||||
"gas_limit": "36000000"
|
||||
}
|
||||
},
|
||||
"0xb057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7b": {
|
||||
|
||||
@@ -9,4 +9,4 @@ default_config:
|
||||
fee_recipient: '0x6e35733c5af9B61374A128e6F85f553aF09ff89A'
|
||||
builder:
|
||||
enabled: false
|
||||
gas_limit: '30000000'
|
||||
gas_limit: '36000000'
|
||||
@@ -146,7 +146,7 @@ func EncryptKey(key *Key, password string, scryptN, scryptP int) ([]byte, error)
|
||||
return nil, errors.New("reading from crypto/rand failed: " + err.Error())
|
||||
}
|
||||
|
||||
cipherText, err := aesCTRXOR(encryptKey, keyBytes, iv)
|
||||
cipherText, err := aesCTRXOR(encryptKey, keyBytes, iv) // #nosec G407
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
40
deps.bzl
40
deps.bzl
@@ -37,8 +37,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "co_honnef_go_tools",
|
||||
importpath = "honnef.co/go/tools",
|
||||
sum = "h1:4bH5o3b5ZULQ4UrBmP+63W9r7qIkqJClEA9ko5YKx+I=",
|
||||
version = "v0.5.1",
|
||||
sum = "h1:TAODvD3knlq75WCp2nyGJtT4LeRV/o7NN9nYPeVJXf8=",
|
||||
version = "v0.6.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_aclements_go_moremath",
|
||||
@@ -3363,8 +3363,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "com_github_trailofbits_go_mutexasserts",
|
||||
importpath = "github.com/trailofbits/go-mutexasserts",
|
||||
sum = "h1:+LynomhWB+14Plp/bOONEAZCtvCZk4leRbTvNzNVkL0=",
|
||||
version = "v0.0.0-20230328101604-8cdbc5f3d279",
|
||||
sum = "h1:EBoYk5zHOfuHDBqLFx4eSPRVcbnW+L3aFJzoCi8zRnk=",
|
||||
version = "v0.0.0-20250212181730-4c2b8e9e784b",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_tyler_smith_go_bip39",
|
||||
@@ -4739,8 +4739,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "org_golang_x_crypto",
|
||||
importpath = "golang.org/x/crypto",
|
||||
sum = "h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=",
|
||||
version = "v0.32.0",
|
||||
sum = "h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=",
|
||||
version = "v0.33.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "org_golang_x_exp",
|
||||
@@ -4775,14 +4775,14 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "org_golang_x_mod",
|
||||
importpath = "golang.org/x/mod",
|
||||
sum = "h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=",
|
||||
version = "v0.22.0",
|
||||
sum = "h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=",
|
||||
version = "v0.23.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "org_golang_x_net",
|
||||
importpath = "golang.org/x/net",
|
||||
sum = "h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=",
|
||||
version = "v0.34.0",
|
||||
sum = "h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=",
|
||||
version = "v0.35.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "org_golang_x_oauth2",
|
||||
@@ -4799,14 +4799,14 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "org_golang_x_sync",
|
||||
importpath = "golang.org/x/sync",
|
||||
sum = "h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=",
|
||||
version = "v0.10.0",
|
||||
sum = "h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=",
|
||||
version = "v0.11.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "org_golang_x_sys",
|
||||
importpath = "golang.org/x/sys",
|
||||
sum = "h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=",
|
||||
version = "v0.29.0",
|
||||
sum = "h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=",
|
||||
version = "v0.30.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "org_golang_x_telemetry",
|
||||
@@ -4817,14 +4817,14 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "org_golang_x_term",
|
||||
importpath = "golang.org/x/term",
|
||||
sum = "h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=",
|
||||
version = "v0.28.0",
|
||||
sum = "h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=",
|
||||
version = "v0.29.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "org_golang_x_text",
|
||||
importpath = "golang.org/x/text",
|
||||
sum = "h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=",
|
||||
version = "v0.21.0",
|
||||
sum = "h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=",
|
||||
version = "v0.22.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "org_golang_x_time",
|
||||
@@ -4835,8 +4835,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "org_golang_x_tools",
|
||||
importpath = "golang.org/x/tools",
|
||||
sum = "h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE=",
|
||||
version = "v0.29.0",
|
||||
sum = "h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=",
|
||||
version = "v0.30.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "org_golang_x_xerrors",
|
||||
|
||||
@@ -22,12 +22,15 @@ func IsHex(b []byte) bool {
|
||||
// DecodeHexWithLength takes a string and a length in bytes,
|
||||
// and validates whether the string is a hex and has the correct length.
|
||||
func DecodeHexWithLength(s string, length int) ([]byte, error) {
|
||||
if len(s) > 2*length+2 {
|
||||
return nil, fmt.Errorf("%s is greather than length %d bytes", s, length)
|
||||
}
|
||||
bytes, err := hexutil.Decode(s)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, fmt.Sprintf("%s is not a valid hex", s))
|
||||
}
|
||||
if len(bytes) != length {
|
||||
return nil, fmt.Errorf("%s is not length %d bytes", s, length)
|
||||
return nil, fmt.Errorf("length of %s is not %d bytes", s, length)
|
||||
}
|
||||
return bytes, nil
|
||||
}
|
||||
|
||||
22
go.mod
22
go.mod
@@ -1,6 +1,6 @@
|
||||
module github.com/prysmaticlabs/prysm/v5
|
||||
|
||||
go 1.23.5
|
||||
go 1.24.0
|
||||
|
||||
require (
|
||||
github.com/MariusVanDerWijden/FuzzyVM v0.0.0-20240516070431-7828990cad7d
|
||||
@@ -71,7 +71,7 @@ require (
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/supranational/blst v0.3.14
|
||||
github.com/thomaso-mirodin/intmath v0.0.0-20160323211736-5dc6d854e46e
|
||||
github.com/trailofbits/go-mutexasserts v0.0.0-20230328101604-8cdbc5f3d279
|
||||
github.com/trailofbits/go-mutexasserts v0.0.0-20250212181730-4c2b8e9e784b
|
||||
github.com/tyler-smith/go-bip39 v1.1.0
|
||||
github.com/urfave/cli/v2 v2.27.1
|
||||
github.com/uudashr/gocognit v1.0.5
|
||||
@@ -87,17 +87,17 @@ require (
|
||||
go.opentelemetry.io/otel/trace v1.34.0
|
||||
go.uber.org/automaxprocs v1.5.2
|
||||
go.uber.org/mock v0.4.0
|
||||
golang.org/x/crypto v0.32.0
|
||||
golang.org/x/crypto v0.33.0
|
||||
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa
|
||||
golang.org/x/sync v0.10.0
|
||||
golang.org/x/tools v0.29.0
|
||||
golang.org/x/sync v0.11.0
|
||||
golang.org/x/tools v0.30.0
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1
|
||||
google.golang.org/grpc v1.69.4
|
||||
google.golang.org/protobuf v1.36.3
|
||||
gopkg.in/d4l3k/messagediff.v1 v1.2.1
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
honnef.co/go/tools v0.5.1
|
||||
honnef.co/go/tools v0.6.0
|
||||
k8s.io/apimachinery v0.30.4
|
||||
k8s.io/client-go v0.30.4
|
||||
)
|
||||
@@ -259,11 +259,11 @@ require (
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/exp/typeparams v0.0.0-20231108232855-2478ac86f678 // indirect
|
||||
golang.org/x/mod v0.22.0 // indirect
|
||||
golang.org/x/net v0.34.0 // indirect
|
||||
golang.org/x/mod v0.23.0 // indirect
|
||||
golang.org/x/net v0.35.0 // indirect
|
||||
golang.org/x/oauth2 v0.24.0 // indirect
|
||||
golang.org/x/term v0.28.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
golang.org/x/term v0.29.0 // indirect
|
||||
golang.org/x/text v0.22.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
@@ -284,7 +284,7 @@ require (
|
||||
github.com/go-playground/validator/v10 v10.13.0
|
||||
github.com/peterh/liner v1.2.0 // indirect
|
||||
github.com/prysmaticlabs/gohashtree v0.0.4-beta.0.20240624100937-73632381301b
|
||||
golang.org/x/sys v0.29.0 // indirect
|
||||
golang.org/x/sys v0.30.0 // indirect
|
||||
k8s.io/klog/v2 v2.120.1 // indirect
|
||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
|
||||
)
|
||||
|
||||
40
go.sum
40
go.sum
@@ -1037,8 +1037,8 @@ github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5I
|
||||
github.com/tklauser/numcpus v0.7.0 h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr4=
|
||||
github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDguyOZRUzAY=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/trailofbits/go-mutexasserts v0.0.0-20230328101604-8cdbc5f3d279 h1:+LynomhWB+14Plp/bOONEAZCtvCZk4leRbTvNzNVkL0=
|
||||
github.com/trailofbits/go-mutexasserts v0.0.0-20230328101604-8cdbc5f3d279/go.mod h1:GA3+Mq3kt3tYAfM0WZCu7ofy+GW9PuGysHfhr+6JX7s=
|
||||
github.com/trailofbits/go-mutexasserts v0.0.0-20250212181730-4c2b8e9e784b h1:EBoYk5zHOfuHDBqLFx4eSPRVcbnW+L3aFJzoCi8zRnk=
|
||||
github.com/trailofbits/go-mutexasserts v0.0.0-20250212181730-4c2b8e9e784b/go.mod h1:4R6Qam+w871wOlyRq59zRLjhb5x9/De/wgPeaCTaCwI=
|
||||
github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
|
||||
github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
|
||||
github.com/umbracle/gohashtree v0.0.2-alpha.0.20230207094856-5b775a815c10 h1:CQh33pStIp/E30b7TxDlXfM0145bn2e8boI30IxAhTg=
|
||||
@@ -1172,8 +1172,8 @@ golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0
|
||||
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
|
||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
|
||||
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -1216,8 +1216,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
|
||||
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
|
||||
golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -1274,8 +1274,8 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
||||
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
||||
golang.org/x/oauth2 v0.0.0-20170912212905-13449ad91cb2/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
@@ -1305,8 +1305,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -1395,8 +1395,8 @@ golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@@ -1405,8 +1405,8 @@ golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
|
||||
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
||||
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
|
||||
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
||||
golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
|
||||
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -1421,8 +1421,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
golang.org/x/time v0.0.0-20170424234030-8be79e1e0910/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -1495,8 +1495,8 @@ golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE=
|
||||
golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588=
|
||||
golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
|
||||
golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -1672,8 +1672,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.5.1 h1:4bH5o3b5ZULQ4UrBmP+63W9r7qIkqJClEA9ko5YKx+I=
|
||||
honnef.co/go/tools v0.5.1/go.mod h1:e9irvo83WDG9/irijV44wr3tbhcFeRnfpVlRqVwpzMs=
|
||||
honnef.co/go/tools v0.6.0 h1:TAODvD3knlq75WCp2nyGJtT4LeRV/o7NN9nYPeVJXf8=
|
||||
honnef.co/go/tools v0.6.0/go.mod h1:3puzxxljPCe8RGJX7BIy1plGbxEOZni5mR2aXe3/uk4=
|
||||
k8s.io/api v0.30.4 h1:XASIELmW8w8q0i1Y4124LqPoWMycLjyQti/fdYHYjCs=
|
||||
k8s.io/api v0.30.4/go.mod h1:ZqniWRKu7WIeLijbbzetF4U9qZ03cg5IRwl8YVs8mX0=
|
||||
k8s.io/apimachinery v0.30.4 h1:5QHQI2tInzr8LsT4kU/2+fSeibH1eIHswNx480cqIoY=
|
||||
|
||||
@@ -46,11 +46,11 @@ func Bitlists64WithSingleBitSet(n, length uint64) []*bitfield.Bitlist64 {
|
||||
func BitlistsWithMultipleBitSet(t testing.TB, n, length, count uint64) []bitfield.Bitlist {
|
||||
seed := time.Now().UnixNano()
|
||||
t.Logf("bitlistsWithMultipleBitSet random seed: %v", seed)
|
||||
rand.Seed(seed)
|
||||
r := rand.New(rand.NewSource(seed)) // #nosec G404
|
||||
lists := make([]bitfield.Bitlist, n)
|
||||
for i := uint64(0); i < n; i++ {
|
||||
b := bitfield.NewBitlist(length)
|
||||
keys := rand.Perm(int(length)) // lint:ignore uintcast -- This is safe in test code.
|
||||
keys := r.Perm(int(length)) // lint:ignore uintcast -- This is safe in test code.
|
||||
for _, key := range keys[:count] {
|
||||
b.SetBitAt(uint64(key), true)
|
||||
}
|
||||
@@ -63,11 +63,11 @@ func BitlistsWithMultipleBitSet(t testing.TB, n, length, count uint64) []bitfiel
|
||||
func Bitlists64WithMultipleBitSet(t testing.TB, n, length, count uint64) []*bitfield.Bitlist64 {
|
||||
seed := time.Now().UnixNano()
|
||||
t.Logf("Bitlists64WithMultipleBitSet random seed: %v", seed)
|
||||
rand.Seed(seed)
|
||||
r := rand.New(rand.NewSource(seed)) // #nosec G404
|
||||
lists := make([]*bitfield.Bitlist64, n)
|
||||
for i := uint64(0); i < n; i++ {
|
||||
b := bitfield.NewBitlist64(length)
|
||||
keys := rand.Perm(int(length)) // lint:ignore uintcast -- This is safe in test code.
|
||||
keys := r.Perm(int(length)) // lint:ignore uintcast -- This is safe in test code.
|
||||
for _, key := range keys[:count] {
|
||||
b.SetBitAt(uint64(key), true)
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"runtime/debug"
|
||||
"slices"
|
||||
"sort"
|
||||
|
||||
@@ -100,6 +101,10 @@ func AttestingIndices(att ethpb.Att, committees ...[]primitives.ValidatorIndex)
|
||||
for _, c := range committees {
|
||||
committeesLen += len(c)
|
||||
}
|
||||
if aggBits.Len() == 0 {
|
||||
fmt.Printf("committee_bits: %v, aggregation_bits: %v, slot: %d", att.CommitteeBitsVal(), att.GetAggregationBits(), att.GetData().Slot)
|
||||
debug.PrintStack()
|
||||
}
|
||||
if aggBits.Len() != uint64(committeesLen) {
|
||||
return nil, fmt.Errorf("bitfield length %d is not equal to committee length %d", aggBits.Len(), committeesLen)
|
||||
}
|
||||
|
||||
@@ -146,6 +146,7 @@ func (m *Miner) initAttempt(ctx context.Context, attempt int) (*os.File, error)
|
||||
fmt.Sprintf("--unlock=%s", EthAddress),
|
||||
"--allow-insecure-unlock",
|
||||
"--syncmode=full",
|
||||
fmt.Sprintf("--miner.gaslimit=%d", params.BeaconConfig().DefaultBuilderGasLimit),
|
||||
fmt.Sprintf("--txpool.locals=%s", EthAddress),
|
||||
fmt.Sprintf("--password=%s", pwFile),
|
||||
}
|
||||
|
||||
@@ -110,6 +110,7 @@ func (node *Node) Start(ctx context.Context) error {
|
||||
"--ipcdisable",
|
||||
"--verbosity=4",
|
||||
"--syncmode=full",
|
||||
fmt.Sprintf("--miner.gaslimit=%d", params.BeaconConfig().DefaultBuilderGasLimit),
|
||||
fmt.Sprintf("--txpool.locals=%s", EthAddress),
|
||||
}
|
||||
|
||||
|
||||
@@ -399,7 +399,7 @@ func (p *Builder) handleHeaderRequest(w http.ResponseWriter, req *http.Request)
|
||||
Message: bid,
|
||||
},
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
err = json.NewEncoder(w).Encode(hdrResp)
|
||||
if err != nil {
|
||||
p.cfg.logger.WithError(err).Error("Could not encode response")
|
||||
@@ -408,7 +408,6 @@ func (p *Builder) handleHeaderRequest(w http.ResponseWriter, req *http.Request)
|
||||
}
|
||||
p.currVersion = version.Bellatrix
|
||||
p.currPayload = wObj
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
func (p *Builder) handleHeaderRequestCapella(w http.ResponseWriter) {
|
||||
@@ -477,7 +476,7 @@ func (p *Builder) handleHeaderRequestCapella(w http.ResponseWriter) {
|
||||
Message: bid,
|
||||
},
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
err = json.NewEncoder(w).Encode(hdrResp)
|
||||
if err != nil {
|
||||
p.cfg.logger.WithError(err).Error("Could not encode response")
|
||||
@@ -486,7 +485,6 @@ func (p *Builder) handleHeaderRequestCapella(w http.ResponseWriter) {
|
||||
}
|
||||
p.currVersion = version.Capella
|
||||
p.currPayload = wObj
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
func (p *Builder) handleHeaderRequestDeneb(w http.ResponseWriter) {
|
||||
@@ -563,7 +561,7 @@ func (p *Builder) handleHeaderRequestDeneb(w http.ResponseWriter) {
|
||||
Message: bid,
|
||||
},
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
err = json.NewEncoder(w).Encode(hdrResp)
|
||||
if err != nil {
|
||||
p.cfg.logger.WithError(err).Error("Could not encode response")
|
||||
@@ -573,7 +571,6 @@ func (p *Builder) handleHeaderRequestDeneb(w http.ResponseWriter) {
|
||||
p.currVersion = version.Deneb
|
||||
p.currPayload = wObj
|
||||
p.blobBundle = b.BlobsBundle
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
func (p *Builder) handleHeaderRequestElectra(w http.ResponseWriter) {
|
||||
@@ -697,7 +694,7 @@ func (p *Builder) handleHeaderRequestElectra(w http.ResponseWriter) {
|
||||
Message: bid,
|
||||
},
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
err = json.NewEncoder(w).Encode(hdrResp)
|
||||
if err != nil {
|
||||
p.cfg.logger.WithError(err).Error("Could not encode response")
|
||||
@@ -707,7 +704,6 @@ func (p *Builder) handleHeaderRequestElectra(w http.ResponseWriter) {
|
||||
p.currVersion = version.Electra
|
||||
p.currPayload = wObj
|
||||
p.blobBundle = b.BlobsBundle
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
func (p *Builder) handleBlindedBlock(w http.ResponseWriter, req *http.Request) {
|
||||
@@ -732,13 +728,13 @@ func (p *Builder) handleBlindedBlock(w http.ResponseWriter, req *http.Request) {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
err = json.NewEncoder(w).Encode(resp)
|
||||
if err != nil {
|
||||
p.cfg.logger.WithError(err).Error("Could not encode full payload response")
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
var errInvalidTypeConversion = errors.New("unable to translate between api and foreign type")
|
||||
|
||||
8
third_party/io_bazel_rules_go_test.patch
vendored
8
third_party/io_bazel_rules_go_test.patch
vendored
@@ -1,8 +1,8 @@
|
||||
diff --git a/go/private/rules/test.bzl b/go/private/rules/test.bzl
|
||||
index 413a19da..b289f52f 100644
|
||||
index 066c6892..5275f541 100644
|
||||
--- a/go/private/rules/test.bzl
|
||||
+++ b/go/private/rules/test.bzl
|
||||
@@ -189,7 +189,7 @@ def _go_test_impl(ctx):
|
||||
@@ -224,7 +224,7 @@ def _go_test_impl(ctx):
|
||||
run_environment_info,
|
||||
]
|
||||
|
||||
@@ -11,12 +11,12 @@ index 413a19da..b289f52f 100644
|
||||
"implementation": _go_test_impl,
|
||||
"attrs": {
|
||||
"data": attr.label_list(
|
||||
@@ -471,7 +471,7 @@ _go_test_kwargs = {
|
||||
@@ -508,7 +508,7 @@ _go_test_kwargs = {
|
||||
""",
|
||||
}
|
||||
|
||||
-go_test = rule(**_go_test_kwargs)
|
||||
+go_test = rule(**go_test_kwargs)
|
||||
|
||||
def _recompile_external_deps(go, external_source, internal_archive, library_labels):
|
||||
def _recompile_external_deps(go, external_go_info, internal_archive, library_labels):
|
||||
"""Recompiles some archives in order to split internal and external tests.
|
||||
|
||||
@@ -63,12 +63,30 @@ def _ssz_go_proto_library_impl(ctx):
|
||||
if len(ctx.attr.exclude_objs) > 0:
|
||||
args.append("--exclude-objs=%s" % ",".join(ctx.attr.exclude_objs))
|
||||
|
||||
ctx.actions.run(
|
||||
executable = ctx.executable.sszgen,
|
||||
progress_message = "Generating ssz marshal and unmarshal functions",
|
||||
inputs = input_files,
|
||||
arguments = args,
|
||||
# golang.org/x/tools requires the go binary to be available in the PATH.
|
||||
# Follows the same pattern as https://github.com/bazel-contrib/rules_go/pull/4173
|
||||
sdk = ctx.toolchains["@io_bazel_rules_go//go:toolchain"].sdk
|
||||
goroot = sdk.root_file.dirname
|
||||
env = {
|
||||
"PATH": "PATH={goroot}/bin:$PATH".format(goroot = goroot),
|
||||
"GOROOT": goroot,
|
||||
}
|
||||
ctx.actions.run_shell(
|
||||
outputs = [output],
|
||||
command = """
|
||||
export GOROOT=$(pwd)/{goroot} &&
|
||||
export PATH=$GOROOT/bin:$PATH &&
|
||||
{cmd} {args}""".format(
|
||||
goroot = goroot,
|
||||
cmd = ctx.executable.sszgen.path,
|
||||
args = " ".join(args),
|
||||
),
|
||||
tools = [
|
||||
ctx.executable.sszgen,
|
||||
sdk.go,
|
||||
],
|
||||
mnemonic = "SszGen",
|
||||
inputs = input_files,
|
||||
)
|
||||
|
||||
ssz_gen_marshal = rule(
|
||||
@@ -86,6 +104,7 @@ ssz_gen_marshal = rule(
|
||||
"includes": attr.label_list(providers = [GoLibrary]),
|
||||
"out": attr.output(),
|
||||
},
|
||||
toolchains = ["@io_bazel_rules_go//go:toolchain"],
|
||||
)
|
||||
|
||||
SSZ_DEPS = ["@com_github_prysmaticlabs_fastssz//:go_default_library"]
|
||||
|
||||
Reference in New Issue
Block a user