Compare commits

..

1 Commits

Author SHA1 Message Date
Manu NALEPA
f7b532e958 Add automatic heap dump monitoring based on memory threshold 2026-01-12 13:24:09 +01:00
98 changed files with 1284 additions and 3480 deletions

View File

@@ -72,7 +72,7 @@ Do NOT add new `go_repository` to the WORKSPACE file. All dependencies should li
To enable conditional compilation and custom configuration for tests (where compiled code has more
debug info, while not being completely optimized), we rely on Go's build tags/constraints mechanism
(see official docs on [build constraints](https://pkg.go.dev/go/build#hdr-Build_Constraints)).
(see official docs on [build constraints](https://golang.org/pkg/go/build/#hdr-Build_Constraints)).
Therefore, whenever using `go test`, do not forget to pass in extra build tag, eg:
```bash

View File

@@ -9,7 +9,7 @@ This README details how to setup Prysm for interop testing for usage with other
## Installation & Setup
1. Install [Bazel](https://bazel.build/install) **(Recommended)**
1. Install [Bazel](https://docs.bazel.build/versions/master/install.html) **(Recommended)**
2. `git clone https://github.com/OffchainLabs/prysm && cd prysm`
3. `bazel build //cmd/...`

View File

@@ -15,7 +15,7 @@
## 📖 Overview
This is the core repository for Prysm, a [Golang](https://go.dev/) implementation of the [Ethereum Consensus](https://ethereum.org/en/developers/docs/consensus-mechanisms/#proof-of-stake) [specification](https://github.com/ethereum/consensus-specs), developed by [Offchain Labs](https://www.offchainlabs.com).
This is the core repository for Prysm, a [Golang](https://golang.org/) implementation of the [Ethereum Consensus](https://ethereum.org/en/developers/docs/consensus-mechanisms/#proof-of-stake) [specification](https://github.com/ethereum/consensus-specs), developed by [Offchain Labs](https://www.offchainlabs.com).
See the [Changelog](https://github.com/OffchainLabs/prysm/releases) for details of the latest releases and upcoming breaking changes.
@@ -23,7 +23,7 @@ See the [Changelog](https://github.com/OffchainLabs/prysm/releases) for details
## 🚀 Getting Started
A detailed set of installation and usage instructions as well as breakdowns of each individual component are available in the **[official documentation portal](https://prysm.offchainlabs.com/docs/)**.
A detailed set of installation and usage instructions as well as breakdowns of each individual component are available in the **[official documentation portal](https://docs.prylabs.network)**.
💬 **Need help?** Join our **[Discord Community](https://discord.gg/prysm)** for support.
@@ -51,7 +51,7 @@ Prysm maintains two permanent branches:
### 🛠 Contribution Guide
Want to get involved? Check out our **[Contribution Guide](https://prysm.offchainlabs.com/docs/contribute/contribution-guidelines/)** to learn more!
Want to get involved? Check out our **[Contribution Guide](https://docs.prylabs.network/docs/contribute/contribution-guidelines/)** to learn more!
---

View File

@@ -273,16 +273,16 @@ filegroup(
url = "https://github.com/ethereum/EIPs/archive/5480440fe51742ed23342b68cf106cefd427e39d.tar.gz",
)
consensus_spec_version = "v1.7.0-alpha.1"
consensus_spec_version = "v1.7.0-alpha.0"
load("@prysm//tools:download_spectests.bzl", "consensus_spec_tests")
consensus_spec_tests(
name = "consensus_spec_tests",
flavors = {
"general": "sha256-j5R3jA7Oo4OSDMTvpMuD+8RomaCByeFSwtfkq6fL0Zg=",
"minimal": "sha256-tdTqByoyswOS4r6OxFmo70y2BP7w1TgEok+gf4cbxB0=",
"mainnet": "sha256-5gB4dt6SnSDKzdBc06VedId3NkgvSYyv9n9FRxWKwYI=",
"general": "sha256-b+rJOuVqq+Dy53quPcNYcQwPFoMU7Wp7tdUVe7n0g8w=",
"minimal": "sha256-qxRIxtjPxVsVCY90WsBJKhk0027XDSmhjnRvRN14V1c=",
"mainnet": "sha256-NsuOQG3LzeiEE1TrWuvQ6vu6BboHv7h7f/RTS0pWkCs=",
},
version = consensus_spec_version,
)
@@ -298,7 +298,7 @@ filegroup(
visibility = ["//visibility:public"],
)
""",
integrity = "sha256-J+43DrK1pF658kTXTwMS6zGf4KDjvas++m8w2a8swpg=",
integrity = "sha256-hwNdUBgdBrkk6pWIpNYbzbwswUuOu6AMD2exN8uv+QQ=",
strip_prefix = "consensus-specs-" + consensus_spec_version[1:],
url = "https://github.com/ethereum/consensus-specs/archive/refs/tags/%s.tar.gz" % consensus_spec_version,
)

View File

@@ -74,6 +74,7 @@ go_library(
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/stategen:go_default_library",
"//beacon-chain/verification:go_default_library",
"//cmd/beacon-chain/flags:go_default_library",
"//config/features:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
@@ -173,6 +174,7 @@ go_test(
"//beacon-chain/state/state-native:go_default_library",
"//beacon-chain/state/stategen:go_default_library",
"//beacon-chain/verification:go_default_library",
"//cmd/beacon-chain/flags:go_default_library",
"//config/features:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",

View File

@@ -14,6 +14,7 @@ import (
"github.com/OffchainLabs/prysm/v7/beacon-chain/cache"
statefeed "github.com/OffchainLabs/prysm/v7/beacon-chain/core/feed/state"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/peerdas"
coreTime "github.com/OffchainLabs/prysm/v7/beacon-chain/core/time"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/transition"
"github.com/OffchainLabs/prysm/v7/beacon-chain/db"
@@ -29,6 +30,7 @@ import (
"github.com/OffchainLabs/prysm/v7/beacon-chain/startup"
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
"github.com/OffchainLabs/prysm/v7/beacon-chain/state/stategen"
"github.com/OffchainLabs/prysm/v7/cmd/beacon-chain/flags"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
@@ -289,6 +291,19 @@ func (s *Service) StartFromSavedState(saved state.BeaconState) error {
return errors.Wrap(err, "failed to initialize blockchain service")
}
if !params.FuluEnabled() {
return nil
}
earliestAvailableSlot, custodySubnetCount, err := s.updateCustodyInfoInDB(saved.Slot())
if err != nil {
return errors.Wrap(err, "could not get and save custody group count")
}
if _, _, err := s.cfg.P2P.UpdateCustodyInfo(earliestAvailableSlot, custodySubnetCount); err != nil {
return errors.Wrap(err, "update custody info")
}
return nil
}
@@ -453,6 +468,73 @@ func (s *Service) removeStartupState() {
s.cfg.FinalizedStateAtStartUp = nil
}
// UpdateCustodyInfoInDB updates the custody information in the database.
// It returns the (potentially updated) custody group count and the earliest available slot.
func (s *Service) updateCustodyInfoInDB(slot primitives.Slot) (primitives.Slot, uint64, error) {
isSupernode := flags.Get().Supernode
isSemiSupernode := flags.Get().SemiSupernode
cfg := params.BeaconConfig()
custodyRequirement := cfg.CustodyRequirement
// Check if the node was previously subscribed to all data subnets, and if so,
// store the new status accordingly.
wasSupernode, err := s.cfg.BeaconDB.UpdateSubscribedToAllDataSubnets(s.ctx, isSupernode)
if err != nil {
return 0, 0, errors.Wrap(err, "update subscribed to all data subnets")
}
// Compute the target custody group count based on current flag configuration.
targetCustodyGroupCount := custodyRequirement
// Supernode: custody all groups (either currently set or previously enabled)
if isSupernode {
targetCustodyGroupCount = cfg.NumberOfCustodyGroups
}
// Semi-supernode: custody minimum needed for reconstruction, or custody requirement if higher
if isSemiSupernode {
semiSupernodeCustody, err := peerdas.MinimumCustodyGroupCountToReconstruct()
if err != nil {
return 0, 0, errors.Wrap(err, "minimum custody group count")
}
targetCustodyGroupCount = max(custodyRequirement, semiSupernodeCustody)
}
// Safely compute the fulu fork slot.
fuluForkSlot, err := fuluForkSlot()
if err != nil {
return 0, 0, errors.Wrap(err, "fulu fork slot")
}
// If slot is before the fulu fork slot, then use the earliest stored slot as the reference slot.
if slot < fuluForkSlot {
slot, err = s.cfg.BeaconDB.EarliestSlot(s.ctx)
if err != nil {
return 0, 0, errors.Wrap(err, "earliest slot")
}
}
earliestAvailableSlot, actualCustodyGroupCount, err := s.cfg.BeaconDB.UpdateCustodyInfo(s.ctx, slot, targetCustodyGroupCount)
if err != nil {
return 0, 0, errors.Wrap(err, "update custody info")
}
if isSupernode {
log.WithFields(logrus.Fields{
"current": actualCustodyGroupCount,
"target": cfg.NumberOfCustodyGroups,
}).Info("Supernode mode enabled. Will custody all data columns going forward.")
}
if wasSupernode && !isSupernode {
log.Warningf("Because the `--%s` flag was previously used, the node will continue to act as a super node.", flags.Supernode.Name)
}
return earliestAvailableSlot, actualCustodyGroupCount, nil
}
func spawnCountdownIfPreGenesis(ctx context.Context, genesisTime time.Time, db db.HeadAccessDatabase) {
currentTime := prysmTime.Now()
if currentTime.After(genesisTime) {
@@ -469,3 +551,19 @@ func spawnCountdownIfPreGenesis(ctx context.Context, genesisTime time.Time, db d
}
go slots.CountdownToGenesis(ctx, genesisTime, uint64(gState.NumValidators()), gRoot)
}
func fuluForkSlot() (primitives.Slot, error) {
cfg := params.BeaconConfig()
fuluForkEpoch := cfg.FuluForkEpoch
if fuluForkEpoch == cfg.FarFutureEpoch {
return cfg.FarFutureSlot, nil
}
forkFuluSlot, err := slots.EpochStart(fuluForkEpoch)
if err != nil {
return 0, errors.Wrap(err, "epoch start")
}
return forkFuluSlot, nil
}

View File

@@ -23,9 +23,11 @@ import (
"github.com/OffchainLabs/prysm/v7/beacon-chain/startup"
state_native "github.com/OffchainLabs/prysm/v7/beacon-chain/state/state-native"
"github.com/OffchainLabs/prysm/v7/beacon-chain/state/stategen"
"github.com/OffchainLabs/prysm/v7/cmd/beacon-chain/flags"
"github.com/OffchainLabs/prysm/v7/config/features"
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
consensusblocks "github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
@@ -594,3 +596,218 @@ func TestNotifyIndex(t *testing.T) {
t.Errorf("Notifier channel did not receive the index")
}
}
func TestUpdateCustodyInfoInDB(t *testing.T) {
const (
fuluForkEpoch = 10
custodyRequirement = uint64(4)
earliestStoredSlot = primitives.Slot(12)
numberOfCustodyGroups = uint64(64)
)
params.SetupTestConfigCleanup(t)
cfg := params.BeaconConfig()
cfg.FuluForkEpoch = fuluForkEpoch
cfg.CustodyRequirement = custodyRequirement
cfg.NumberOfCustodyGroups = numberOfCustodyGroups
params.OverrideBeaconConfig(cfg)
ctx := t.Context()
pbBlock := util.NewBeaconBlock()
pbBlock.Block.Slot = 12
signedBeaconBlock, err := blocks.NewSignedBeaconBlock(pbBlock)
require.NoError(t, err)
roBlock, err := blocks.NewROBlock(signedBeaconBlock)
require.NoError(t, err)
t.Run("CGC increases before fulu", func(t *testing.T) {
service, requirements := minimalTestService(t)
err = requirements.db.SaveBlock(ctx, roBlock)
require.NoError(t, err)
// Before Fulu
// -----------
actualEas, actualCgc, err := service.updateCustodyInfoInDB(15)
require.NoError(t, err)
require.Equal(t, earliestStoredSlot, actualEas)
require.Equal(t, custodyRequirement, actualCgc)
actualEas, actualCgc, err = service.updateCustodyInfoInDB(17)
require.NoError(t, err)
require.Equal(t, earliestStoredSlot, actualEas)
require.Equal(t, custodyRequirement, actualCgc)
resetFlags := flags.Get()
gFlags := new(flags.GlobalFlags)
gFlags.Supernode = true
flags.Init(gFlags)
defer flags.Init(resetFlags)
actualEas, actualCgc, err = service.updateCustodyInfoInDB(19)
require.NoError(t, err)
require.Equal(t, earliestStoredSlot, actualEas)
require.Equal(t, numberOfCustodyGroups, actualCgc)
// After Fulu
// ----------
actualEas, actualCgc, err = service.updateCustodyInfoInDB(fuluForkEpoch*primitives.Slot(cfg.SlotsPerEpoch) + 1)
require.NoError(t, err)
require.Equal(t, earliestStoredSlot, actualEas)
require.Equal(t, numberOfCustodyGroups, actualCgc)
})
t.Run("CGC increases after fulu", func(t *testing.T) {
service, requirements := minimalTestService(t)
err = requirements.db.SaveBlock(ctx, roBlock)
require.NoError(t, err)
// Before Fulu
// -----------
actualEas, actualCgc, err := service.updateCustodyInfoInDB(15)
require.NoError(t, err)
require.Equal(t, earliestStoredSlot, actualEas)
require.Equal(t, custodyRequirement, actualCgc)
actualEas, actualCgc, err = service.updateCustodyInfoInDB(17)
require.NoError(t, err)
require.Equal(t, earliestStoredSlot, actualEas)
require.Equal(t, custodyRequirement, actualCgc)
// After Fulu
// ----------
resetFlags := flags.Get()
gFlags := new(flags.GlobalFlags)
gFlags.Supernode = true
flags.Init(gFlags)
defer flags.Init(resetFlags)
slot := fuluForkEpoch*primitives.Slot(cfg.SlotsPerEpoch) + 1
actualEas, actualCgc, err = service.updateCustodyInfoInDB(slot)
require.NoError(t, err)
require.Equal(t, slot, actualEas)
require.Equal(t, numberOfCustodyGroups, actualCgc)
actualEas, actualCgc, err = service.updateCustodyInfoInDB(slot + 2)
require.NoError(t, err)
require.Equal(t, slot, actualEas)
require.Equal(t, numberOfCustodyGroups, actualCgc)
})
t.Run("Supernode downgrade prevented", func(t *testing.T) {
service, requirements := minimalTestService(t)
err = requirements.db.SaveBlock(ctx, roBlock)
require.NoError(t, err)
// Enable supernode
resetFlags := flags.Get()
gFlags := new(flags.GlobalFlags)
gFlags.Supernode = true
flags.Init(gFlags)
slot := fuluForkEpoch*primitives.Slot(cfg.SlotsPerEpoch) + 1
actualEas, actualCgc, err := service.updateCustodyInfoInDB(slot)
require.NoError(t, err)
require.Equal(t, slot, actualEas)
require.Equal(t, numberOfCustodyGroups, actualCgc)
// Try to downgrade by removing flag
gFlags.Supernode = false
flags.Init(gFlags)
defer flags.Init(resetFlags)
// Should still be supernode
actualEas, actualCgc, err = service.updateCustodyInfoInDB(slot + 2)
require.NoError(t, err)
require.Equal(t, slot, actualEas)
require.Equal(t, numberOfCustodyGroups, actualCgc) // Still 64, not downgraded
})
t.Run("Semi-supernode downgrade prevented", func(t *testing.T) {
service, requirements := minimalTestService(t)
err = requirements.db.SaveBlock(ctx, roBlock)
require.NoError(t, err)
// Enable semi-supernode
resetFlags := flags.Get()
gFlags := new(flags.GlobalFlags)
gFlags.SemiSupernode = true
flags.Init(gFlags)
slot := fuluForkEpoch*primitives.Slot(cfg.SlotsPerEpoch) + 1
actualEas, actualCgc, err := service.updateCustodyInfoInDB(slot)
require.NoError(t, err)
require.Equal(t, slot, actualEas)
semiSupernodeCustody := numberOfCustodyGroups / 2 // 64
require.Equal(t, semiSupernodeCustody, actualCgc) // Semi-supernode custodies 64 groups
// Try to downgrade by removing flag
gFlags.SemiSupernode = false
flags.Init(gFlags)
defer flags.Init(resetFlags)
// UpdateCustodyInfo should prevent downgrade - custody count should remain at 64
actualEas, actualCgc, err = service.updateCustodyInfoInDB(slot + 2)
require.NoError(t, err)
require.Equal(t, slot, actualEas)
require.Equal(t, semiSupernodeCustody, actualCgc) // Still 64 due to downgrade prevention by UpdateCustodyInfo
})
t.Run("Semi-supernode to supernode upgrade allowed", func(t *testing.T) {
service, requirements := minimalTestService(t)
err = requirements.db.SaveBlock(ctx, roBlock)
require.NoError(t, err)
// Start with semi-supernode
resetFlags := flags.Get()
gFlags := new(flags.GlobalFlags)
gFlags.SemiSupernode = true
flags.Init(gFlags)
slot := fuluForkEpoch*primitives.Slot(cfg.SlotsPerEpoch) + 1
actualEas, actualCgc, err := service.updateCustodyInfoInDB(slot)
require.NoError(t, err)
require.Equal(t, slot, actualEas)
semiSupernodeCustody := numberOfCustodyGroups / 2 // 64
require.Equal(t, semiSupernodeCustody, actualCgc) // Semi-supernode custodies 64 groups
// Upgrade to full supernode
gFlags.SemiSupernode = false
gFlags.Supernode = true
flags.Init(gFlags)
defer flags.Init(resetFlags)
// Should upgrade to full supernode
upgradeSlot := slot + 2
actualEas, actualCgc, err = service.updateCustodyInfoInDB(upgradeSlot)
require.NoError(t, err)
require.Equal(t, upgradeSlot, actualEas) // Earliest slot updates when upgrading
require.Equal(t, numberOfCustodyGroups, actualCgc) // Upgraded to 128
})
t.Run("Semi-supernode with high validator requirements uses higher custody", func(t *testing.T) {
service, requirements := minimalTestService(t)
err = requirements.db.SaveBlock(ctx, roBlock)
require.NoError(t, err)
// Enable semi-supernode
resetFlags := flags.Get()
gFlags := new(flags.GlobalFlags)
gFlags.SemiSupernode = true
flags.Init(gFlags)
defer flags.Init(resetFlags)
// Mock a high custody requirement (simulating many validators)
// We need to override the custody requirement calculation
// For this test, we'll verify the logic by checking if custodyRequirement > 64
// Since custodyRequirement in minimalTestService is 4, we can't test the high case here
// This would require a different test setup with actual validators
slot := fuluForkEpoch*primitives.Slot(cfg.SlotsPerEpoch) + 1
actualEas, actualCgc, err := service.updateCustodyInfoInDB(slot)
require.NoError(t, err)
require.Equal(t, slot, actualEas)
semiSupernodeCustody := numberOfCustodyGroups / 2 // 64
// With low validator requirements (4), should use semi-supernode minimum (64)
require.Equal(t, semiSupernodeCustody, actualCgc)
})
}

View File

@@ -26,6 +26,7 @@ go_library(
"//beacon-chain/core/time:go_default_library",
"//beacon-chain/core/validators:go_default_library",
"//beacon-chain/state:go_default_library",
"//config/features:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//consensus-types:go_default_library",

View File

@@ -7,6 +7,7 @@ import (
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/signing"
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
"github.com/OffchainLabs/prysm/v7/config/features"
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
@@ -212,7 +213,12 @@ func ProcessWithdrawals(st state.BeaconState, executionData interfaces.Execution
if err != nil {
return nil, errors.Wrap(err, "could not get next withdrawal validator index")
}
nextValidatorIndex += primitives.ValidatorIndex(params.BeaconConfig().MaxValidatorsPerWithdrawalsSweep)
if features.Get().LowValcountSweep {
bound := min(uint64(st.NumValidators()), params.BeaconConfig().MaxValidatorsPerWithdrawalsSweep)
nextValidatorIndex += primitives.ValidatorIndex(bound)
} else {
nextValidatorIndex += primitives.ValidatorIndex(params.BeaconConfig().MaxValidatorsPerWithdrawalsSweep)
}
nextValidatorIndex = nextValidatorIndex % primitives.ValidatorIndex(st.NumValidators())
} else {
nextValidatorIndex = expectedWithdrawals[len(expectedWithdrawals)-1].ValidatorIndex + 1

View File

@@ -12,6 +12,7 @@ go_library(
"log.go",
"registry_updates.go",
"transition.go",
"transition_no_verify_sig.go",
"upgrade.go",
"validator.go",
"withdrawals.go",
@@ -61,6 +62,7 @@ go_test(
"error_test.go",
"export_test.go",
"registry_updates_test.go",
"transition_no_verify_sig_test.go",
"transition_test.go",
"upgrade_test.go",
"validator_test.go",

View File

@@ -6,11 +6,6 @@ type execReqErr struct {
error
}
// NewExecReqError creates a new execReqErr.
func NewExecReqError(msg string) error {
return execReqErr{errors.New(msg)}
}
// IsExecutionRequestError returns true if the error has `execReqErr`.
func IsExecutionRequestError(e error) bool {
if e == nil {

View File

@@ -1,10 +1,9 @@
package transition
package electra
import (
"context"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/blocks"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/electra"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers"
v "github.com/OffchainLabs/prysm/v7/beacon-chain/core/validators"
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
@@ -48,7 +47,7 @@ var (
// # [New in Electra:EIP7251]
// for_ops(body.execution_payload.consolidation_requests, process_consolidation_request)
func electraOperations(ctx context.Context, st state.BeaconState, block interfaces.ReadOnlyBeaconBlock) (state.BeaconState, error) {
func ProcessOperations(ctx context.Context, st state.BeaconState, block interfaces.ReadOnlyBeaconBlock) (state.BeaconState, error) {
var err error
// 6110 validations are in VerifyOperationLengths
@@ -64,60 +63,59 @@ func electraOperations(ctx context.Context, st state.BeaconState, block interfac
return nil, errors.Wrap(err, "could not update total active balance cache")
}
}
st, err = blocks.ProcessProposerSlashings(ctx, st, bb.ProposerSlashings(), exitInfo)
st, err = ProcessProposerSlashings(ctx, st, bb.ProposerSlashings(), exitInfo)
if err != nil {
return nil, errors.Wrap(ErrProcessProposerSlashingsFailed, err.Error())
return nil, errors.Wrap(err, "could not process altair proposer slashing")
}
st, err = blocks.ProcessAttesterSlashings(ctx, st, bb.AttesterSlashings(), exitInfo)
st, err = ProcessAttesterSlashings(ctx, st, bb.AttesterSlashings(), exitInfo)
if err != nil {
return nil, errors.Wrap(ErrProcessAttesterSlashingsFailed, err.Error())
return nil, errors.Wrap(err, "could not process altair attester slashing")
}
st, err = electra.ProcessAttestationsNoVerifySignature(ctx, st, block)
st, err = ProcessAttestationsNoVerifySignature(ctx, st, block)
if err != nil {
return nil, errors.Wrap(ErrProcessAttestationsFailed, err.Error())
return nil, errors.Wrap(err, "could not process altair attestation")
}
if _, err := electra.ProcessDeposits(ctx, st, bb.Deposits()); err != nil {
return nil, errors.Wrap(ErrProcessDepositsFailed, err.Error())
if _, err := ProcessDeposits(ctx, st, bb.Deposits()); err != nil { // new in electra
return nil, errors.Wrap(err, "could not process altair deposit")
}
st, err = blocks.ProcessVoluntaryExits(ctx, st, bb.VoluntaryExits(), exitInfo)
st, err = ProcessVoluntaryExits(ctx, st, bb.VoluntaryExits(), exitInfo)
if err != nil {
return nil, errors.Wrap(ErrProcessVoluntaryExitsFailed, err.Error())
return nil, errors.Wrap(err, "could not process voluntary exits")
}
st, err = blocks.ProcessBLSToExecutionChanges(st, block)
st, err = ProcessBLSToExecutionChanges(st, block)
if err != nil {
return nil, errors.Wrap(ErrProcessBLSChangesFailed, err.Error())
return nil, errors.Wrap(err, "could not process bls-to-execution changes")
}
// new in electra
requests, err := bb.ExecutionRequests()
if err != nil {
return nil, electra.NewExecReqError(errors.Wrap(err, "could not get execution requests").Error())
return nil, errors.Wrap(err, "could not get execution requests")
}
for _, d := range requests.Deposits {
if d == nil {
return nil, electra.NewExecReqError("nil deposit request")
return nil, errors.New("nil deposit request")
}
}
st, err = electra.ProcessDepositRequests(ctx, st, requests.Deposits)
st, err = ProcessDepositRequests(ctx, st, requests.Deposits)
if err != nil {
return nil, electra.NewExecReqError(errors.Wrap(err, "could not process deposit requests").Error())
return nil, execReqErr{errors.Wrap(err, "could not process deposit requests")}
}
for _, w := range requests.Withdrawals {
if w == nil {
return nil, electra.NewExecReqError("nil withdrawal request")
return nil, errors.New("nil withdrawal request")
}
}
st, err = electra.ProcessWithdrawalRequests(ctx, st, requests.Withdrawals)
st, err = ProcessWithdrawalRequests(ctx, st, requests.Withdrawals)
if err != nil {
return nil, electra.NewExecReqError(errors.Wrap(err, "could not process withdrawal requests").Error())
return nil, execReqErr{errors.Wrap(err, "could not process withdrawal requests")}
}
for _, c := range requests.Consolidations {
if c == nil {
return nil, electra.NewExecReqError("nil consolidation request")
return nil, errors.New("nil consolidation request")
}
}
if err := electra.ProcessConsolidationRequests(ctx, st, requests.Consolidations); err != nil {
return nil, electra.NewExecReqError(errors.Wrap(err, "could not process consolidation requests").Error())
if err := ProcessConsolidationRequests(ctx, st, requests.Consolidations); err != nil {
return nil, execReqErr{errors.Wrap(err, "could not process consolidation requests")}
}
return st, nil
}

View File

@@ -0,0 +1,60 @@
package electra_test
import (
"testing"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/electra"
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v7/testing/require"
"github.com/OffchainLabs/prysm/v7/testing/util"
)
func TestProcessOperationsWithNilRequests(t *testing.T) {
tests := []struct {
name string
modifyBlk func(blockElectra *ethpb.SignedBeaconBlockElectra)
errMsg string
}{
{
name: "Nil deposit request",
modifyBlk: func(blk *ethpb.SignedBeaconBlockElectra) {
blk.Block.Body.ExecutionRequests.Deposits = []*enginev1.DepositRequest{nil}
},
errMsg: "nil deposit request",
},
{
name: "Nil withdrawal request",
modifyBlk: func(blk *ethpb.SignedBeaconBlockElectra) {
blk.Block.Body.ExecutionRequests.Withdrawals = []*enginev1.WithdrawalRequest{nil}
},
errMsg: "nil withdrawal request",
},
{
name: "Nil consolidation request",
modifyBlk: func(blk *ethpb.SignedBeaconBlockElectra) {
blk.Block.Body.ExecutionRequests.Consolidations = []*enginev1.ConsolidationRequest{nil}
},
errMsg: "nil consolidation request",
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
st, ks := util.DeterministicGenesisStateElectra(t, 128)
blk, err := util.GenerateFullBlockElectra(st, ks, util.DefaultBlockGenConfig(), 1)
require.NoError(t, err)
tc.modifyBlk(blk)
b, err := blocks.NewSignedBeaconBlock(blk)
require.NoError(t, err)
require.NoError(t, st.SetSlot(1))
_, err = electra.ProcessOperations(t.Context(), st, b.Block())
require.ErrorContains(t, tc.errMsg, err)
})
}
}

View File

@@ -3,8 +3,6 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"electra.go",
"errors.go",
"log.go",
"skip_slot_cache.go",
"state.go",
@@ -64,8 +62,6 @@ go_test(
"altair_transition_no_verify_sig_test.go",
"bellatrix_transition_no_verify_sig_test.go",
"benchmarks_test.go",
"electra_test.go",
"exports_test.go",
"skip_slot_cache_test.go",
"state_fuzz_test.go",
"state_test.go",

View File

@@ -1,216 +0,0 @@
package transition_test
import (
"context"
"errors"
"testing"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/transition"
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v7/testing/require"
"github.com/OffchainLabs/prysm/v7/testing/util"
)
func TestProcessOperationsWithNilRequests(t *testing.T) {
tests := []struct {
name string
modifyBlk func(blockElectra *ethpb.SignedBeaconBlockElectra)
errMsg string
}{
{
name: "Nil deposit request",
modifyBlk: func(blk *ethpb.SignedBeaconBlockElectra) {
blk.Block.Body.ExecutionRequests.Deposits = []*enginev1.DepositRequest{nil}
},
errMsg: "nil deposit request",
},
{
name: "Nil withdrawal request",
modifyBlk: func(blk *ethpb.SignedBeaconBlockElectra) {
blk.Block.Body.ExecutionRequests.Withdrawals = []*enginev1.WithdrawalRequest{nil}
},
errMsg: "nil withdrawal request",
},
{
name: "Nil consolidation request",
modifyBlk: func(blk *ethpb.SignedBeaconBlockElectra) {
blk.Block.Body.ExecutionRequests.Consolidations = []*enginev1.ConsolidationRequest{nil}
},
errMsg: "nil consolidation request",
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
st, ks := util.DeterministicGenesisStateElectra(t, 128)
blk, err := util.GenerateFullBlockElectra(st, ks, util.DefaultBlockGenConfig(), 1)
require.NoError(t, err)
tc.modifyBlk(blk)
b, err := blocks.NewSignedBeaconBlock(blk)
require.NoError(t, err)
require.NoError(t, st.SetSlot(1))
_, err = transition.ElectraOperations(t.Context(), st, b.Block())
require.ErrorContains(t, tc.errMsg, err)
})
}
}
func TestElectraOperations_ProcessingErrors(t *testing.T) {
tests := []struct {
name string
modifyBlk func(blk *ethpb.SignedBeaconBlockElectra)
errCheck func(t *testing.T, err error)
}{
{
name: "ErrProcessProposerSlashingsFailed",
modifyBlk: func(blk *ethpb.SignedBeaconBlockElectra) {
// Create invalid proposer slashing with out-of-bounds proposer index
blk.Block.Body.ProposerSlashings = []*ethpb.ProposerSlashing{
{
Header_1: &ethpb.SignedBeaconBlockHeader{
Header: &ethpb.BeaconBlockHeader{
Slot: 1,
ProposerIndex: 999999, // Invalid index (out of bounds)
ParentRoot: make([]byte, 32),
StateRoot: make([]byte, 32),
BodyRoot: make([]byte, 32),
},
Signature: make([]byte, 96),
},
Header_2: &ethpb.SignedBeaconBlockHeader{
Header: &ethpb.BeaconBlockHeader{
Slot: 1,
ProposerIndex: 999999,
ParentRoot: make([]byte, 32),
StateRoot: make([]byte, 32),
BodyRoot: make([]byte, 32),
},
Signature: make([]byte, 96),
},
},
}
},
errCheck: func(t *testing.T, err error) {
require.ErrorContains(t, "process proposer slashings failed", err)
require.Equal(t, true, errors.Is(err, transition.ErrProcessProposerSlashingsFailed))
},
},
{
name: "ErrProcessAttestationsFailed",
modifyBlk: func(blk *ethpb.SignedBeaconBlockElectra) {
// Create attestation with invalid committee index
blk.Block.Body.Attestations = []*ethpb.AttestationElectra{
{
AggregationBits: []byte{0b00000001},
Data: &ethpb.AttestationData{
Slot: 1,
CommitteeIndex: 999999, // Invalid committee index
BeaconBlockRoot: make([]byte, 32),
Source: &ethpb.Checkpoint{
Epoch: 0,
Root: make([]byte, 32),
},
Target: &ethpb.Checkpoint{
Epoch: 0,
Root: make([]byte, 32),
},
},
CommitteeBits: []byte{0b00000001},
Signature: make([]byte, 96),
},
}
},
errCheck: func(t *testing.T, err error) {
require.ErrorContains(t, "process attestations failed", err)
require.Equal(t, true, errors.Is(err, transition.ErrProcessAttestationsFailed))
},
},
{
name: "ErrProcessDepositsFailed",
modifyBlk: func(blk *ethpb.SignedBeaconBlockElectra) {
// Create deposit with invalid proof length
blk.Block.Body.Deposits = []*ethpb.Deposit{
{
Proof: [][]byte{}, // Invalid: empty proof
Data: &ethpb.Deposit_Data{
PublicKey: make([]byte, 48),
WithdrawalCredentials: make([]byte, 32),
Amount: 32000000000, // 32 ETH in Gwei
Signature: make([]byte, 96),
},
},
}
},
errCheck: func(t *testing.T, err error) {
require.ErrorContains(t, "process deposits failed", err)
require.Equal(t, true, errors.Is(err, transition.ErrProcessDepositsFailed))
},
},
{
name: "ErrProcessVoluntaryExitsFailed",
modifyBlk: func(blk *ethpb.SignedBeaconBlockElectra) {
// Create voluntary exit with invalid validator index
blk.Block.Body.VoluntaryExits = []*ethpb.SignedVoluntaryExit{
{
Exit: &ethpb.VoluntaryExit{
Epoch: 0,
ValidatorIndex: 999999, // Invalid index (out of bounds)
},
Signature: make([]byte, 96),
},
}
},
errCheck: func(t *testing.T, err error) {
require.ErrorContains(t, "process voluntary exits failed", err)
require.Equal(t, true, errors.Is(err, transition.ErrProcessVoluntaryExitsFailed))
},
},
{
name: "ErrProcessBLSChangesFailed",
modifyBlk: func(blk *ethpb.SignedBeaconBlockElectra) {
// Create BLS to execution change with invalid validator index
blk.Block.Body.BlsToExecutionChanges = []*ethpb.SignedBLSToExecutionChange{
{
Message: &ethpb.BLSToExecutionChange{
ValidatorIndex: 999999, // Invalid index (out of bounds)
FromBlsPubkey: make([]byte, 48),
ToExecutionAddress: make([]byte, 20),
},
Signature: make([]byte, 96),
},
}
},
errCheck: func(t *testing.T, err error) {
require.ErrorContains(t, "process BLS to execution changes failed", err)
require.Equal(t, true, errors.Is(err, transition.ErrProcessBLSChangesFailed))
},
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
ctx := context.Background()
st, ks := util.DeterministicGenesisStateElectra(t, 128)
blk, err := util.GenerateFullBlockElectra(st, ks, util.DefaultBlockGenConfig(), 1)
require.NoError(t, err)
tc.modifyBlk(blk)
b, err := blocks.NewSignedBeaconBlock(blk)
require.NoError(t, err)
require.NoError(t, st.SetSlot(primitives.Slot(1)))
_, err = transition.ElectraOperations(ctx, st, b.Block())
require.NotNil(t, err, "Expected an error but got nil")
tc.errCheck(t, err)
})
}
}

View File

@@ -1,19 +0,0 @@
package transition
import "errors"
var (
ErrAttestationsSignatureInvalid = errors.New("attestations signature invalid")
ErrRandaoSignatureInvalid = errors.New("randao signature invalid")
ErrBLSToExecutionChangesSignatureInvalid = errors.New("BLS to execution changes signature invalid")
ErrProcessWithdrawalsFailed = errors.New("process withdrawals failed")
ErrProcessRandaoFailed = errors.New("process randao failed")
ErrProcessEth1DataFailed = errors.New("process eth1 data failed")
ErrProcessProposerSlashingsFailed = errors.New("process proposer slashings failed")
ErrProcessAttesterSlashingsFailed = errors.New("process attester slashings failed")
ErrProcessAttestationsFailed = errors.New("process attestations failed")
ErrProcessDepositsFailed = errors.New("process deposits failed")
ErrProcessVoluntaryExitsFailed = errors.New("process voluntary exits failed")
ErrProcessBLSChangesFailed = errors.New("process BLS to execution changes failed")
ErrProcessSyncAggregateFailed = errors.New("process sync aggregate failed")
)

View File

@@ -1,3 +0,0 @@
package transition
var ElectraOperations = electraOperations

View File

@@ -7,11 +7,12 @@ import (
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/altair"
b "github.com/OffchainLabs/prysm/v7/beacon-chain/core/blocks"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/electra"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/transition/interop"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/validators"
v "github.com/OffchainLabs/prysm/v7/beacon-chain/core/validators"
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
"github.com/OffchainLabs/prysm/v7/config/features"
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
"github.com/OffchainLabs/prysm/v7/crypto/bls"
@@ -69,11 +70,10 @@ func ExecuteStateTransitionNoVerifyAnySig(
}
// Execute per block transition.
sigSlice, st, err := ProcessBlockNoVerifyAnySig(ctx, st, signed)
set, st, err := ProcessBlockNoVerifyAnySig(ctx, st, signed)
if err != nil {
return nil, nil, errors.Wrap(err, "could not process block")
}
set := sigSlice.Batch()
// State root validation.
postStateRoot, err := st.HashTreeRoot(ctx)
@@ -113,7 +113,7 @@ func ExecuteStateTransitionNoVerifyAnySig(
// assert block.state_root == hash_tree_root(state)
func CalculateStateRoot(
ctx context.Context,
rollback state.BeaconState,
state state.BeaconState,
signed interfaces.ReadOnlySignedBeaconBlock,
) ([32]byte, error) {
ctx, span := trace.StartSpan(ctx, "core.state.CalculateStateRoot")
@@ -122,7 +122,7 @@ func CalculateStateRoot(
tracing.AnnotateError(span, ctx.Err())
return [32]byte{}, ctx.Err()
}
if rollback == nil || rollback.IsNil() {
if state == nil || state.IsNil() {
return [32]byte{}, errors.New("nil state")
}
if signed == nil || signed.IsNil() || signed.Block().IsNil() {
@@ -130,7 +130,7 @@ func CalculateStateRoot(
}
// Copy state to avoid mutating the state reference.
state := rollback.Copy()
state = state.Copy()
// Execute per slots transition.
var err error
@@ -141,103 +141,14 @@ func CalculateStateRoot(
}
// Execute per block transition.
if features.Get().EnableProposerPreprocessing {
state, err = processBlockForProposing(ctx, state, signed)
if err != nil {
return [32]byte{}, errors.Wrap(err, "could not process block for proposing")
}
} else {
state, err = ProcessBlockForStateRoot(ctx, state, signed)
if err != nil {
return [32]byte{}, errors.Wrap(err, "could not process block")
}
state, err = ProcessBlockForStateRoot(ctx, state, signed)
if err != nil {
return [32]byte{}, errors.Wrap(err, "could not process block")
}
return state.HashTreeRoot(ctx)
}
// processBlockVerifySigs processes the block and verifies the signatures within it. Block signatures are not verified as this block is not yet signed.
func processBlockForProposing(ctx context.Context, st state.BeaconState, signed interfaces.ReadOnlySignedBeaconBlock) (state.BeaconState, error) {
var err error
var set BlockSignatureBatches
set, st, err = ProcessBlockNoVerifyAnySig(ctx, st, signed)
if err != nil {
return nil, err
}
// We first try to verify all sigantures batched optimistically. We ignore block proposer signature.
sigSet := set.Batch()
valid, err := sigSet.Verify()
if err != nil || valid {
return st, err
}
// Some signature failed to verify.
// Verify Attestations signatures
attSigs := set.AttestationSignatures
if attSigs == nil {
return nil, ErrAttestationsSignatureInvalid
}
valid, err = attSigs.Verify()
if err != nil {
return nil, err
}
if !valid {
return nil, ErrAttestationsSignatureInvalid
}
// Verify Randao signature
randaoSigs := set.RandaoSignatures
if randaoSigs == nil {
return nil, ErrRandaoSignatureInvalid
}
valid, err = randaoSigs.Verify()
if err != nil {
return nil, err
}
if !valid {
return nil, ErrRandaoSignatureInvalid
}
if signed.Block().Version() < version.Capella {
//This should not happen as we must have failed one of the above signatures.
return st, nil
}
// Verify BLS to execution changes signatures
blsChangeSigs := set.BLSChangeSignatures
if blsChangeSigs == nil {
return nil, ErrBLSToExecutionChangesSignatureInvalid
}
valid, err = blsChangeSigs.Verify()
if err != nil {
return nil, err
}
if !valid {
return nil, ErrBLSToExecutionChangesSignatureInvalid
}
// We should not reach this point as one of the above signatures must have failed.
return st, nil
}
// BlockSignatureBatches holds the signature batches for different parts of a beacon block.
type BlockSignatureBatches struct {
RandaoSignatures *bls.SignatureBatch
AttestationSignatures *bls.SignatureBatch
BLSChangeSignatures *bls.SignatureBatch
}
// Batch returns the batch of signature batches in the BlockSignatureBatches.
func (b BlockSignatureBatches) Batch() *bls.SignatureBatch {
sigs := bls.NewSet()
if b.RandaoSignatures != nil {
sigs.Join(b.RandaoSignatures)
}
if b.AttestationSignatures != nil {
sigs.Join(b.AttestationSignatures)
}
if b.BLSChangeSignatures != nil {
sigs.Join(b.BLSChangeSignatures)
}
return sigs
}
// ProcessBlockNoVerifyAnySig creates a new, modified beacon state by applying block operation
// transformations as defined in the Ethereum Serenity specification. It does not validate
// any block signature except for deposit and slashing signatures. It also returns the relevant
@@ -254,48 +165,48 @@ func ProcessBlockNoVerifyAnySig(
ctx context.Context,
st state.BeaconState,
signed interfaces.ReadOnlySignedBeaconBlock,
) (BlockSignatureBatches, state.BeaconState, error) {
) (*bls.SignatureBatch, state.BeaconState, error) {
ctx, span := trace.StartSpan(ctx, "core.state.ProcessBlockNoVerifyAnySig")
defer span.End()
set := BlockSignatureBatches{}
if err := blocks.BeaconBlockIsNil(signed); err != nil {
return set, nil, err
return nil, nil, err
}
if st.Version() != signed.Block().Version() {
return set, nil, fmt.Errorf("state and block are different version. %d != %d", st.Version(), signed.Block().Version())
return nil, nil, fmt.Errorf("state and block are different version. %d != %d", st.Version(), signed.Block().Version())
}
blk := signed.Block()
st, err := ProcessBlockForStateRoot(ctx, st, signed)
if err != nil {
return set, nil, err
return nil, nil, err
}
randaoReveal := signed.Block().Body().RandaoReveal()
rSet, err := b.RandaoSignatureBatch(ctx, st, randaoReveal[:])
if err != nil {
tracing.AnnotateError(span, err)
return set, nil, errors.Wrap(err, "could not retrieve randao signature set")
return nil, nil, errors.Wrap(err, "could not retrieve randao signature set")
}
set.RandaoSignatures = rSet
aSet, err := b.AttestationSignatureBatch(ctx, st, signed.Block().Body().Attestations())
if err != nil {
return set, nil, errors.Wrap(err, "could not retrieve attestation signature set")
return nil, nil, errors.Wrap(err, "could not retrieve attestation signature set")
}
set.AttestationSignatures = aSet
// Merge beacon block, randao and attestations signatures into a set.
set := bls.NewSet()
set.Join(rSet).Join(aSet)
if blk.Version() >= version.Capella {
changes, err := signed.Block().Body().BLSToExecutionChanges()
if err != nil {
return set, nil, errors.Wrap(err, "could not get BLSToExecutionChanges")
return nil, nil, errors.Wrap(err, "could not get BLSToExecutionChanges")
}
cSet, err := b.BLSChangesSignatureBatch(st, changes)
if err != nil {
return set, nil, errors.Wrap(err, "could not get BLSToExecutionChanges signatures")
return nil, nil, errors.Wrap(err, "could not get BLSToExecutionChanges signatures")
}
set.BLSChangeSignatures = cSet
set.Join(cSet)
}
return set, st, nil
}
@@ -357,7 +268,7 @@ func ProcessOperationsNoVerifyAttsSigs(
return nil, err
}
} else {
state, err = electraOperations(ctx, state, beaconBlock)
state, err = electra.ProcessOperations(ctx, state, beaconBlock)
if err != nil {
return nil, err
}
@@ -415,7 +326,7 @@ func ProcessBlockForStateRoot(
if state.Version() >= version.Capella {
state, err = b.ProcessWithdrawals(state, executionData)
if err != nil {
return nil, errors.Wrap(ErrProcessWithdrawalsFailed, err.Error())
return nil, errors.Wrap(err, "could not process withdrawals")
}
}
if err = b.ProcessPayload(state, blk.Body()); err != nil {
@@ -427,13 +338,13 @@ func ProcessBlockForStateRoot(
state, err = b.ProcessRandaoNoVerify(state, randaoReveal[:])
if err != nil {
tracing.AnnotateError(span, err)
return nil, errors.Wrap(ErrProcessRandaoFailed, err.Error())
return nil, errors.Wrap(err, "could not verify and process randao")
}
state, err = b.ProcessEth1DataInBlock(ctx, state, signed.Block().Body().Eth1Data())
if err != nil {
tracing.AnnotateError(span, err)
return nil, errors.Wrap(ErrProcessEth1DataFailed, err.Error())
return nil, errors.Wrap(err, "could not process eth1 data")
}
state, err = ProcessOperationsNoVerifyAttsSigs(ctx, state, signed.Block())
@@ -452,7 +363,7 @@ func ProcessBlockForStateRoot(
}
state, _, err = altair.ProcessSyncAggregate(ctx, state, sa)
if err != nil {
return nil, errors.Wrap(ErrProcessSyncAggregateFailed, err.Error())
return nil, errors.Wrap(err, "process_sync_aggregate failed")
}
return state, nil
@@ -468,35 +379,31 @@ func altairOperations(ctx context.Context, st state.BeaconState, beaconBlock int
exitInfo := &validators.ExitInfo{}
if hasSlashings || hasExits {
// ExitInformation is expensive to compute, only do it if we need it.
exitInfo = validators.ExitInformation(st)
exitInfo = v.ExitInformation(st)
if err := helpers.UpdateTotalActiveBalanceCache(st, exitInfo.TotalActiveBalance); err != nil {
return nil, errors.Wrap(err, "could not update total active balance cache")
}
}
st, err = b.ProcessProposerSlashings(ctx, st, beaconBlock.Body().ProposerSlashings(), exitInfo)
if err != nil {
return nil, errors.Wrap(ErrProcessProposerSlashingsFailed, err.Error())
return nil, errors.Wrap(err, "could not process altair proposer slashing")
}
st, err = b.ProcessAttesterSlashings(ctx, st, beaconBlock.Body().AttesterSlashings(), exitInfo)
if err != nil {
return nil, errors.Wrap(ErrProcessAttesterSlashingsFailed, err.Error())
return nil, errors.Wrap(err, "could not process altair attester slashing")
}
st, err = altair.ProcessAttestationsNoVerifySignature(ctx, st, beaconBlock)
if err != nil {
return nil, errors.Wrap(ErrProcessAttestationsFailed, err.Error())
return nil, errors.Wrap(err, "could not process altair attestation")
}
if _, err := altair.ProcessDeposits(ctx, st, beaconBlock.Body().Deposits()); err != nil {
return nil, errors.Wrap(ErrProcessDepositsFailed, err.Error())
return nil, errors.Wrap(err, "could not process altair deposit")
}
st, err = b.ProcessVoluntaryExits(ctx, st, beaconBlock.Body().VoluntaryExits(), exitInfo)
if err != nil {
return nil, errors.Wrap(ErrProcessVoluntaryExitsFailed, err.Error())
return nil, errors.Wrap(err, "could not process voluntary exits")
}
st, err = b.ProcessBLSToExecutionChanges(st, beaconBlock)
if err != nil {
return nil, errors.Wrap(ErrProcessBLSChangesFailed, err.Error())
}
return st, nil
return b.ProcessBLSToExecutionChanges(st, beaconBlock)
}
// This calls phase 0 block operations.
@@ -504,32 +411,32 @@ func phase0Operations(ctx context.Context, st state.BeaconState, beaconBlock int
var err error
hasSlashings := len(beaconBlock.Body().ProposerSlashings()) > 0 || len(beaconBlock.Body().AttesterSlashings()) > 0
hasExits := len(beaconBlock.Body().VoluntaryExits()) > 0
var exitInfo *validators.ExitInfo
var exitInfo *v.ExitInfo
if hasSlashings || hasExits {
// ExitInformation is expensive to compute, only do it if we need it.
exitInfo = validators.ExitInformation(st)
exitInfo = v.ExitInformation(st)
if err := helpers.UpdateTotalActiveBalanceCache(st, exitInfo.TotalActiveBalance); err != nil {
return nil, errors.Wrap(err, "could not update total active balance cache")
}
}
st, err = b.ProcessProposerSlashings(ctx, st, beaconBlock.Body().ProposerSlashings(), exitInfo)
if err != nil {
return nil, errors.Wrap(ErrProcessProposerSlashingsFailed, err.Error())
return nil, errors.Wrap(err, "could not process block proposer slashings")
}
st, err = b.ProcessAttesterSlashings(ctx, st, beaconBlock.Body().AttesterSlashings(), exitInfo)
if err != nil {
return nil, errors.Wrap(ErrProcessAttesterSlashingsFailed, err.Error())
return nil, errors.Wrap(err, "could not process block attester slashings")
}
st, err = b.ProcessAttestationsNoVerifySignature(ctx, st, beaconBlock)
if err != nil {
return nil, errors.Wrap(ErrProcessAttestationsFailed, err.Error())
return nil, errors.Wrap(err, "could not process block attestations")
}
if _, err := altair.ProcessDeposits(ctx, st, beaconBlock.Body().Deposits()); err != nil {
return nil, errors.Wrap(ErrProcessDepositsFailed, err.Error())
return nil, errors.Wrap(err, "could not process deposits")
}
st, err = b.ProcessVoluntaryExits(ctx, st, beaconBlock.Body().VoluntaryExits(), exitInfo)
if err != nil {
return nil, errors.Wrap(ErrProcessVoluntaryExitsFailed, err.Error())
return nil, errors.Wrap(err, "could not process voluntary exits")
}
return st, nil
}

View File

@@ -132,8 +132,7 @@ func TestProcessBlockNoVerify_PassesProcessingConditions(t *testing.T) {
set, _, err := transition.ProcessBlockNoVerifyAnySig(t.Context(), beaconState, wsb)
require.NoError(t, err)
// Test Signature set verifies.
sigSet := set.Batch()
verified, err := sigSet.Verify()
verified, err := set.Verify()
require.NoError(t, err)
assert.Equal(t, true, verified, "Could not verify signature set.")
}
@@ -146,8 +145,7 @@ func TestProcessBlockNoVerifyAnySigAltair_OK(t *testing.T) {
require.NoError(t, err)
set, _, err := transition.ProcessBlockNoVerifyAnySig(t.Context(), beaconState, wsb)
require.NoError(t, err)
sigSet := set.Batch()
verified, err := sigSet.Verify()
verified, err := set.Verify()
require.NoError(t, err)
require.Equal(t, true, verified, "Could not verify signature set")
}
@@ -156,9 +154,8 @@ func TestProcessBlockNoVerify_SigSetContainsDescriptions(t *testing.T) {
beaconState, block, _, _, _ := createFullBlockWithOperations(t)
wsb, err := blocks.NewSignedBeaconBlock(block)
require.NoError(t, err)
signatures, _, err := transition.ProcessBlockNoVerifyAnySig(t.Context(), beaconState, wsb)
set, _, err := transition.ProcessBlockNoVerifyAnySig(t.Context(), beaconState, wsb)
require.NoError(t, err)
set := signatures.Batch()
assert.Equal(t, len(set.Signatures), len(set.Descriptions), "Signatures and descriptions do not match up")
assert.Equal(t, "randao signature", set.Descriptions[0])
assert.Equal(t, "attestation signature", set.Descriptions[1])

View File

@@ -89,7 +89,6 @@ type NoHeadAccessDatabase interface {
SaveBlocks(ctx context.Context, blocks []interfaces.ReadOnlySignedBeaconBlock) error
SaveROBlocks(ctx context.Context, blks []blocks.ROBlock, cache bool) error
SaveGenesisBlockRoot(ctx context.Context, blockRoot [32]byte) error
SlotByBlockRoot(context.Context, [32]byte) (primitives.Slot, error)
// State related methods.
SaveState(ctx context.Context, state state.ReadOnlyBeaconState, blockRoot [32]byte) error
SaveStates(ctx context.Context, states []state.ReadOnlyBeaconState, blockRoots [][32]byte) error
@@ -97,7 +96,6 @@ type NoHeadAccessDatabase interface {
DeleteStates(ctx context.Context, blockRoots [][32]byte) error
SaveStateSummary(ctx context.Context, summary *ethpb.StateSummary) error
SaveStateSummaries(ctx context.Context, summaries []*ethpb.StateSummary) error
SlotInDiffTree(primitives.Slot) (uint64, int, error)
// Checkpoint operations.
SaveJustifiedCheckpoint(ctx context.Context, checkpoint *ethpb.Checkpoint) error
SaveFinalizedCheckpoint(ctx context.Context, checkpoint *ethpb.Checkpoint) error

View File

@@ -32,7 +32,6 @@ go_library(
"state_diff_helpers.go",
"state_summary.go",
"state_summary_cache.go",
"testing_helpers.go",
"utils.go",
"validated_checkpoint.go",
"wss.go",

View File

@@ -23,16 +23,6 @@ const (
The data at level 0 is saved every 2**exponent[0] slots and always contains a full state snapshot that is used as a base for the delta saved at other levels.
*/
// SlotInDiffTree returns whether the given slot is a saving point in the diff tree.
// It it is, it also returns the offset and level in the tree.
func (s *Store) SlotInDiffTree(slot primitives.Slot) (uint64, int, error) {
offset := s.getOffset()
if uint64(slot) < offset {
return 0, -1, ErrSlotBeforeOffset
}
return offset, computeLevel(offset, slot), nil
}
// saveStateByDiff takes a state and decides between saving a full state snapshot or a diff.
func (s *Store) saveStateByDiff(ctx context.Context, st state.ReadOnlyBeaconState) error {
_, span := trace.StartSpan(ctx, "BeaconDB.saveStateByDiff")
@@ -43,10 +33,13 @@ func (s *Store) saveStateByDiff(ctx context.Context, st state.ReadOnlyBeaconStat
}
slot := st.Slot()
offset, lvl, err := s.SlotInDiffTree(slot)
if err != nil {
return errors.Wrap(err, "could not determine if slot is in diff tree")
offset := s.getOffset()
if uint64(slot) < offset {
return ErrSlotBeforeOffset
}
// Find the level to save the state.
lvl := computeLevel(offset, slot)
if lvl == -1 {
return nil
}

View File

@@ -1,37 +0,0 @@
package kv
import (
"encoding/binary"
"testing"
"go.etcd.io/bbolt"
)
// InitStateDiffCacheForTesting initializes the state diff cache with the given offset.
// This is intended for testing purposes when setting up state diff after database creation.
// This file is only compiled when the "testing" build tag is set.
func (s *Store) InitStateDiffCacheForTesting(t testing.TB, offset uint64) error {
// First, set the offset in the database.
err := s.db.Update(func(tx *bbolt.Tx) error {
bucket := tx.Bucket(stateDiffBucket)
if bucket == nil {
return bbolt.ErrBucketNotFound
}
offsetBytes := make([]byte, 8)
binary.LittleEndian.PutUint64(offsetBytes, offset)
return bucket.Put([]byte("offset"), offsetBytes)
})
if err != nil {
return err
}
// Then create the state diff cache.
sdCache, err := newStateDiffCache(s)
if err != nil {
return err
}
s.stateDiffCache = sdCache
return nil
}

View File

@@ -602,7 +602,7 @@ func (vs *Server) GetFeeRecipientByPubKey(ctx context.Context, request *ethpb.Fe
// computeStateRoot computes the state root after a block has been processed through a state transition and
// returns it to the validator client.
func (vs *Server) computeStateRoot(ctx context.Context, block interfaces.SignedBeaconBlock) ([]byte, error) {
func (vs *Server) computeStateRoot(ctx context.Context, block interfaces.ReadOnlySignedBeaconBlock) ([]byte, error) {
beaconState, err := vs.StateGen.StateByRoot(ctx, block.Block().ParentRoot())
if err != nil {
return nil, errors.Wrap(err, "could not retrieve beacon state")
@@ -613,72 +613,13 @@ func (vs *Server) computeStateRoot(ctx context.Context, block interfaces.SignedB
block,
)
if err != nil {
return vs.handleStateRootError(ctx, block, err)
return nil, errors.Wrapf(err, "could not calculate state root at slot %d", beaconState.Slot())
}
log.WithField("beaconStateRoot", fmt.Sprintf("%#x", root)).Debugf("Computed state root")
return root[:], nil
}
type computeStateRootAttemptsKeyType string
const computeStateRootAttemptsKey = computeStateRootAttemptsKeyType("compute-state-root-attempts")
const maxComputeStateRootAttempts = 3
// handleStateRootError retries block construction in some error cases.
func (vs *Server) handleStateRootError(ctx context.Context, block interfaces.SignedBeaconBlock, err error) ([]byte, error) {
if ctx.Err() != nil {
return nil, status.Errorf(codes.Canceled, "context error: %v", ctx.Err())
}
switch {
case errors.Is(err, transition.ErrAttestationsSignatureInvalid),
errors.Is(err, transition.ErrProcessAttestationsFailed):
log.WithError(err).Warn("Retrying block construction without attestations")
if err := block.SetAttestations([]ethpb.Att{}); err != nil {
return nil, errors.Wrap(err, "could not set attestations")
}
case errors.Is(err, transition.ErrProcessBLSChangesFailed), errors.Is(err, transition.ErrBLSToExecutionChangesSignatureInvalid):
log.WithError(err).Warn("Retrying block construction without BLS to execution changes")
if err := block.SetBLSToExecutionChanges([]*ethpb.SignedBLSToExecutionChange{}); err != nil {
return nil, errors.Wrap(err, "could not set BLS to execution changes")
}
case errors.Is(err, transition.ErrProcessProposerSlashingsFailed):
log.WithError(err).Warn("Retrying block construction without proposer slashings")
block.SetProposerSlashings([]*ethpb.ProposerSlashing{})
case errors.Is(err, transition.ErrProcessAttesterSlashingsFailed):
log.WithError(err).Warn("Retrying block construction without attester slashings")
if err := block.SetAttesterSlashings([]ethpb.AttSlashing{}); err != nil {
return nil, errors.Wrap(err, "could not set attester slashings")
}
case errors.Is(err, transition.ErrProcessVoluntaryExitsFailed):
log.WithError(err).Warn("Retrying block construction without voluntary exits")
block.SetVoluntaryExits([]*ethpb.SignedVoluntaryExit{})
case errors.Is(err, transition.ErrProcessSyncAggregateFailed):
log.WithError(err).Warn("Retrying block construction without sync aggregate")
emptySig := [96]byte{0xC0}
emptyAggregate := &ethpb.SyncAggregate{
SyncCommitteeBits: make([]byte, params.BeaconConfig().SyncCommitteeSize/8),
SyncCommitteeSignature: emptySig[:],
}
if err := block.SetSyncAggregate(emptyAggregate); err != nil {
log.WithError(err).Error("Could not set sync aggregate")
}
default:
return nil, errors.Wrap(err, "could not compute state root")
}
// prevent deep recursion by limiting max attempts.
if v, ok := ctx.Value(computeStateRootAttemptsKey).(int); !ok {
ctx = context.WithValue(ctx, computeStateRootAttemptsKey, int(1))
} else if v >= maxComputeStateRootAttempts {
return nil, fmt.Errorf("attempted max compute state root attempts %d", maxComputeStateRootAttempts)
} else {
ctx = context.WithValue(ctx, computeStateRootAttemptsKey, v+1)
}
// recursive call to compute state root again
return vs.computeStateRoot(ctx, block)
}
// Deprecated: The gRPC API will remain the default and fully supported through v8 (expected in 2026) but will be eventually removed in favor of REST API.
//
// SubmitValidatorRegistrations submits validator registrations.

View File

@@ -1313,59 +1313,6 @@ func TestProposer_ComputeStateRoot_OK(t *testing.T) {
require.NoError(t, err)
}
func TestHandleStateRootError_MaxAttemptsReached(t *testing.T) {
// Test that handleStateRootError returns an error when max attempts is reached
// instead of recursing infinitely.
ctx := t.Context()
vs := &Server{}
// Create a minimal block for testing
blk := util.NewBeaconBlock()
wsb, err := blocks.NewSignedBeaconBlock(blk)
require.NoError(t, err)
// Pre-seed the context with max attempts already reached
ctx = context.WithValue(ctx, computeStateRootAttemptsKey, maxComputeStateRootAttempts)
// Call handleStateRootError with a retryable error
_, err = vs.handleStateRootError(ctx, wsb, transition.ErrAttestationsSignatureInvalid)
// Should return an error about max attempts instead of recursing
require.ErrorContains(t, "attempted max compute state root attempts", err)
}
func TestHandleStateRootError_IncrementsAttempts(t *testing.T) {
// Test that handleStateRootError properly increments the attempts counter
// and eventually fails after max attempts.
db := dbutil.SetupDB(t)
ctx := t.Context()
beaconState, parentRoot, _ := util.DeterministicGenesisStateWithGenesisBlock(t, ctx, db, 100)
stateGen := stategen.New(db, doublylinkedtree.New())
vs := &Server{
StateGen: stateGen,
}
// Create a block that will trigger retries
blk := util.NewBeaconBlock()
blk.Block.ParentRoot = parentRoot[:]
blk.Block.Slot = 1
wsb, err := blocks.NewSignedBeaconBlock(blk)
require.NoError(t, err)
// Add a state for the parent root so StateByRoot succeeds
require.NoError(t, stateGen.SaveState(ctx, parentRoot, beaconState))
// Call handleStateRootError with a retryable error - it will recurse
// but eventually hit the max attempts limit since CalculateStateRoot
// will keep failing (no valid attestations, randao, etc.)
_, err = vs.handleStateRootError(ctx, wsb, transition.ErrAttestationsSignatureInvalid)
// Should eventually fail - either with max attempts or another error
require.NotNil(t, err)
}
func TestProposer_PendingDeposits_Eth1DataVoteOK(t *testing.T) {
ctx := t.Context()

View File

@@ -11,7 +11,6 @@ go_library(
visibility = ["//visibility:public"],
deps = [
"//beacon-chain/state/state-native/custom-types:go_default_library",
"//beacon-chain/state/state-native/types:go_default_library",
"//config/fieldparams:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//consensus-types/primitives:go_default_library",

View File

@@ -10,7 +10,6 @@ import (
"github.com/OffchainLabs/go-bitfield"
customtypes "github.com/OffchainLabs/prysm/v7/beacon-chain/state/state-native/custom-types"
"github.com/OffchainLabs/prysm/v7/beacon-chain/state/state-native/types"
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
@@ -44,8 +43,6 @@ type Prover interface {
FinalizedRootProof(ctx context.Context) ([][]byte, error)
CurrentSyncCommitteeProof(ctx context.Context) ([][]byte, error)
NextSyncCommitteeProof(ctx context.Context) ([][]byte, error)
ProofByFieldIndex(ctx context.Context, f types.FieldIndex) ([][]byte, error)
}
// ReadOnlyBeaconState defines a struct which only has read access to beacon state methods.

View File

@@ -5,7 +5,6 @@ import (
"encoding/binary"
"github.com/OffchainLabs/prysm/v7/beacon-chain/state/state-native/types"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/container/trie"
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v7/runtime/version"
@@ -40,51 +39,33 @@ func (b *BeaconState) NextSyncCommitteeGeneralizedIndex() (uint64, error) {
// CurrentSyncCommitteeProof from the state's Merkle trie representation.
func (b *BeaconState) CurrentSyncCommitteeProof(ctx context.Context) ([][]byte, error) {
return b.ProofByFieldIndex(ctx, types.CurrentSyncCommittee)
b.lock.Lock()
defer b.lock.Unlock()
if b.version == version.Phase0 {
return nil, errNotSupported("CurrentSyncCommitteeProof", b.version)
}
// In case the Merkle layers of the trie are not populated, we need
// to perform some initialization.
if err := b.initializeMerkleLayers(ctx); err != nil {
return nil, err
}
// Our beacon state uses a "dirty" fields pattern which requires us to
// recompute branches of the Merkle layers that are marked as dirty.
if err := b.recomputeDirtyFields(ctx); err != nil {
return nil, err
}
return trie.ProofFromMerkleLayers(b.merkleLayers, types.CurrentSyncCommittee.RealPosition()), nil
}
// NextSyncCommitteeProof from the state's Merkle trie representation.
func (b *BeaconState) NextSyncCommitteeProof(ctx context.Context) ([][]byte, error) {
return b.ProofByFieldIndex(ctx, types.NextSyncCommittee)
}
// FinalizedRootProof crafts a Merkle proof for the finalized root
// contained within the finalized checkpoint of a beacon state.
func (b *BeaconState) FinalizedRootProof(ctx context.Context) ([][]byte, error) {
b.lock.Lock()
defer b.lock.Unlock()
branchProof, err := b.proofByFieldIndex(ctx, types.FinalizedCheckpoint)
if err != nil {
return nil, err
}
// The epoch field of a finalized checkpoint is the neighbor
// index of the finalized root field in its Merkle tree representation
// of the checkpoint. This neighbor is the first element added to the proof.
epochBuf := make([]byte, 8)
binary.LittleEndian.PutUint64(epochBuf, uint64(b.finalizedCheckpointVal().Epoch))
epochRoot := bytesutil.ToBytes32(epochBuf)
proof := make([][]byte, 0)
proof = append(proof, epochRoot[:])
proof = append(proof, branchProof...)
return proof, nil
}
// ProofByFieldIndex constructs proofs for given field index with lock acquisition.
func (b *BeaconState) ProofByFieldIndex(ctx context.Context, f types.FieldIndex) ([][]byte, error) {
b.lock.Lock()
defer b.lock.Unlock()
return b.proofByFieldIndex(ctx, f)
}
// proofByFieldIndex constructs proofs for given field index.
// Important: it is assumed that beacon state mutex is locked when calling this method.
func (b *BeaconState) proofByFieldIndex(ctx context.Context, f types.FieldIndex) ([][]byte, error) {
err := b.validateFieldIndex(f)
if err != nil {
return nil, err
if b.version == version.Phase0 {
return nil, errNotSupported("NextSyncCommitteeProof", b.version)
}
if err := b.initializeMerkleLayers(ctx); err != nil {
@@ -93,40 +74,35 @@ func (b *BeaconState) proofByFieldIndex(ctx context.Context, f types.FieldIndex)
if err := b.recomputeDirtyFields(ctx); err != nil {
return nil, err
}
return trie.ProofFromMerkleLayers(b.merkleLayers, f.RealPosition()), nil
return trie.ProofFromMerkleLayers(b.merkleLayers, types.NextSyncCommittee.RealPosition()), nil
}
func (b *BeaconState) validateFieldIndex(f types.FieldIndex) error {
switch b.version {
case version.Phase0:
if f.RealPosition() > params.BeaconConfig().BeaconStateFieldCount-1 {
return errNotSupported(f.String(), b.version)
}
case version.Altair:
if f.RealPosition() > params.BeaconConfig().BeaconStateAltairFieldCount-1 {
return errNotSupported(f.String(), b.version)
}
case version.Bellatrix:
if f.RealPosition() > params.BeaconConfig().BeaconStateBellatrixFieldCount-1 {
return errNotSupported(f.String(), b.version)
}
case version.Capella:
if f.RealPosition() > params.BeaconConfig().BeaconStateCapellaFieldCount-1 {
return errNotSupported(f.String(), b.version)
}
case version.Deneb:
if f.RealPosition() > params.BeaconConfig().BeaconStateDenebFieldCount-1 {
return errNotSupported(f.String(), b.version)
}
case version.Electra:
if f.RealPosition() > params.BeaconConfig().BeaconStateElectraFieldCount-1 {
return errNotSupported(f.String(), b.version)
}
case version.Fulu:
if f.RealPosition() > params.BeaconConfig().BeaconStateFuluFieldCount-1 {
return errNotSupported(f.String(), b.version)
}
// FinalizedRootProof crafts a Merkle proof for the finalized root
// contained within the finalized checkpoint of a beacon state.
func (b *BeaconState) FinalizedRootProof(ctx context.Context) ([][]byte, error) {
b.lock.Lock()
defer b.lock.Unlock()
if b.version == version.Phase0 {
return nil, errNotSupported("FinalizedRootProof", b.version)
}
return nil
if err := b.initializeMerkleLayers(ctx); err != nil {
return nil, err
}
if err := b.recomputeDirtyFields(ctx); err != nil {
return nil, err
}
cpt := b.finalizedCheckpointVal()
// The epoch field of a finalized checkpoint is the neighbor
// index of the finalized root field in its Merkle tree representation
// of the checkpoint. This neighbor is the first element added to the proof.
epochBuf := make([]byte, 8)
binary.LittleEndian.PutUint64(epochBuf, uint64(cpt.Epoch))
epochRoot := bytesutil.ToBytes32(epochBuf)
proof := make([][]byte, 0)
proof = append(proof, epochRoot[:])
branch := trie.ProofFromMerkleLayers(b.merkleLayers, types.FinalizedCheckpoint.RealPosition())
proof = append(proof, branch...)
return proof, nil
}

View File

@@ -21,6 +21,10 @@ func TestBeaconStateMerkleProofs_phase0_notsupported(t *testing.T) {
_, err := st.NextSyncCommitteeProof(ctx)
require.ErrorContains(t, "not supported", err)
})
t.Run("finalized root", func(t *testing.T) {
_, err := st.FinalizedRootProof(ctx)
require.ErrorContains(t, "not supported", err)
})
}
func TestBeaconStateMerkleProofs_altair(t *testing.T) {
ctx := t.Context()

View File

@@ -29,7 +29,6 @@ go_library(
"//beacon-chain/state:go_default_library",
"//beacon-chain/sync/backfill/coverage:go_default_library",
"//cache/lru:go_default_library",
"//config/features:go_default_library",
"//config/params:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/interfaces:go_default_library",
@@ -69,14 +68,11 @@ go_test(
"//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/core/transition:go_default_library",
"//beacon-chain/db:go_default_library",
"//beacon-chain/db/kv:go_default_library",
"//beacon-chain/db/testing:go_default_library",
"//beacon-chain/forkchoice/doubly-linked-tree:go_default_library",
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/state-native:go_default_library",
"//beacon-chain/state/testing:go_default_library",
"//cmd/beacon-chain/flags:go_default_library",
"//config/features:go_default_library",
"//config/params:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/blocks/testing:go_default_library",

View File

@@ -5,13 +5,10 @@ import (
"encoding/hex"
"fmt"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/transition"
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
"github.com/OffchainLabs/prysm/v7/config/features"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v7/monitoring/tracing/trace"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -28,10 +25,6 @@ func (s *State) MigrateToCold(ctx context.Context, fRoot [32]byte) error {
s.migrationLock.Lock()
defer s.migrationLock.Unlock()
if features.Get().EnableStateDiff {
return s.migrateToColdHdiff(ctx, fRoot)
}
s.finalizedInfo.lock.RLock()
oldFSlot := s.finalizedInfo.slot
s.finalizedInfo.lock.RUnlock()
@@ -97,8 +90,21 @@ func (s *State) MigrateToCold(ctx context.Context, fRoot [32]byte) error {
}
}
}
if s.beaconDB.HasState(ctx, aRoot) {
s.migrateHotToCold(aRoot)
// If you are migrating a state and its already part of the hot state cache saved to the db,
// you can just remove it from the hot state cache as it becomes redundant.
s.saveHotStateDB.lock.Lock()
roots := s.saveHotStateDB.blockRootsOfSavedStates
for i := range roots {
if aRoot == roots[i] {
s.saveHotStateDB.blockRootsOfSavedStates = append(roots[:i], roots[i+1:]...)
// There shouldn't be duplicated roots in `blockRootsOfSavedStates`.
// Break here is ok.
break
}
}
s.saveHotStateDB.lock.Unlock()
continue
}
@@ -123,103 +129,3 @@ func (s *State) MigrateToCold(ctx context.Context, fRoot [32]byte) error {
return nil
}
// migrateToColdHdiff saves the state-diffs for slots that are in the state diff tree after finalization
func (s *State) migrateToColdHdiff(ctx context.Context, fRoot [32]byte) error {
s.finalizedInfo.lock.RLock()
oldFSlot := s.finalizedInfo.slot
s.finalizedInfo.lock.RUnlock()
fSlot, err := s.beaconDB.SlotByBlockRoot(ctx, fRoot)
if err != nil {
return errors.Wrap(err, "could not get slot by block root")
}
for slot := oldFSlot; slot < fSlot; slot++ {
if ctx.Err() != nil {
return ctx.Err()
}
_, lvl, err := s.beaconDB.SlotInDiffTree(slot)
if err != nil {
log.WithError(err).Errorf("could not determine if slot %d is in diff tree", slot)
continue
}
if lvl == -1 {
continue
}
// The state needs to be saved.
// Try the epoch boundary cache first.
cached, exists, err := s.epochBoundaryStateCache.getBySlot(slot)
if err != nil {
log.WithError(err).Errorf("could not get epoch boundary state for slot %d", slot)
cached = nil
exists = false
}
var aRoot [32]byte
var aState state.BeaconState
if exists {
aRoot = cached.root
aState = cached.state
} else {
_, roots, err := s.beaconDB.HighestRootsBelowSlot(ctx, slot)
if err != nil {
return err
}
// Given the block has been finalized, the db should not have more than one block in a given slot.
// We should error out when this happens.
if len(roots) != 1 {
return errUnknownBlock
}
aRoot = roots[0]
// Different than the legacy MigrateToCold, we need to always get the state even if
// the state exists in DB as part of the hot state db, because we need to process slots
// to the state diff tree slots.
aState, err = s.StateByRoot(ctx, aRoot)
if err != nil {
return err
}
}
if s.beaconDB.HasState(ctx, aRoot) {
s.migrateHotToCold(aRoot)
continue
}
// advance slots to the target slot
if aState.Slot() < slot {
aState, err = transition.ProcessSlots(ctx, aState, slot)
if err != nil {
return errors.Wrapf(err, "could not process slots to slot %d", slot)
}
}
if err := s.beaconDB.SaveState(ctx, aState, aRoot); err != nil {
return err
}
log.WithFields(
logrus.Fields{
"slot": aState.Slot(),
"root": fmt.Sprintf("%#x", aRoot),
}).Info("Saved state in DB")
}
// Update finalized info in memory.
fInfo, ok, err := s.epochBoundaryStateCache.getByBlockRoot(fRoot)
if err != nil {
return err
}
if ok {
s.SaveFinalizedState(fSlot, fRoot, fInfo.state)
}
return nil
}
func (s *State) migrateHotToCold(aRoot [32]byte) {
// If you are migrating a state and its already part of the hot state cache saved to the db,
// you can just remove it from the hot state cache as it becomes redundant.
s.saveHotStateDB.lock.Lock()
roots := s.saveHotStateDB.blockRootsOfSavedStates
for i := range roots {
if aRoot == roots[i] {
s.saveHotStateDB.blockRootsOfSavedStates = append(roots[:i], roots[i+1:]...)
// There shouldn't be duplicated roots in `blockRootsOfSavedStates`.
// Break here is ok.
break
}
}
s.saveHotStateDB.lock.Unlock()
}

View File

@@ -4,11 +4,8 @@ import (
"testing"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/blocks"
"github.com/OffchainLabs/prysm/v7/beacon-chain/db/kv"
testDB "github.com/OffchainLabs/prysm/v7/beacon-chain/db/testing"
doublylinkedtree "github.com/OffchainLabs/prysm/v7/beacon-chain/forkchoice/doubly-linked-tree"
"github.com/OffchainLabs/prysm/v7/cmd/beacon-chain/flags"
"github.com/OffchainLabs/prysm/v7/config/features"
consensusblocks "github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
@@ -227,170 +224,3 @@ func TestMigrateToCold_ParallelCalls(t *testing.T) {
assert.DeepEqual(t, [][32]byte{r7}, service.saveHotStateDB.blockRootsOfSavedStates, "Did not remove all saved hot state roots")
require.LogsContain(t, hook, "Saved state in DB")
}
// =========================================================================
// Tests for migrateToColdHdiff (state diff migration)
// =========================================================================
// setStateDiffExponents sets state diff exponents for testing.
// Uses exponents [6, 5] which means:
// - Level 0: Every 2^6 = 64 slots (full snapshot)
// - Level 1: Every 2^5 = 32 slots (diff)
func setStateDiffExponents() {
globalFlags := flags.GlobalFlags{
StateDiffExponents: []int{6, 5},
}
flags.Init(&globalFlags)
}
// TestMigrateToColdHdiff_CanUpdateFinalizedInfo verifies that the migration
// correctly updates finalized info when migrating to slots not in the diff tree.
func TestMigrateToColdHdiff_CanUpdateFinalizedInfo(t *testing.T) {
ctx := t.Context()
// Set exponents and create DB first (without EnableStateDiff flag).
setStateDiffExponents()
beaconDB := testDB.SetupDB(t)
// Initialize the state diff cache via the method on *kv.Store (not in interface).
require.NoError(t, beaconDB.(*kv.Store).InitStateDiffCacheForTesting(t, 0))
// Now enable the feature flag.
resetCfg := features.InitWithReset(&features.Flags{EnableStateDiff: true})
defer resetCfg()
service := New(beaconDB, doublylinkedtree.New())
beaconState, _ := util.DeterministicGenesisState(t, 32)
genesisStateRoot, err := beaconState.HashTreeRoot(ctx)
require.NoError(t, err)
genesis := blocks.NewGenesisBlock(genesisStateRoot[:])
util.SaveBlock(t, ctx, beaconDB, genesis)
gRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err)
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, gRoot))
// Put genesis state in epoch boundary cache so migrateToColdHdiff doesn't need to retrieve from DB.
require.NoError(t, service.epochBoundaryStateCache.put(gRoot, beaconState))
// Set initial finalized info at genesis.
service.finalizedInfo = &finalizedInfo{
slot: 0,
root: gRoot,
state: beaconState,
}
// Create finalized block at slot 10 (not in diff tree, so no intermediate states saved).
finalizedState := beaconState.Copy()
require.NoError(t, finalizedState.SetSlot(10))
b := util.NewBeaconBlock()
b.Block.Slot = 10
fRoot, err := b.Block.HashTreeRoot()
require.NoError(t, err)
util.SaveBlock(t, ctx, beaconDB, b)
require.NoError(t, service.epochBoundaryStateCache.put(fRoot, finalizedState))
require.NoError(t, service.MigrateToCold(ctx, fRoot))
// Verify finalized info is updated.
assert.Equal(t, primitives.Slot(10), service.finalizedInfo.slot)
assert.DeepEqual(t, fRoot, service.finalizedInfo.root)
expectedHTR, err := finalizedState.HashTreeRoot(ctx)
require.NoError(t, err)
actualHTR, err := service.finalizedInfo.state.HashTreeRoot(ctx)
require.NoError(t, err)
assert.DeepEqual(t, expectedHTR, actualHTR)
}
// TestMigrateToColdHdiff_SkipsSlotsNotInDiffTree verifies that the migration
// skips slots that are not in the diff tree.
func TestMigrateToColdHdiff_SkipsSlotsNotInDiffTree(t *testing.T) {
hook := logTest.NewGlobal()
ctx := t.Context()
// Set exponents and create DB first (without EnableStateDiff flag).
setStateDiffExponents()
beaconDB := testDB.SetupDB(t)
// Initialize the state diff cache via the method on *kv.Store (not in interface).
require.NoError(t, beaconDB.(*kv.Store).InitStateDiffCacheForTesting(t, 0))
// Now enable the feature flag.
resetCfg := features.InitWithReset(&features.Flags{EnableStateDiff: true})
defer resetCfg()
service := New(beaconDB, doublylinkedtree.New())
beaconState, pks := util.DeterministicGenesisState(t, 32)
genesisStateRoot, err := beaconState.HashTreeRoot(ctx)
require.NoError(t, err)
genesis := blocks.NewGenesisBlock(genesisStateRoot[:])
util.SaveBlock(t, ctx, beaconDB, genesis)
gRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err)
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, gRoot))
// Start from slot 1 to avoid slot 0 which is in the diff tree.
service.finalizedInfo = &finalizedInfo{
slot: 1,
root: gRoot,
state: beaconState,
}
// Reset the log hook to ignore setup logs.
hook.Reset()
// Create a block at slot 20 (NOT in diff tree with exponents [6,5]).
b20, err := util.GenerateFullBlock(beaconState, pks, util.DefaultBlockGenConfig(), 20)
require.NoError(t, err)
r20, err := b20.Block.HashTreeRoot()
require.NoError(t, err)
util.SaveBlock(t, ctx, beaconDB, b20)
require.NoError(t, beaconDB.SaveStateSummary(ctx, &ethpb.StateSummary{Slot: 20, Root: r20[:]}))
// Put finalized state in cache.
finalizedState := beaconState.Copy()
require.NoError(t, finalizedState.SetSlot(20))
require.NoError(t, service.epochBoundaryStateCache.put(r20, finalizedState))
require.NoError(t, service.MigrateToCold(ctx, r20))
// Verify NO states were saved during migration (slots 1-19 are not in diff tree).
assert.LogsDoNotContain(t, hook, "Saved state in DB")
}
// TestMigrateToColdHdiff_NoOpWhenFinalizedSlotNotAdvanced verifies that
// migration is a no-op when the finalized slot has not advanced.
func TestMigrateToColdHdiff_NoOpWhenFinalizedSlotNotAdvanced(t *testing.T) {
ctx := t.Context()
// Set exponents and create DB first (without EnableStateDiff flag).
setStateDiffExponents()
beaconDB := testDB.SetupDB(t)
// Initialize the state diff cache via the method on *kv.Store (not in interface).
require.NoError(t, beaconDB.(*kv.Store).InitStateDiffCacheForTesting(t, 0))
// Now enable the feature flag.
resetCfg := features.InitWithReset(&features.Flags{EnableStateDiff: true})
defer resetCfg()
service := New(beaconDB, doublylinkedtree.New())
beaconState, _ := util.DeterministicGenesisState(t, 32)
genesisStateRoot, err := beaconState.HashTreeRoot(ctx)
require.NoError(t, err)
genesis := blocks.NewGenesisBlock(genesisStateRoot[:])
util.SaveBlock(t, ctx, beaconDB, genesis)
gRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err)
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, gRoot))
// Set finalized info already at slot 50.
finalizedState := beaconState.Copy()
require.NoError(t, finalizedState.SetSlot(50))
service.finalizedInfo = &finalizedInfo{
slot: 50,
root: gRoot,
state: finalizedState,
}
// Create block at same slot 50.
b := util.NewBeaconBlock()
b.Block.Slot = 50
fRoot, err := b.Block.HashTreeRoot()
require.NoError(t, err)
util.SaveBlock(t, ctx, beaconDB, b)
require.NoError(t, service.epochBoundaryStateCache.put(fRoot, finalizedState))
// Migration should be a no-op (finalized slot not advancing).
require.NoError(t, service.MigrateToCold(ctx, fRoot))
}

View File

@@ -10,72 +10,20 @@ import (
"github.com/OffchainLabs/prysm/v7/beacon-chain/p2p"
"github.com/OffchainLabs/prysm/v7/cmd/beacon-chain/flags"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/time/slots"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
var nilFinalizedStateError = errors.New("finalized state is nil")
func (s *Service) maintainCustodyInfo() error {
// Rationale of slot choice:
// - If syncing with an empty DB from genesis, then justifiedSlot = finalizedSlot = 0,
// and the node starts to sync from slot 0 ==> Using justifiedSlot is correct.
// - If syncing with an empty DB from a checkpoint, then justifiedSlot = finalizedSlot = checkpointSlot,
// and the node starts to sync from checkpointSlot ==> Using justifiedSlot is correct.
// - If syncing with a non-empty DB, then justifiedSlot > finalizedSlot,
// and the node starts to sync from justifiedSlot + 1 ==> Using justifiedSlot + 1 is correct.
func (s *Service) maintainCustodyInfo() {
const interval = 1 * time.Minute
finalizedCheckpoint, err := s.cfg.beaconDB.FinalizedCheckpoint(s.ctx)
if err != nil {
return errors.Wrap(err, "finalized checkpoint")
}
if finalizedCheckpoint == nil {
return errors.New("finalized checkpoint is nil")
}
finalizedSlot, err := slots.EpochStart(finalizedCheckpoint.Epoch)
if err != nil {
return errors.Wrap(err, "epoch start for finalized slot")
}
justifiedCheckpoint, err := s.cfg.beaconDB.JustifiedCheckpoint(s.ctx)
if err != nil {
return errors.Wrap(err, "justified checkpoint")
}
if justifiedCheckpoint == nil {
return errors.New("justified checkpoint is nil")
}
justifiedSlot, err := slots.EpochStart(justifiedCheckpoint.Epoch)
if err != nil {
return errors.Wrap(err, "epoch start for justified slot")
}
slot := justifiedSlot
if justifiedSlot > finalizedSlot {
slot++
}
earliestAvailableSlot, custodySubnetCount, err := s.updateCustodyInfoInDB(slot)
if err != nil {
return errors.Wrap(err, "could not get and save custody group count")
}
if _, _, err := s.cfg.p2p.UpdateCustodyInfo(earliestAvailableSlot, custodySubnetCount); err != nil {
return errors.Wrap(err, "update custody info")
}
async.RunEvery(s.ctx, interval, func() {
if err := s.updateCustodyInfoIfNeeded(); err != nil {
log.WithError(err).Error("Failed to update custody info")
}
})
return nil
}
func (s *Service) updateCustodyInfoIfNeeded() error {

View File

@@ -12,7 +12,6 @@ import (
mock "github.com/OffchainLabs/prysm/v7/beacon-chain/blockchain/testing"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/transition"
"github.com/OffchainLabs/prysm/v7/beacon-chain/db/kv"
dbTest "github.com/OffchainLabs/prysm/v7/beacon-chain/db/testing"
testingDB "github.com/OffchainLabs/prysm/v7/beacon-chain/db/testing"
"github.com/OffchainLabs/prysm/v7/beacon-chain/p2p"
"github.com/OffchainLabs/prysm/v7/beacon-chain/p2p/peers"
@@ -935,7 +934,6 @@ func TestStatusRPCRequest_BadPeerHandshake(t *testing.T) {
r := &Service{
cfg: &config{
p2p: p1,
beaconDB: dbTest.SetupDB(t),
chain: chain,
stateNotifier: chain.StateNotifier(),
initialSync: &mockSync.Sync{IsSyncing: false},

View File

@@ -17,7 +17,6 @@ import (
blockfeed "github.com/OffchainLabs/prysm/v7/beacon-chain/core/feed/block"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/feed/operation"
statefeed "github.com/OffchainLabs/prysm/v7/beacon-chain/core/feed/state"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/peerdas"
"github.com/OffchainLabs/prysm/v7/beacon-chain/db"
"github.com/OffchainLabs/prysm/v7/beacon-chain/db/filesystem"
"github.com/OffchainLabs/prysm/v7/beacon-chain/execution"
@@ -34,11 +33,9 @@ import (
"github.com/OffchainLabs/prysm/v7/beacon-chain/sync/backfill/coverage"
"github.com/OffchainLabs/prysm/v7/beacon-chain/verification"
lruwrpr "github.com/OffchainLabs/prysm/v7/cache/lru"
"github.com/OffchainLabs/prysm/v7/cmd/beacon-chain/flags"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
leakybucket "github.com/OffchainLabs/prysm/v7/container/leaky-bucket"
"github.com/OffchainLabs/prysm/v7/crypto/rand"
"github.com/OffchainLabs/prysm/v7/runtime"
@@ -278,6 +275,11 @@ func (s *Service) Start() {
s.processPendingBlocksQueue()
s.maintainPeerStatuses()
if params.FuluEnabled() {
s.maintainCustodyInfo()
}
s.resyncIfBehind()
// Update sync metrics.
@@ -285,15 +287,6 @@ func (s *Service) Start() {
// Prune data column cache periodically on finalization.
async.RunEvery(s.ctx, 30*time.Second, s.pruneDataColumnCache)
if !params.FuluEnabled() {
return
}
if err := s.maintainCustodyInfo(); err != nil {
log.WithError(err).Error("Failed to maintain custody info")
}
}
// Stop the regular sync service.
@@ -459,89 +452,6 @@ func (s *Service) waitForInitialSync(ctx context.Context) error {
}
}
// UpdateCustodyInfoInDB updates the custody information in the database.
// It returns the (potentially updated) custody group count and the earliest available slot.
func (s *Service) updateCustodyInfoInDB(slot primitives.Slot) (primitives.Slot, uint64, error) {
isSupernode := flags.Get().Supernode
isSemiSupernode := flags.Get().SemiSupernode
cfg := params.BeaconConfig()
custodyRequirement := cfg.CustodyRequirement
// Check if the node was previously subscribed to all data subnets, and if so,
// store the new status accordingly.
wasSupernode, err := s.cfg.beaconDB.UpdateSubscribedToAllDataSubnets(s.ctx, isSupernode)
if err != nil {
return 0, 0, errors.Wrap(err, "update subscribed to all data subnets")
}
// Compute the target custody group count based on current flag configuration.
targetCustodyGroupCount := custodyRequirement
// Supernode: custody all groups (either currently set or previously enabled)
if isSupernode {
targetCustodyGroupCount = cfg.NumberOfCustodyGroups
}
// Semi-supernode: custody minimum needed for reconstruction, or custody requirement if higher
if isSemiSupernode {
semiSupernodeCustody, err := peerdas.MinimumCustodyGroupCountToReconstruct()
if err != nil {
return 0, 0, errors.Wrap(err, "minimum custody group count")
}
targetCustodyGroupCount = max(custodyRequirement, semiSupernodeCustody)
}
// Safely compute the fulu fork slot.
fuluForkSlot, err := fuluForkSlot()
if err != nil {
return 0, 0, errors.Wrap(err, "fulu fork slot")
}
// If slot is before the fulu fork slot, then use the earliest stored slot as the reference slot.
if slot < fuluForkSlot {
slot, err = s.cfg.beaconDB.EarliestSlot(s.ctx)
if err != nil {
return 0, 0, errors.Wrap(err, "earliest slot")
}
}
earliestAvailableSlot, actualCustodyGroupCount, err := s.cfg.beaconDB.UpdateCustodyInfo(s.ctx, slot, targetCustodyGroupCount)
if err != nil {
return 0, 0, errors.Wrap(err, "update custody info")
}
if isSupernode {
log.WithFields(logrus.Fields{
"current": actualCustodyGroupCount,
"target": cfg.NumberOfCustodyGroups,
}).Info("Supernode mode enabled. Will custody all data columns going forward.")
}
if wasSupernode && !isSupernode {
log.Warningf("Because the `--%s` flag was previously used, the node will continue to act as a super node.", flags.Supernode.Name)
}
return earliestAvailableSlot, actualCustodyGroupCount, nil
}
func fuluForkSlot() (primitives.Slot, error) {
cfg := params.BeaconConfig()
fuluForkEpoch := cfg.FuluForkEpoch
if fuluForkEpoch == cfg.FarFutureEpoch {
return cfg.FarFutureSlot, nil
}
forkFuluSlot, err := slots.EpochStart(fuluForkEpoch)
if err != nil {
return 0, errors.Wrap(err, "epoch start")
}
return forkFuluSlot, nil
}
// Checker defines a struct which can verify whether a node is currently
// synchronizing a chain with the rest of peers in the network.
type Checker interface {

View File

@@ -16,9 +16,6 @@ import (
"github.com/OffchainLabs/prysm/v7/beacon-chain/startup"
state_native "github.com/OffchainLabs/prysm/v7/beacon-chain/state/state-native"
mockSync "github.com/OffchainLabs/prysm/v7/beacon-chain/sync/initial-sync/testing"
"github.com/OffchainLabs/prysm/v7/cmd/beacon-chain/flags"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
leakybucket "github.com/OffchainLabs/prysm/v7/container/leaky-bucket"
"github.com/OffchainLabs/prysm/v7/crypto/bls"
@@ -443,224 +440,3 @@ func TestService_Stop_ConcurrentGoodbyeMessages(t *testing.T) {
require.Equal(t, false, util.WaitTimeout(&wg, 2*time.Second))
}
func TestUpdateCustodyInfoInDB(t *testing.T) {
const (
fuluForkEpoch = 10
custodyRequirement = uint64(4)
earliestStoredSlot = primitives.Slot(12)
numberOfCustodyGroups = uint64(64)
)
params.SetupTestConfigCleanup(t)
cfg := params.BeaconConfig()
cfg.FuluForkEpoch = fuluForkEpoch
cfg.CustodyRequirement = custodyRequirement
cfg.NumberOfCustodyGroups = numberOfCustodyGroups
params.OverrideBeaconConfig(cfg)
ctx := t.Context()
pbBlock := util.NewBeaconBlock()
pbBlock.Block.Slot = 12
signedBeaconBlock, err := blocks.NewSignedBeaconBlock(pbBlock)
require.NoError(t, err)
roBlock, err := blocks.NewROBlock(signedBeaconBlock)
require.NoError(t, err)
t.Run("CGC increases before fulu", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
service := Service{cfg: &config{beaconDB: beaconDB}}
err = beaconDB.SaveBlock(ctx, roBlock)
require.NoError(t, err)
// Before Fulu
// -----------
actualEas, actualCgc, err := service.updateCustodyInfoInDB(15)
require.NoError(t, err)
require.Equal(t, earliestStoredSlot, actualEas)
require.Equal(t, custodyRequirement, actualCgc)
actualEas, actualCgc, err = service.updateCustodyInfoInDB(17)
require.NoError(t, err)
require.Equal(t, earliestStoredSlot, actualEas)
require.Equal(t, custodyRequirement, actualCgc)
resetFlags := flags.Get()
gFlags := new(flags.GlobalFlags)
gFlags.Supernode = true
flags.Init(gFlags)
defer flags.Init(resetFlags)
actualEas, actualCgc, err = service.updateCustodyInfoInDB(19)
require.NoError(t, err)
require.Equal(t, earliestStoredSlot, actualEas)
require.Equal(t, numberOfCustodyGroups, actualCgc)
// After Fulu
// ----------
actualEas, actualCgc, err = service.updateCustodyInfoInDB(fuluForkEpoch*primitives.Slot(cfg.SlotsPerEpoch) + 1)
require.NoError(t, err)
require.Equal(t, earliestStoredSlot, actualEas)
require.Equal(t, numberOfCustodyGroups, actualCgc)
})
t.Run("CGC increases after fulu", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
service := Service{cfg: &config{beaconDB: beaconDB}}
err = beaconDB.SaveBlock(ctx, roBlock)
require.NoError(t, err)
// Before Fulu
// -----------
actualEas, actualCgc, err := service.updateCustodyInfoInDB(15)
require.NoError(t, err)
require.Equal(t, earliestStoredSlot, actualEas)
require.Equal(t, custodyRequirement, actualCgc)
actualEas, actualCgc, err = service.updateCustodyInfoInDB(17)
require.NoError(t, err)
require.Equal(t, earliestStoredSlot, actualEas)
require.Equal(t, custodyRequirement, actualCgc)
// After Fulu
// ----------
resetFlags := flags.Get()
gFlags := new(flags.GlobalFlags)
gFlags.Supernode = true
flags.Init(gFlags)
defer flags.Init(resetFlags)
slot := fuluForkEpoch*primitives.Slot(cfg.SlotsPerEpoch) + 1
actualEas, actualCgc, err = service.updateCustodyInfoInDB(slot)
require.NoError(t, err)
require.Equal(t, slot, actualEas)
require.Equal(t, numberOfCustodyGroups, actualCgc)
actualEas, actualCgc, err = service.updateCustodyInfoInDB(slot + 2)
require.NoError(t, err)
require.Equal(t, slot, actualEas)
require.Equal(t, numberOfCustodyGroups, actualCgc)
})
t.Run("Supernode downgrade prevented", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
service := Service{cfg: &config{beaconDB: beaconDB}}
err = beaconDB.SaveBlock(ctx, roBlock)
require.NoError(t, err)
// Enable supernode
resetFlags := flags.Get()
gFlags := new(flags.GlobalFlags)
gFlags.Supernode = true
flags.Init(gFlags)
slot := fuluForkEpoch*primitives.Slot(cfg.SlotsPerEpoch) + 1
actualEas, actualCgc, err := service.updateCustodyInfoInDB(slot)
require.NoError(t, err)
require.Equal(t, slot, actualEas)
require.Equal(t, numberOfCustodyGroups, actualCgc)
// Try to downgrade by removing flag
gFlags.Supernode = false
flags.Init(gFlags)
defer flags.Init(resetFlags)
// Should still be supernode
actualEas, actualCgc, err = service.updateCustodyInfoInDB(slot + 2)
require.NoError(t, err)
require.Equal(t, slot, actualEas)
require.Equal(t, numberOfCustodyGroups, actualCgc) // Still 64, not downgraded
})
t.Run("Semi-supernode downgrade prevented", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
service := Service{cfg: &config{beaconDB: beaconDB}}
err = beaconDB.SaveBlock(ctx, roBlock)
require.NoError(t, err)
// Enable semi-supernode
resetFlags := flags.Get()
gFlags := new(flags.GlobalFlags)
gFlags.SemiSupernode = true
flags.Init(gFlags)
slot := fuluForkEpoch*primitives.Slot(cfg.SlotsPerEpoch) + 1
actualEas, actualCgc, err := service.updateCustodyInfoInDB(slot)
require.NoError(t, err)
require.Equal(t, slot, actualEas)
semiSupernodeCustody := numberOfCustodyGroups / 2 // 64
require.Equal(t, semiSupernodeCustody, actualCgc) // Semi-supernode custodies 64 groups
// Try to downgrade by removing flag
gFlags.SemiSupernode = false
flags.Init(gFlags)
defer flags.Init(resetFlags)
// UpdateCustodyInfo should prevent downgrade - custody count should remain at 64
actualEas, actualCgc, err = service.updateCustodyInfoInDB(slot + 2)
require.NoError(t, err)
require.Equal(t, slot, actualEas)
require.Equal(t, semiSupernodeCustody, actualCgc) // Still 64 due to downgrade prevention by UpdateCustodyInfo
})
t.Run("Semi-supernode to supernode upgrade allowed", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
service := Service{cfg: &config{beaconDB: beaconDB}}
err = beaconDB.SaveBlock(ctx, roBlock)
require.NoError(t, err)
// Start with semi-supernode
resetFlags := flags.Get()
gFlags := new(flags.GlobalFlags)
gFlags.SemiSupernode = true
flags.Init(gFlags)
slot := fuluForkEpoch*primitives.Slot(cfg.SlotsPerEpoch) + 1
actualEas, actualCgc, err := service.updateCustodyInfoInDB(slot)
require.NoError(t, err)
require.Equal(t, slot, actualEas)
semiSupernodeCustody := numberOfCustodyGroups / 2 // 64
require.Equal(t, semiSupernodeCustody, actualCgc) // Semi-supernode custodies 64 groups
// Upgrade to full supernode
gFlags.SemiSupernode = false
gFlags.Supernode = true
flags.Init(gFlags)
defer flags.Init(resetFlags)
// Should upgrade to full supernode
upgradeSlot := slot + 2
actualEas, actualCgc, err = service.updateCustodyInfoInDB(upgradeSlot)
require.NoError(t, err)
require.Equal(t, upgradeSlot, actualEas) // Earliest slot updates when upgrading
require.Equal(t, numberOfCustodyGroups, actualCgc) // Upgraded to 128
})
t.Run("Semi-supernode with high validator requirements uses higher custody", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
service := Service{cfg: &config{beaconDB: beaconDB}}
err = beaconDB.SaveBlock(ctx, roBlock)
require.NoError(t, err)
// Enable semi-supernode
resetFlags := flags.Get()
gFlags := new(flags.GlobalFlags)
gFlags.SemiSupernode = true
flags.Init(gFlags)
defer flags.Init(resetFlags)
// Mock a high custody requirement (simulating many validators)
// We need to override the custody requirement calculation
// For this test, we'll verify the logic by checking if custodyRequirement > 64
// Since custodyRequirement in minimalTestService is 4, we can't test the high case here
// This would require a different test setup with actual validators
slot := fuluForkEpoch*primitives.Slot(cfg.SlotsPerEpoch) + 1
actualEas, actualCgc, err := service.updateCustodyInfoInDB(slot)
require.NoError(t, err)
require.Equal(t, slot, actualEas)
semiSupernodeCustody := numberOfCustodyGroups / 2 // 64
// With low validator requirements (4), should use semi-supernode minimum (64)
require.Equal(t, semiSupernodeCustody, actualCgc)
})
}

View File

@@ -588,12 +588,6 @@ func fcReturnsTargetRoot(root [32]byte) func([32]byte, primitives.Epoch) ([32]by
}
}
func fcReturnsDependentRoot() func([32]byte, primitives.Epoch) ([32]byte, error) {
return func(root [32]byte, epoch primitives.Epoch) ([32]byte, error) {
return root, nil
}
}
type mockSignatureCache struct {
svCalledForSig map[signatureData]bool
svcb func(sig signatureData) (bool, error)

View File

@@ -1,6 +1,7 @@
package verification
import (
"bytes"
"context"
"crypto/sha256"
"fmt"
@@ -18,7 +19,6 @@ import (
"github.com/OffchainLabs/prysm/v7/runtime/logging"
"github.com/OffchainLabs/prysm/v7/time/slots"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
var (
@@ -293,57 +293,55 @@ func (dv *RODataColumnsVerifier) ValidProposerSignature(ctx context.Context) (er
// The returned state is guaranteed to be at the same epoch as the data column's epoch, and have the same randao mix and active
// validator indices as the data column's parent state advanced to the data column's slot.
func (dv *RODataColumnsVerifier) getVerifyingState(ctx context.Context, dataColumn blocks.RODataColumn) (state.ReadOnlyBeaconState, error) {
dataColumnSlot := dataColumn.Slot()
dataColumnEpoch := slots.ToEpoch(dataColumnSlot)
if dataColumnEpoch == 0 {
return dv.hsp.HeadStateReadOnly(ctx)
}
parentRoot := dataColumn.ParentRoot()
dcDependentRoot, err := dv.fc.DependentRootForEpoch(parentRoot, dataColumnEpoch-1)
if err != nil {
return nil, err
}
headRoot, err := dv.hsp.HeadRoot(ctx)
if err != nil {
return nil, err
}
headDependentRoot, err := dv.fc.DependentRootForEpoch(bytesutil.ToBytes32(headRoot), dataColumnEpoch-1)
if err != nil {
return nil, err
}
if dcDependentRoot == headDependentRoot {
headSlot := dv.hsp.HeadSlot()
headEpoch := slots.ToEpoch(headSlot)
if headEpoch == dataColumnEpoch || headEpoch == dataColumnEpoch-1 {
parentRoot := dataColumn.ParentRoot()
dataColumnSlot := dataColumn.Slot()
dataColumnEpoch := slots.ToEpoch(dataColumnSlot)
headSlot := dv.hsp.HeadSlot()
headEpoch := slots.ToEpoch(headSlot)
// Use head if it's the parent
if bytes.Equal(parentRoot[:], headRoot) {
// If they are in the same epoch, then we can return the head state directly
if dataColumnEpoch == headEpoch {
return dv.hsp.HeadStateReadOnly(ctx)
}
if headEpoch+1 < dataColumnEpoch {
headState, err := dv.hsp.HeadState(ctx)
if err != nil {
return nil, err
}
return transition.ProcessSlotsUsingNextSlotCache(ctx, headState, headRoot, dataColumnSlot)
// Otherwise, we need to process the head state to the data column's slot
headState, err := dv.hsp.HeadState(ctx)
if err != nil {
return nil, err
}
return transition.ProcessSlotsUsingNextSlotCache(ctx, headState, headRoot, dataColumnSlot)
}
// If head and data column are in the same epoch and head is compatible with the parent's depdendent root, then use head
if dataColumnEpoch == headEpoch {
headDependent, err := dv.fc.DependentRootForEpoch(bytesutil.ToBytes32(headRoot), dataColumnEpoch)
if err != nil {
return nil, err
}
parentDependent, err := dv.fc.DependentRootForEpoch(parentRoot, dataColumnEpoch)
if err != nil {
return nil, err
}
if bytes.Equal(headDependent[:], parentDependent[:]) {
return dv.hsp.HeadStateReadOnly(ctx)
}
}
logrus.WithFields(logrus.Fields{
"slot": dataColumnSlot,
"parentRoot": fmt.Sprintf("%#x", parentRoot),
"headRoot": fmt.Sprintf("%#x", headRoot),
}).Debug("Replying state for data column verification")
targetRoot, err := dv.fc.TargetRootForEpoch(parentRoot, dataColumnEpoch)
// Otherwise retrieve the parent state and advance it to the data column's slot
parentState, err := dv.sr.StateByRoot(ctx, parentRoot)
if err != nil {
return nil, err
}
targetState, err := dv.sr.StateByRoot(ctx, targetRoot)
if err != nil {
return nil, err
parentEpoch := slots.ToEpoch(parentState.Slot())
if dataColumnEpoch == parentEpoch {
return parentState, nil
}
targetEpoch := slots.ToEpoch(targetState.Slot())
if targetEpoch == dataColumnEpoch || targetEpoch == dataColumnEpoch-1 {
return targetState, nil
}
return transition.ProcessSlotsUsingNextSlotCache(ctx, targetState, parentRoot[:], dataColumnSlot)
return transition.ProcessSlotsUsingNextSlotCache(ctx, parentState, parentRoot[:], dataColumnSlot)
}
func (dv *RODataColumnsVerifier) SidecarParentSeen(parentSeen func([fieldparams.RootLength]byte) bool) (err error) {

View File

@@ -1,7 +1,6 @@
package verification
import (
"context"
"reflect"
"testing"
"time"
@@ -10,7 +9,6 @@ import (
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/peerdas"
forkchoicetypes "github.com/OffchainLabs/prysm/v7/beacon-chain/forkchoice/types"
"github.com/OffchainLabs/prysm/v7/beacon-chain/startup"
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
@@ -283,7 +281,7 @@ func TestColumnSlotAboveFinalized(t *testing.T) {
func TestValidProposerSignature(t *testing.T) {
const (
columnSlot = 97
columnSlot = 0
blobCount = 1
)
@@ -296,83 +294,59 @@ func TestValidProposerSignature(t *testing.T) {
// The signature data does not depend on the data column itself, so we can use the first one.
expectedSignatureData := columnToSignatureData(firstColumn)
// Create a proper Fulu state for verification.
// We need enough validators to cover the proposer index.
numValidators := max(uint64(firstColumn.ProposerIndex()+1), 64)
fuluState, _ := util.DeterministicGenesisStateFulu(t, numValidators)
// Head state provider that returns the fuluState via HeadStateReadOnly path.
headStateWithState := &mockHeadStateProvider{
headRoot: parentRoot[:],
headSlot: columnSlot,
headStateReadOnly: fuluState,
}
// Head state provider that will fail (headStateReadOnly is nil).
headStateNotFound := &mockHeadStateProvider{
headRoot: parentRoot[:],
headSlot: columnSlot,
}
testCases := []struct {
isError bool
vscbShouldError bool
svcbReturn bool
stateByRooter StateByRooter
headStateProvider *mockHeadStateProvider
vscbError error
svcbError error
name string
isError bool
vscbShouldError bool
svcbReturn bool
stateByRooter StateByRooter
vscbError error
svcbError error
name string
}{
{
name: "cache hit - success",
svcbReturn: true,
svcbError: nil,
vscbShouldError: true,
vscbError: nil,
stateByRooter: &mockStateByRooter{sbr: sbrErrorIfCalled(t)},
headStateProvider: headStateWithState,
isError: false,
name: "cache hit - success",
svcbReturn: true,
svcbError: nil,
vscbShouldError: true,
vscbError: nil,
stateByRooter: &mockStateByRooter{sbr: sbrErrorIfCalled(t)},
isError: false,
},
{
name: "cache hit - error",
svcbReturn: true,
svcbError: errors.New("derp"),
vscbShouldError: true,
vscbError: nil,
stateByRooter: &mockStateByRooter{sbr: sbrErrorIfCalled(t)},
headStateProvider: headStateWithState,
isError: true,
name: "cache hit - error",
svcbReturn: true,
svcbError: errors.New("derp"),
vscbShouldError: true,
vscbError: nil,
stateByRooter: &mockStateByRooter{sbr: sbrErrorIfCalled(t)},
isError: true,
},
{
name: "cache miss - success",
svcbReturn: false,
svcbError: nil,
vscbShouldError: false,
vscbError: nil,
stateByRooter: sbrForValOverrideWithT(t, firstColumn.ProposerIndex(), validator),
headStateProvider: headStateWithState,
isError: false,
name: "cache miss - success",
svcbReturn: false,
svcbError: nil,
vscbShouldError: false,
vscbError: nil,
stateByRooter: sbrForValOverrideWithT(t, firstColumn.ProposerIndex(), validator),
isError: false,
},
{
name: "cache miss - state not found",
svcbReturn: false,
svcbError: nil,
vscbShouldError: false,
vscbError: nil,
stateByRooter: sbrNotFound(t, expectedSignatureData.Parent),
headStateProvider: headStateNotFound,
isError: true,
name: "cache miss - state not found",
svcbReturn: false,
svcbError: nil,
vscbShouldError: false,
vscbError: nil,
stateByRooter: sbrNotFound(t, expectedSignatureData.Parent),
isError: true,
},
{
name: "cache miss - signature failure",
svcbReturn: false,
svcbError: nil,
vscbShouldError: false,
vscbError: errors.New("signature, not so good!"),
stateByRooter: sbrForValOverrideWithT(t, firstColumn.ProposerIndex(), validator),
headStateProvider: headStateWithState,
isError: true,
name: "cache miss - signature failure",
svcbReturn: false,
svcbError: nil,
vscbShouldError: false,
vscbError: errors.New("signature, not so good!"),
stateByRooter: sbrForValOverrideWithT(t, firstColumn.ProposerIndex(), validator),
isError: true,
},
}
@@ -403,10 +377,9 @@ func TestValidProposerSignature(t *testing.T) {
shared: &sharedResources{
sc: signatureCache,
sr: tc.stateByRooter,
hsp: tc.headStateProvider,
hsp: &mockHeadStateProvider{},
fc: &mockForkchoicer{
DependentRootForEpochCB: fcReturnsDependentRoot(),
TargetRootForEpochCB: fcReturnsTargetRoot([fieldparams.RootLength]byte{}),
TargetRootForEpochCB: fcReturnsTargetRoot([fieldparams.RootLength]byte{}),
},
},
}
@@ -432,7 +405,7 @@ func TestValidProposerSignature(t *testing.T) {
func TestDataColumnsSidecarParentSeen(t *testing.T) {
const (
columnSlot = 97
columnSlot = 0
blobCount = 1
)
@@ -536,7 +509,7 @@ func TestDataColumnsSidecarParentValid(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
const (
columnSlot = 97
columnSlot = 0
blobCount = 1
)
@@ -657,7 +630,7 @@ func TestDataColumnsSidecarDescendsFromFinalized(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
const (
columnSlot = 97
columnSlot = 0
blobCount = 1
)
@@ -720,7 +693,7 @@ func TestDataColumnsSidecarInclusionProven(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
const (
columnSlot = 97
columnSlot = 0
blobCount = 1
)
@@ -775,7 +748,7 @@ func TestDataColumnsSidecarKzgProofVerified(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
const (
columnSlot = 97
columnSlot = 0
blobCount = 1
)
@@ -951,135 +924,3 @@ func TestColumnRequirementSatisfaction(t *testing.T) {
require.NoError(t, err)
}
func TestGetVerifyingStateEdgeCases(t *testing.T) {
const (
columnSlot = 97 // epoch 3
blobCount = 1
)
parentRoot := [fieldparams.RootLength]byte{}
columns := GenerateTestDataColumns(t, parentRoot, columnSlot, blobCount)
// Create a proper Fulu state for verification.
numValidators := max(uint64(columns[0].ProposerIndex()+1), 64)
fuluState, _ := util.DeterministicGenesisStateFulu(t, numValidators)
t.Run("different dependent roots - uses StateByRoot path", func(t *testing.T) {
// Parent and head are on different forks with different dependent roots.
// This forces the code to use TargetRootForEpoch -> StateByRoot path.
signatureCache := &mockSignatureCache{
svcb: func(signatureData signatureData) (bool, error) {
return false, nil // Cache miss
},
vscb: func(signatureData signatureData, _ validatorAtIndexer) (err error) {
return nil // Signature valid
},
}
// StateByRoot will be called because dependent roots differ
stateByRootCalled := false
stateByRooter := &mockStateByRooter{
sbr: func(_ context.Context, root [32]byte) (state.BeaconState, error) {
stateByRootCalled = true
return fuluState, nil
},
}
initializer := Initializer{
shared: &sharedResources{
sc: signatureCache,
sr: stateByRooter,
hsp: &mockHeadStateProvider{
headRoot: []byte{0xff}, // Different from parentRoot
headSlot: columnSlot,
},
fc: &mockForkchoicer{
// Return different roots for parent vs head to simulate different forks
DependentRootForEpochCB: func(root [32]byte, epoch primitives.Epoch) ([32]byte, error) {
return root, nil // Returns input, so parent [0...] != head [0xff...]
},
TargetRootForEpochCB: fcReturnsTargetRoot([fieldparams.RootLength]byte{}),
},
},
}
verifier := initializer.NewDataColumnsVerifier(columns, GossipDataColumnSidecarRequirements)
err := verifier.ValidProposerSignature(t.Context())
require.NoError(t, err)
require.Equal(t, true, stateByRootCalled, "StateByRoot should be called when dependent roots differ")
})
t.Run("same dependent root head far ahead - uses head state with ProcessSlots", func(t *testing.T) {
// Parent is ancestor of head on same chain, but head is in epoch 1 while column is in epoch 3.
// headEpoch (1) + 1 < dataColumnEpoch (3), so ProcessSlots is called on head state.
signatureCache := &mockSignatureCache{
svcb: func(signatureData signatureData) (bool, error) {
return false, nil // Cache miss
},
vscb: func(signatureData signatureData, _ validatorAtIndexer) (err error) {
return nil // Signature valid
},
}
headStateCalled := false
initializer := Initializer{
shared: &sharedResources{
sc: signatureCache,
sr: &mockStateByRooter{sbr: sbrErrorIfCalled(t)}, // Should not be called
hsp: &mockHeadStateProvider{
headRoot: parentRoot[:], // Same as parent
headSlot: 32, // Epoch 1
headState: fuluState.Copy(), // HeadState (not ReadOnly) for ProcessSlots
headStateReadOnly: nil, // Should not use ReadOnly path
},
fc: &mockForkchoicer{
// Return same root for both to simulate same chain
DependentRootForEpochCB: func(root [32]byte, epoch primitives.Epoch) ([32]byte, error) {
return [32]byte{0xaa}, nil // Same for all inputs
},
TargetRootForEpochCB: fcReturnsTargetRoot([fieldparams.RootLength]byte{}),
},
},
}
// Wrap to detect HeadState call
originalHsp := initializer.shared.hsp.(*mockHeadStateProvider)
wrappedHsp := &mockHeadStateProvider{
headRoot: originalHsp.headRoot,
headSlot: originalHsp.headSlot,
headState: originalHsp.headState,
}
initializer.shared.hsp = &headStateCallTracker{
mockHeadStateProvider: wrappedHsp,
headStateCalled: &headStateCalled,
}
verifier := initializer.NewDataColumnsVerifier(columns, GossipDataColumnSidecarRequirements)
err := verifier.ValidProposerSignature(t.Context())
require.NoError(t, err)
require.Equal(t, true, headStateCalled, "HeadState should be called when head is far ahead")
})
}
// headStateCallTracker wraps mockHeadStateProvider to track HeadState calls.
type headStateCallTracker struct {
*mockHeadStateProvider
headStateCalled *bool
}
func (h *headStateCallTracker) HeadState(ctx context.Context) (state.BeaconState, error) {
*h.headStateCalled = true
return h.mockHeadStateProvider.HeadState(ctx)
}
func (h *headStateCallTracker) HeadRoot(ctx context.Context) ([]byte, error) {
return h.mockHeadStateProvider.HeadRoot(ctx)
}
func (h *headStateCallTracker) HeadSlot() primitives.Slot {
return h.mockHeadStateProvider.HeadSlot()
}
func (h *headStateCallTracker) HeadStateReadOnly(ctx context.Context) (state.ReadOnlyBeaconState, error) {
return h.mockHeadStateProvider.HeadStateReadOnly(ctx)
}

View File

@@ -1,11 +0,0 @@
### Added
- Adding basic fulu fork transition support for mainnet and minimal e2e tests (multi scenario is not included)
### Changed
- updated go ethereum to 1.16.7
### Removed
- removed github.com/MariusVanDerWijden/FuzzyVM and github.com/MariusVanDerWijden/tx-fuzz due to lack of support post 1.16.7, only used in e2e for transaction fuzzing

View File

@@ -1,3 +0,0 @@
### Fixed
- When adding the `--[semi-]supernode` flag, update the ealiest available slot accordingly.

View File

@@ -1,3 +0,0 @@
### Fixed
- fixed broken and old links to actual

View File

@@ -1,2 +0,0 @@
### Changed
- Use dependent root and target root to verify data column proposer index.

View File

@@ -1,3 +0,0 @@
### Added
- Migrate to cold with the hdiff feature.

View File

@@ -1,3 +0,0 @@
### Added
- Add feature flag `--enable-proposer-preprocessing` to process the block and verify signatures before proposing.

View File

@@ -1,2 +0,0 @@
### Added
- Update spectests to v1.7.0-alpha-1.

View File

@@ -1,2 +0,0 @@
### Added
- Add feature flag to use hashtree instead of gohashtre.

View File

@@ -1,3 +0,0 @@
### Added
- Add `ProofByFieldIndex` to generalize merkle proof generation for `BeaconState`.

View File

@@ -130,6 +130,7 @@ var appFlags = []cli.Flag{
debug.MemProfileRateFlag,
debug.BlockProfileRateFlag,
debug.MutexProfileFractionFlag,
debug.HeapDumpThresholdFlag,
cmd.LogFileName,
cmd.EnableUPnPFlag,
cmd.ConfigFileFlag,

View File

@@ -230,6 +230,7 @@ var appHelpFlagGroups = []flagGroup{
debug.PProfAddrFlag,
debug.PProfFlag,
debug.PProfPortFlag,
debug.HeapDumpThresholdFlag,
flags.SetGCPercent,
},
},

View File

@@ -70,9 +70,7 @@ type Flags struct {
DisableStakinContractCheck bool // Disables check for deposit contract when proposing blocks
IgnoreUnviableAttestations bool // Ignore attestations whose target state is not viable (avoids lagging-node DoS).
EnableHashtree bool // Enables usage of the hashtree library for hashing
EnableVerboseSigVerification bool // EnableVerboseSigVerification specifies whether to verify individual signature if batch verification fails
EnableProposerPreprocessing bool // EnableProposerPreprocessing enables proposer pre-processing of blocks before proposing.
PrepareAllPayloads bool // PrepareAllPayloads informs the engine to prepare a block on every slot.
// BlobSaveFsync requires blob saving to block on fsync to ensure blobs are durably persisted before passing DA.
@@ -82,6 +80,7 @@ type Flags struct {
SaveInvalidBlob bool // SaveInvalidBlob saves invalid blob to temp.
EnableDiscoveryReboot bool // EnableDiscoveryReboot allows the node to have its local listener to be rebooted in the event of discovery issues.
LowValcountSweep bool // LowValcountSweep bounds withdrawal sweep by validator count.
// KeystoreImportDebounceInterval specifies the time duration the validator waits to reload new keys if they have
// changed on disk. This feature is for advanced use cases only.
@@ -238,19 +237,11 @@ func ConfigureBeaconChain(ctx *cli.Context) error {
logEnabled(enableFullSSZDataLogging)
cfg.EnableFullSSZDataLogging = true
}
if ctx.IsSet(enableHashtree.Name) {
logEnabled(enableHashtree)
cfg.EnableHashtree = true
}
cfg.EnableVerboseSigVerification = true
if ctx.IsSet(disableVerboseSigVerification.Name) {
logEnabled(disableVerboseSigVerification)
cfg.EnableVerboseSigVerification = false
}
cfg.EnableProposerPreprocessing = ctx.Bool(enableProposerPreprocessing.Name)
if cfg.EnableProposerPreprocessing {
logEnabled(enableProposerPreprocessing)
}
if ctx.IsSet(prepareAllPayloads.Name) {
logEnabled(prepareAllPayloads)
cfg.PrepareAllPayloads = true
@@ -294,6 +285,11 @@ func ConfigureBeaconChain(ctx *cli.Context) error {
logEnabled(ignoreUnviableAttestations)
cfg.IgnoreUnviableAttestations = true
}
if ctx.Bool(lowValcountSweep.Name) {
logEnabled(lowValcountSweep)
cfg.LowValcountSweep = true
}
if ctx.IsSet(EnableStateDiff.Name) {
logEnabled(EnableStateDiff)
cfg.EnableStateDiff = true

View File

@@ -133,19 +133,10 @@ var (
Name: "enable-beacon-rest-api",
Usage: "(Experimental): Enables of the beacon REST API when querying a beacon node.",
}
enableHashtree = &cli.BoolFlag{
Name: "enable-hashtree",
Usage: "(Experimental): Enables the hashtree hashing library.",
}
disableVerboseSigVerification = &cli.BoolFlag{
Name: "disable-verbose-sig-verification",
Usage: "Disables identifying invalid signatures if batch verification fails when processing block.",
}
enableProposerPreprocessing = &cli.BoolFlag{
Name: "enable-proposer-preprocessing",
Usage: "Enables proposer pre-processing of blocks before proposing.",
Value: false,
}
prepareAllPayloads = &cli.BoolFlag{
Name: "prepare-all-payloads",
Usage: "Informs the engine to prepare all local payloads. Useful for relayers and builders.",
@@ -220,6 +211,13 @@ var (
Name: "ignore-unviable-attestations",
Usage: "Ignores attestations whose target state is not viable with respect to the current head (avoid expensive state replay from lagging attesters).",
}
// lowValcountSweep bounds withdrawal sweep by validator count.
lowValcountSweep = &cli.BoolFlag{
Name: "low-valcount-sweep",
Usage: "Uses validator count bound for withdrawal sweep when validator count is less than MaxValidatorsPerWithdrawalsSweep.",
Value: false,
Hidden: true,
}
)
// devModeFlags holds list of flags that are set when development mode is on.
@@ -268,7 +266,6 @@ var BeaconChainFlags = combinedFlags([]cli.Flag{
ignoreUnviableAttestations,
enableFullSSZDataLogging,
disableVerboseSigVerification,
enableProposerPreprocessing,
prepareAllPayloads,
aggregateFirstInterval,
aggregateSecondInterval,
@@ -282,7 +279,7 @@ var BeaconChainFlags = combinedFlags([]cli.Flag{
enableExperimentalAttestationPool,
forceHeadFlag,
blacklistRoots,
enableHashtree,
lowValcountSweep,
}, deprecatedBeaconFlags, deprecatedFlags, upcomingDeprecation)
func combinedFlags(flags ...[]cli.Flag) []cli.Flag {

View File

@@ -28,7 +28,6 @@ go_library(
"testutils_develop.go", # keep
"values.go",
],
embedsrcs = ["testdata/e2e_config.yaml"],
importpath = "github.com/OffchainLabs/prysm/v7/config/params",
visibility = ["//visibility:public"],
deps = [

View File

@@ -49,7 +49,7 @@ ELECTRA_FORK_VERSION: 0x050000fd
ELECTRA_FORK_EPOCH: 14
# Fulu
FULU_FORK_VERSION: 0x060000fd
FULU_FORK_EPOCH: 16
FULU_FORK_EPOCH: 18446744073709551615
# Time parameters
@@ -62,8 +62,6 @@ SLOT_DURATION_MS: 10000
SECONDS_PER_ETH1_BLOCK: 2 # Override for e2e tests
# [customized] faster time for withdrawals
MIN_VALIDATOR_WITHDRAWABILITY_DELAY: 1
# [customized] increased for e2e testing (minimal default is 16)
MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP: 128
# [customized] higher frequency of committee turnover and faster time to acceptable voluntary exit
SHARD_COMMITTEE_PERIOD: 4 # Override for e2e tests
# [customized] process deposits more quickly, but insecure
@@ -124,7 +122,7 @@ MIN_SYNC_COMMITTEE_PARTICIPANTS: 1
# Other e2e overrides
# ---------------------------------------------------------------
CONFIG_NAME: "end-to-end"
SLOTS_PER_EPOCH: 8
SLOTS_PER_EPOCH: 6
EPOCHS_PER_ETH1_VOTING_PERIOD: 2
MAX_SEED_LOOKAHEAD: 1
@@ -138,8 +136,3 @@ BLOB_SCHEDULE:
# Electra
- EPOCH: 14
MAX_BLOBS_PER_BLOCK: 9
# BPO (Blob Parameter Optimization) schedule for Fulu
- EPOCH: 17
MAX_BLOBS_PER_BLOCK: 15
- EPOCH: 18
MAX_BLOBS_PER_BLOCK: 21

View File

@@ -1,30 +1,72 @@
package params
import (
_ "embed"
"sync"
)
import "math"
//go:embed testdata/e2e_config.yaml
var e2eConfigYAML []byte
var (
e2eConfigOnce sync.Once
e2eConfig *BeaconChainConfig
const (
AltairE2EForkEpoch = 6
BellatrixE2EForkEpoch = 8
CapellaE2EForkEpoch = 10
DenebE2EForkEpoch = 12
ElectraE2EForkEpoch = 14
FuluE2EForkEpoch = math.MaxUint64
)
// E2ETestConfig retrieves the configurations made specifically for E2E testing.
// The config is loaded from testdata/e2e_config.yaml and cached.
//
// WARNING: This config is only for testing, it is not meant for use outside of E2E.
func E2ETestConfig() *BeaconChainConfig {
e2eConfigOnce.Do(func() {
cfg, err := UnmarshalConfig(e2eConfigYAML, nil)
if err != nil {
log.WithError(err).Fatal("Failed to load embedded e2e config")
}
e2eConfig = cfg
})
e2eConfig := MinimalSpecConfig()
e2eConfig.DepositContractAddress = "0x4242424242424242424242424242424242424242"
e2eConfig.Eth1FollowDistance = 8
// Misc.
e2eConfig.MinGenesisActiveValidatorCount = 256
e2eConfig.GenesisDelay = 10 // 10 seconds so E2E has enough time to process deposits and get started.
e2eConfig.ChurnLimitQuotient = 65536
e2eConfig.MaxValidatorsPerWithdrawalsSweep = 128
// Time parameters.
e2eConfig.SecondsPerSlot = 10
e2eConfig.SlotDurationMilliseconds = 10000
e2eConfig.SlotsPerEpoch = 6
e2eConfig.SqrRootSlotsPerEpoch = 2
e2eConfig.SecondsPerETH1Block = 2
e2eConfig.EpochsPerEth1VotingPeriod = 2
e2eConfig.ShardCommitteePeriod = 4
e2eConfig.MaxSeedLookahead = 1
e2eConfig.MinValidatorWithdrawabilityDelay = 1
// PoW parameters.
e2eConfig.DepositChainID = 1337 // Chain ID of eth1 dev net.
e2eConfig.DepositNetworkID = 1337 // Network ID of eth1 dev net.
// Fork Parameters.
e2eConfig.AltairForkEpoch = AltairE2EForkEpoch
e2eConfig.BellatrixForkEpoch = BellatrixE2EForkEpoch
e2eConfig.CapellaForkEpoch = CapellaE2EForkEpoch
e2eConfig.DenebForkEpoch = DenebE2EForkEpoch
e2eConfig.ElectraForkEpoch = ElectraE2EForkEpoch
e2eConfig.FuluForkEpoch = FuluE2EForkEpoch
// Terminal Total Difficulty.
e2eConfig.TerminalTotalDifficulty = "480"
// Prysm constants.
e2eConfig.ConfigName = EndToEndName
e2eConfig.GenesisForkVersion = []byte{0, 0, 0, 253}
e2eConfig.AltairForkVersion = []byte{1, 0, 0, 253}
e2eConfig.BellatrixForkVersion = []byte{2, 0, 0, 253}
e2eConfig.CapellaForkVersion = []byte{3, 0, 0, 253}
e2eConfig.DenebForkVersion = []byte{4, 0, 0, 253}
e2eConfig.ElectraForkVersion = []byte{5, 0, 0, 253}
e2eConfig.FuluForkVersion = []byte{6, 0, 0, 253}
e2eConfig.BlobSchedule = []BlobScheduleEntry{
{Epoch: e2eConfig.DenebForkEpoch, MaxBlobsPerBlock: uint64(e2eConfig.DeprecatedMaxBlobsPerBlock)},
{Epoch: e2eConfig.ElectraForkEpoch, MaxBlobsPerBlock: uint64(e2eConfig.DeprecatedMaxBlobsPerBlockElectra)},
}
e2eConfig.InitializeForkSchedule()
return e2eConfig
}
@@ -51,12 +93,12 @@ func E2EMainnetTestConfig() *BeaconChainConfig {
e2eConfig.DepositNetworkID = 1337 // Network ID of eth1 dev net.
// Altair Fork Parameters.
e2eConfig.AltairForkEpoch = E2ETestConfig().AltairForkEpoch
e2eConfig.BellatrixForkEpoch = E2ETestConfig().BellatrixForkEpoch
e2eConfig.CapellaForkEpoch = E2ETestConfig().CapellaForkEpoch
e2eConfig.DenebForkEpoch = E2ETestConfig().DenebForkEpoch
e2eConfig.ElectraForkEpoch = E2ETestConfig().ElectraForkEpoch
e2eConfig.FuluForkEpoch = E2ETestConfig().FuluForkEpoch
e2eConfig.AltairForkEpoch = AltairE2EForkEpoch
e2eConfig.BellatrixForkEpoch = BellatrixE2EForkEpoch
e2eConfig.CapellaForkEpoch = CapellaE2EForkEpoch
e2eConfig.DenebForkEpoch = DenebE2EForkEpoch
e2eConfig.ElectraForkEpoch = ElectraE2EForkEpoch
e2eConfig.FuluForkEpoch = FuluE2EForkEpoch
// Terminal Total Difficulty.
e2eConfig.TerminalTotalDifficulty = "480"
@@ -77,9 +119,6 @@ func E2EMainnetTestConfig() *BeaconChainConfig {
e2eConfig.BlobSchedule = []BlobScheduleEntry{
{Epoch: e2eConfig.DenebForkEpoch, MaxBlobsPerBlock: uint64(e2eConfig.DeprecatedMaxBlobsPerBlock)},
{Epoch: e2eConfig.ElectraForkEpoch, MaxBlobsPerBlock: uint64(e2eConfig.DeprecatedMaxBlobsPerBlockElectra)},
// BPO (Blob Parameter Optimization) schedule for Fulu
{Epoch: e2eConfig.FuluForkEpoch + 1, MaxBlobsPerBlock: 15},
{Epoch: e2eConfig.FuluForkEpoch + 2, MaxBlobsPerBlock: 21},
}
e2eConfig.InitializeForkSchedule()

View File

@@ -36,6 +36,7 @@ go_library(
"//runtime/version:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_prysmaticlabs_fastssz//:go_default_library",
"@com_github_prysmaticlabs_gohashtree//:go_default_library",
"@org_golang_google_protobuf//proto:go_default_library",
],
)
@@ -62,7 +63,6 @@ go_test(
"//consensus-types/interfaces:go_default_library",
"//consensus-types/primitives:go_default_library",
"//container/trie:go_default_library",
"//crypto/hash/htr:go_default_library",
"//encoding/bytesutil:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
@@ -72,5 +72,6 @@ go_test(
"//testing/require:go_default_library",
"@com_github_prysmaticlabs_fastssz//:go_default_library",
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
"@com_github_prysmaticlabs_gohashtree//:go_default_library",
],
)

View File

@@ -5,10 +5,10 @@ import (
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
"github.com/OffchainLabs/prysm/v7/container/trie"
"github.com/OffchainLabs/prysm/v7/crypto/hash/htr"
"github.com/OffchainLabs/prysm/v7/encoding/ssz"
"github.com/OffchainLabs/prysm/v7/runtime/version"
"github.com/pkg/errors"
"github.com/prysmaticlabs/gohashtree"
)
const (
@@ -45,7 +45,7 @@ func VerifyKZGInclusionProof(blob ROBlob) error {
return errInvalidBodyRoot
}
chunks := makeChunk(blob.KzgCommitment)
htr.HashChunks(chunks, chunks)
gohashtree.HashChunks(chunks, chunks)
verified := trie.VerifyMerkleProof(root, chunks[0][:], blob.Index+KZGOffset, blob.CommitmentInclusionProof)
if !verified {
return errInvalidInclusionProof
@@ -182,7 +182,7 @@ func LeavesFromCommitments(commitments [][]byte) [][]byte {
leaves := make([][]byte, len(commitments))
for i, kzg := range commitments {
chunk := makeChunk(kzg)
htr.HashChunks(chunk, chunk)
gohashtree.HashChunks(chunk, chunk)
leaves[i] = chunk[0][:]
}
return leaves

View File

@@ -8,10 +8,10 @@ import (
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
"github.com/OffchainLabs/prysm/v7/container/trie"
"github.com/OffchainLabs/prysm/v7/crypto/hash/htr"
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v7/testing/require"
"github.com/prysmaticlabs/gohashtree"
)
func Test_MerkleProofKZGCommitment_Altair(t *testing.T) {
@@ -108,7 +108,7 @@ func Test_MerkleProofKZGCommitment(t *testing.T) {
require.Equal(t, true, trie.VerifyMerkleProof(root[:], commitmentsRoot[:], kzgPosition, topProof[:len(topProof)-1]))
chunk := makeChunk(kzgs[index])
htr.HashChunks(chunk, chunk)
gohashtree.HashChunks(chunk, chunk)
require.Equal(t, true, trie.VerifyMerkleProof(root[:], chunk[0][:], uint64(index+KZGOffset), proof))
}

View File

@@ -5,12 +5,7 @@ go_library(
srcs = ["hashtree.go"],
importpath = "github.com/OffchainLabs/prysm/v7/crypto/hash/htr",
visibility = ["//visibility:public"],
deps = [
"//config/features:go_default_library",
"@com_github_offchainlabs_hashtree//:go_default_library",
"@com_github_prysmaticlabs_gohashtree//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
],
deps = ["@com_github_prysmaticlabs_gohashtree//:go_default_library"],
)
go_test(
@@ -18,8 +13,5 @@ go_test(
size = "small",
srcs = ["hashtree_test.go"],
embed = [":go_default_library"],
deps = [
"//config/features:go_default_library",
"//testing/require:go_default_library",
],
deps = ["//testing/require:go_default_library"],
)

View File

@@ -4,38 +4,14 @@ import (
"runtime"
"sync"
"github.com/OffchainLabs/hashtree"
"github.com/OffchainLabs/prysm/v7/config/features"
"github.com/prysmaticlabs/gohashtree"
log "github.com/sirupsen/logrus"
)
const minSliceSizeToParallelize = 5000
// Hash hashes chunks pairwise into digests using the configured hashing library.
// It performs input validation (odd chunks, digest length).
func Hash(digests, chunks [][32]byte) error {
if features.Get().EnableHashtree {
return hashtree.Hash(digests, chunks)
}
return gohashtree.Hash(digests, chunks)
}
// HashChunks hashes chunks pairwise into digests without error checking.
// The caller must ensure inputs are valid (even chunks, sufficient digest space).
func HashChunks(digests, chunks [][32]byte) {
if features.Get().EnableHashtree {
if err := hashtree.Hash(digests, chunks); err != nil {
log.WithError(err).Error("Could not hash chunks")
}
} else {
gohashtree.HashChunks(digests, chunks)
}
}
func hashParallel(inputList [][32]byte, outputList [][32]byte, wg *sync.WaitGroup) {
defer wg.Done()
err := Hash(outputList, inputList)
err := gohashtree.Hash(outputList, inputList)
if err != nil {
panic(err) // lint:nopanic -- This should never panic.
}
@@ -49,7 +25,7 @@ func hashParallel(inputList [][32]byte, outputList [][32]byte, wg *sync.WaitGrou
func VectorizedSha256(inputList [][32]byte) [][32]byte {
outputList := make([][32]byte, len(inputList)/2)
if len(inputList) < minSliceSizeToParallelize {
err := Hash(outputList, inputList)
err := gohashtree.Hash(outputList, inputList)
if err != nil {
panic(err) // lint:nopanic -- This should never panic.
}
@@ -62,7 +38,7 @@ func VectorizedSha256(inputList [][32]byte) [][32]byte {
for j := range n {
go hashParallel(inputList[j*2*groupSize:(j+1)*2*groupSize], outputList[j*groupSize:], &wg)
}
err := Hash(outputList[n*groupSize:], inputList[n*2*groupSize:])
err := gohashtree.Hash(outputList[n*groupSize:], inputList[n*2*groupSize:])
if err != nil {
panic(err) // lint:nopanic -- This should never panic.
}

View File

@@ -4,7 +4,6 @@ import (
"sync"
"testing"
"github.com/OffchainLabs/prysm/v7/config/features"
"github.com/OffchainLabs/prysm/v7/testing/require"
)
@@ -24,25 +23,3 @@ func Test_VectorizedSha256(t *testing.T) {
require.Equal(t, r, hash2[i])
}
}
func Test_VectorizedSha256_hashtree_enabled(t *testing.T) {
resetCfg := features.InitWithReset(&features.Flags{
EnableHashtree: true,
})
defer resetCfg()
largeSlice := make([][32]byte, 32*minSliceSizeToParallelize)
secondLargeSlice := make([][32]byte, 32*minSliceSizeToParallelize)
hash1 := make([][32]byte, 16*minSliceSizeToParallelize)
wg := sync.WaitGroup{}
wg.Go(func() {
tempHash := VectorizedSha256(largeSlice)
copy(hash1, tempHash)
})
wg.Wait()
hash2 := VectorizedSha256(secondLargeSlice)
require.Equal(t, len(hash1), len(hash2))
for i, r := range hash1 {
require.Equal(t, r, hash2[i])
}
}

175
deps.bzl
View File

@@ -301,8 +301,8 @@ def prysm_deps():
go_repository(
name = "com_github_bits_and_blooms_bitset",
importpath = "github.com/bits-and-blooms/bitset",
sum = "h1:Tquv9S8+SGaS3EhyA+up3FXzmkhxPGjQQCkcs2uw7w4=",
version = "v1.22.0",
sum = "h1:1X2TS7aHz1ELcC0yU1y2stUs/0ig5oMU6STFZGrhvHI=",
version = "v1.17.0",
)
go_repository(
name = "com_github_bradfitz_go_smtpd",
@@ -482,8 +482,8 @@ def prysm_deps():
go_repository(
name = "com_github_cockroachdb_pebble",
importpath = "github.com/cockroachdb/pebble",
sum = "h1:5AAWCBWbat0uE0blr8qzufZP5tBjkRyy/jWe1QWLnvw=",
version = "v1.1.5",
sum = "h1:CUh2IPtR4swHlEj48Rhfzw6l/d0qA31fItcIszQVIsA=",
version = "v1.1.2",
)
go_repository(
name = "com_github_cockroachdb_redact",
@@ -512,16 +512,14 @@ def prysm_deps():
go_repository(
name = "com_github_consensys_bavard",
importpath = "github.com/consensys/bavard",
sum = "h1:dTlIwEdFQmldzFf5F6bbTcYWhvnAgZai2g8eq3Wwxqg=",
version = "v0.1.31-0.20250406004941-2db259e4b582",
sum = "h1:Uw2CGvbXSZWhqK59X0VG/zOjpTFuOMcPLStrp1ihI0A=",
version = "v0.1.22",
)
go_repository(
name = "com_github_consensys_gnark_crypto",
importpath = "github.com/consensys/gnark-crypto",
patch_args = ["-p1"],
patches = ["//third_party:com_github_consensys_gnark_crypto.patch"],
sum = "h1:vIye/FqI50VeAr0B3dx+YjeIvmc3LWz4yEfbWBpTUf0=",
version = "v0.18.0",
sum = "h1:DDBdl4HaBtdQsq/wfMwJvZNE80sHidrK3Nfrefatm0E=",
version = "v0.14.0",
)
go_repository(
name = "com_github_containerd_cgroups",
@@ -557,14 +555,8 @@ def prysm_deps():
go_repository(
name = "com_github_cpuguy83_go_md2man_v2",
importpath = "github.com/cpuguy83/go-md2man/v2",
sum = "h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo=",
version = "v2.0.7",
)
go_repository(
name = "com_github_crate_crypto_go_eth_kzg",
importpath = "github.com/crate-crypto/go-eth-kzg",
sum = "h1:WzDGjHk4gFg6YzV0rJOAsTK4z3Qkz5jd4RE3DAvPFkg=",
version = "v1.4.0",
sum = "h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=",
version = "v2.0.5",
)
go_repository(
name = "com_github_crate_crypto_go_ipa",
@@ -599,8 +591,8 @@ def prysm_deps():
go_repository(
name = "com_github_datadog_zstd",
importpath = "github.com/DataDog/zstd",
sum = "h1:ybO8RBeh29qrxIhCA9E8gKY6xfONU9T6G6aP9DTKfLE=",
version = "v1.5.7",
sum = "h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ=",
version = "v1.5.5",
)
go_repository(
name = "com_github_davecgh_go_spew",
@@ -614,29 +606,23 @@ def prysm_deps():
sum = "h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU=",
version = "v0.0.0-20200604182044-b73af7476f6c",
)
go_repository(
name = "com_github_dchest_siphash",
importpath = "github.com/dchest/siphash",
sum = "h1:QXwFc8cFOR2dSa/gE6o/HokBMWtLUaNDVd+22aKHeEA=",
version = "v1.2.3",
)
go_repository(
name = "com_github_deckarep_golang_set_v2",
importpath = "github.com/deckarep/golang-set/v2",
sum = "h1:swm0rlPCmdWn9mESxKOjWk8hXSqoxOp+ZlfuyaAdFlQ=",
version = "v2.8.0",
sum = "h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM=",
version = "v2.6.0",
)
go_repository(
name = "com_github_decred_dcrd_crypto_blake256",
importpath = "github.com/decred/dcrd/crypto/blake256",
sum = "h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8=",
version = "v1.1.0",
sum = "h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=",
version = "v1.0.1",
)
go_repository(
name = "com_github_decred_dcrd_dcrec_secp256k1_v4",
importpath = "github.com/decred/dcrd/dcrec/secp256k1/v4",
sum = "h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc=",
version = "v4.4.0",
sum = "h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg=",
version = "v4.3.0",
)
go_repository(
name = "com_github_deepmap_oapi_codegen",
@@ -749,8 +735,8 @@ def prysm_deps():
go_repository(
name = "com_github_emicklei_dot",
importpath = "github.com/emicklei/dot",
sum = "h1:08GN+DD79cy/tzN6uLCT84+2Wk9u+wvqP+Hkx/dIR8A=",
version = "v1.6.2",
sum = "h1:Ase39UD9T9fRBOb5ptgpixrxfx8abVzNWZi2+lr53PI=",
version = "v0.11.0",
)
go_repository(
name = "com_github_emicklei_go_restful_v3",
@@ -793,12 +779,6 @@ def prysm_deps():
sum = "h1:aVtoLK5xwJ6c5RiqO8g8ptJ5KU+2Hdquf6G3aXiHh5s=",
version = "v2.1.5",
)
go_repository(
name = "com_github_ethereum_go_bigmodexpfix",
importpath = "github.com/ethereum/go-bigmodexpfix",
sum = "h1:rvv6MJhy07IMfEKuARQ9TKojGqLVNxQajaXEp/BoqSk=",
version = "v0.0.0-20250911101455-f9e208c548ab",
)
go_repository(
name = "com_github_ethereum_go_ethereum",
build_directives = [
@@ -810,8 +790,8 @@ def prysm_deps():
patches = [
"//third_party:com_github_ethereum_go_ethereum_secp256k1.patch",
],
sum = "h1:qeM4TvbrWK0UC0tgkZ7NiRsmBGwsjqc64BHo20U59UQ=",
version = "v1.16.7",
sum = "h1:bRra1zi+/q+qyXZ6fylZOrlaF8kDdnlTtzNTmNHfX+g=",
version = "v1.15.9",
)
go_repository(
name = "com_github_ethereum_go_verkle",
@@ -852,8 +832,8 @@ def prysm_deps():
go_repository(
name = "com_github_ferranbt_fastssz",
importpath = "github.com/ferranbt/fastssz",
sum = "h1:OCDB+dYDEQDvAgtAGnTSidK1Pe2tW3nFV40XyMkTeDY=",
version = "v0.1.4",
sum = "h1:ZI+z3JH05h4kgmFXdHuR1aWYsgrg7o+Fw7/NCzM16Mo=",
version = "v0.1.3",
)
go_repository(
name = "com_github_fjl_gencodec",
@@ -939,6 +919,12 @@ def prysm_deps():
sum = "h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays=",
version = "v0.0.0-20191108122812-4678299bea08",
)
go_repository(
name = "com_github_gballet_go_verkle",
importpath = "github.com/gballet/go-verkle",
sum = "h1:BAIP2GihuqhwdILrV+7GJel5lyPV3u1+PgzrWLc0TkE=",
version = "v0.1.1-0.20231031103413-a67434b50f46",
)
go_repository(
name = "com_github_gdamore_encoding",
importpath = "github.com/gdamore/encoding",
@@ -1146,8 +1132,8 @@ def prysm_deps():
go_repository(
name = "com_github_gofrs_flock",
importpath = "github.com/gofrs/flock",
sum = "h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=",
version = "v0.12.1",
sum = "h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=",
version = "v0.8.1",
)
go_repository(
name = "com_github_gogo_googleapis",
@@ -1214,8 +1200,8 @@ def prysm_deps():
go_repository(
name = "com_github_golang_snappy",
importpath = "github.com/golang/snappy",
sum = "h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=",
version = "v1.0.0",
sum = "h1:4bw4WeyTYPp0smaXiJZCNnLrvVBqirQVreixayXezGc=",
version = "v0.0.5-0.20231225225746-43d5d4cd4e0e",
)
go_repository(
name = "com_github_golangci_lint_1",
@@ -1289,6 +1275,12 @@ def prysm_deps():
sum = "h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA=",
version = "v0.1.0",
)
go_repository(
name = "com_github_google_subcommands",
importpath = "github.com/google/subcommands",
sum = "h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE=",
version = "v1.2.0",
)
go_repository(
name = "com_github_google_uuid",
importpath = "github.com/google/uuid",
@@ -1550,8 +1542,8 @@ def prysm_deps():
go_repository(
name = "com_github_holiman_billy",
importpath = "github.com/holiman/billy",
sum = "h1:IZUYC/xb3giYwBLMnr8d0TGTzPKFGNTCGgGLoyeX330=",
version = "v0.0.0-20250707135307-f2f9b9aae7db",
sum = "h1:X4egAf/gcS1zATw6wn4Ej8vjuVGxeHdan+bRb2ebyv4=",
version = "v0.0.0-20240216141850-2abb0c79d3c4",
)
go_repository(
name = "com_github_holiman_bloomfilter_v2",
@@ -1562,8 +1554,8 @@ def prysm_deps():
go_repository(
name = "com_github_holiman_goevmlab",
importpath = "github.com/holiman/goevmlab",
sum = "h1:krEMViaomzuBfH/L1V4b8w2lVfsEpUbxH1ZJQpUaT6E=",
version = "v0.0.0-20250515153315-ab84907ebdb2",
sum = "h1:JHZ8k9n9G9KXIo1qrvK5Cxah6ax5BR0qVTA9bFYl1oM=",
version = "v0.0.0-20241121133100-cfa6b078c8c4",
)
go_repository(
name = "com_github_holiman_uint256",
@@ -1858,8 +1850,8 @@ def prysm_deps():
go_repository(
name = "com_github_klauspost_compress",
importpath = "github.com/klauspost/compress",
sum = "h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=",
version = "v1.18.0",
sum = "h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=",
version = "v1.17.11",
)
go_repository(
name = "com_github_klauspost_cpuid",
@@ -2112,6 +2104,18 @@ def prysm_deps():
sum = "h1:3l11YT8tm9MnwGFQ4kETwkzpAwY2Jt9lCrumCUW4+z4=",
version = "v0.7.0",
)
go_repository(
name = "com_github_mariusvanderwijden_fuzzyvm",
importpath = "github.com/MariusVanDerWijden/FuzzyVM",
sum = "h1:RQtzNvriR3Yu5CvVBTJPwDmfItBT90TWZ3fFondhc08=",
version = "v0.0.0-20240516070431-7828990cad7d",
)
go_repository(
name = "com_github_mariusvanderwijden_tx_fuzz",
importpath = "github.com/MariusVanDerWijden/tx-fuzz",
sum = "h1:Tq4lXivsR8mtoP4RpasUDIUpDLHfN1YhFge/kzrzK78=",
version = "v1.4.0",
)
go_repository(
name = "com_github_marten_seemann_tcp",
importpath = "github.com/marten-seemann/tcp",
@@ -2139,8 +2143,8 @@ def prysm_deps():
go_repository(
name = "com_github_mattn_go_runewidth",
importpath = "github.com/mattn/go-runewidth",
sum = "h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=",
version = "v0.0.16",
sum = "h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=",
version = "v0.0.15",
)
go_repository(
name = "com_github_matttproud_golang_protobuf_extensions",
@@ -2253,8 +2257,8 @@ def prysm_deps():
go_repository(
name = "com_github_mitchellh_mapstructure",
importpath = "github.com/mitchellh/mapstructure",
sum = "h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=",
version = "v1.5.0",
sum = "h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=",
version = "v1.4.1",
)
go_repository(
name = "com_github_mitchellh_pointerstructure",
@@ -2268,6 +2272,12 @@ def prysm_deps():
sum = "h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY=",
version = "v0.4.0",
)
go_repository(
name = "com_github_mmcloughlin_profile",
importpath = "github.com/mmcloughlin/profile",
sum = "h1:jhDmAqPyebOsVDOCICJoINoLb/AnLBaUw58nFzxWS2w=",
version = "v0.1.1",
)
go_repository(
name = "com_github_moby_spdystream",
importpath = "github.com/moby/spdystream",
@@ -2439,15 +2449,6 @@ def prysm_deps():
sum = "h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=",
version = "v1.4.11",
)
go_repository(
name = "com_github_offchainlabs_hashtree",
build_file_generation = "off",
importpath = "github.com/OffchainLabs/hashtree",
patch_args = ["-p1"],
patches = ["//third_party:com_github_offchainlabs_hashtree.patch"],
sum = "h1:R6DAjgAUwwfgji3jEI4WUxtZ3eJ+FbRHjW21UPMBJyo=",
version = "v0.2.2",
)
go_repository(
name = "com_github_oklog_oklog",
importpath = "github.com/oklog/oklog",
@@ -2820,12 +2821,6 @@ def prysm_deps():
sum = "h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=",
version = "v1.1.0",
)
go_repository(
name = "com_github_projectzkm_ziren_crates_go_runtime_zkvm_runtime",
importpath = "github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime",
sum = "h1:1zYrtlhrZ6/b6SAjLSfKzWtdgqK0U+HtH/VcBWh1BaU=",
version = "v0.0.0-20251001021608-1fe7b43fc4d6",
)
go_repository(
name = "com_github_prometheus_client_golang",
importpath = "github.com/prometheus/client_golang",
@@ -3272,8 +3267,8 @@ def prysm_deps():
go_repository(
name = "com_github_spf13_pflag",
importpath = "github.com/spf13/pflag",
sum = "h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=",
version = "v1.0.6",
sum = "h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=",
version = "v1.0.5",
)
go_repository(
name = "com_github_spf13_viper",
@@ -3389,14 +3384,14 @@ def prysm_deps():
go_repository(
name = "com_github_tklauser_go_sysconf",
importpath = "github.com/tklauser/go-sysconf",
sum = "h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=",
version = "v0.3.15",
sum = "h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4=",
version = "v0.3.13",
)
go_repository(
name = "com_github_tklauser_numcpus",
importpath = "github.com/tklauser/numcpus",
sum = "h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=",
version = "v0.10.0",
sum = "h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr4=",
version = "v0.7.0",
)
go_repository(
name = "com_github_tmc_grpc_websocket_proxy",
@@ -3416,6 +3411,12 @@ def prysm_deps():
sum = "h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=",
version = "v1.2.7",
)
go_repository(
name = "com_github_umbracle_gohashtree",
importpath = "github.com/umbracle/gohashtree",
sum = "h1:CQh33pStIp/E30b7TxDlXfM0145bn2e8boI30IxAhTg=",
version = "v0.0.2-alpha.0.20230207094856-5b775a815c10",
)
go_repository(
name = "com_github_urfave_cli",
importpath = "github.com/urfave/cli",
@@ -3425,8 +3426,8 @@ def prysm_deps():
go_repository(
name = "com_github_urfave_cli_v2",
importpath = "github.com/urfave/cli/v2",
sum = "h1:VdRdS98FNhKZ8/Az8B7MTyGQmpIr36O1EHybx/LaZ4g=",
version = "v2.27.6",
sum = "h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w=",
version = "v2.27.5",
)
go_repository(
name = "com_github_urfave_negroni",
@@ -3473,8 +3474,8 @@ def prysm_deps():
go_repository(
name = "com_github_victoriametrics_fastcache",
importpath = "github.com/VictoriaMetrics/fastcache",
sum = "h1:AW4mheMR5Vd9FkAPUv+NH6Nhw+fmbTMGMsNAoA/+4G0=",
version = "v1.13.0",
sum = "h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI=",
version = "v1.12.2",
)
go_repository(
name = "com_github_vividcortex_gohistogram",
@@ -3596,8 +3597,8 @@ def prysm_deps():
go_repository(
name = "com_github_yusufpapurcu_wmi",
importpath = "github.com/yusufpapurcu/wmi",
sum = "h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=",
version = "v1.2.4",
sum = "h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=",
version = "v1.2.3",
)
go_repository(
name = "com_google_cloud_go",
@@ -4783,8 +4784,8 @@ def prysm_deps():
go_repository(
name = "org_golang_x_exp",
importpath = "golang.org/x/exp",
sum = "h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI=",
version = "v0.0.0-20250506013437-ce4c2cf36ca6",
sum = "h1:KL/ZBHXgKGVmuZBZ01Lt57yE5ws8ZPSkkihmEyq7FXc=",
version = "v0.0.0-20250128182459-e0ece0dbea4c",
)
go_repository(
name = "org_golang_x_exp_typeparams",

View File

@@ -21,6 +21,7 @@ go_library(
"@com_github_minio_sha256_simd//:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
"@com_github_prysmaticlabs_gohashtree//:go_default_library",
],
)

View File

@@ -6,6 +6,7 @@ import (
"github.com/OffchainLabs/prysm/v7/container/trie"
"github.com/OffchainLabs/prysm/v7/crypto/hash/htr"
"github.com/pkg/errors"
"github.com/prysmaticlabs/gohashtree"
)
var errInvalidNilSlice = errors.New("invalid empty slice")
@@ -181,10 +182,10 @@ func MerkleizeListSSZ[T Hashable](elements []T, limit uint64) ([32]byte, error)
chunks := make([][32]byte, 2)
chunks[0] = body
binary.LittleEndian.PutUint64(chunks[1][:], uint64(len(elements)))
if err = htr.Hash(chunks, chunks); err != nil {
if err := gohashtree.Hash(chunks, chunks); err != nil {
return [32]byte{}, err
}
return chunks[0], nil
return chunks[0], err
}
// MerkleizeByteSliceSSZ hashes a byteslice by chunkifying it and returning the

56
go.mod
View File

@@ -3,19 +3,20 @@ module github.com/OffchainLabs/prysm/v7
go 1.25.1
require (
github.com/MariusVanDerWijden/FuzzyVM v0.0.0-20240516070431-7828990cad7d
github.com/MariusVanDerWijden/tx-fuzz v1.4.0
github.com/OffchainLabs/go-bitfield v0.0.0-20251031151322-f427d04d8506
github.com/OffchainLabs/hashtree v0.2.3
github.com/aristanetworks/goarista v0.0.0-20200805130819-fd197cf57d96
github.com/bazelbuild/rules_go v0.23.2
github.com/btcsuite/btcd/btcec/v2 v2.3.4
github.com/consensys/gnark-crypto v0.18.0
github.com/consensys/gnark-crypto v0.14.0
github.com/crate-crypto/go-kzg-4844 v1.1.0
github.com/d4l3k/messagediff v1.2.1
github.com/dgraph-io/ristretto/v2 v2.2.0
github.com/dustin/go-humanize v1.0.1
github.com/emicklei/dot v1.6.2
github.com/emicklei/dot v0.11.0
github.com/ethereum/c-kzg-4844/v2 v2.1.5
github.com/ethereum/go-ethereum v1.16.7
github.com/ethereum/go-ethereum v1.15.9
github.com/fsnotify/fsnotify v1.6.0
github.com/ghodss/yaml v1.0.0
github.com/go-yaml/yaml v2.1.0+incompatible
@@ -23,7 +24,7 @@ require (
github.com/golang-jwt/jwt/v4 v4.5.2
github.com/golang/gddo v0.0.0-20200528160355-8d077c1d8f4c
github.com/golang/protobuf v1.5.4
github.com/golang/snappy v1.0.0
github.com/golang/snappy v0.0.5-0.20231225225746-43d5d4cd4e0e
github.com/google/go-cmp v0.7.0
github.com/google/gofuzz v1.2.0
github.com/google/uuid v1.6.0
@@ -73,7 +74,7 @@ require (
github.com/thomaso-mirodin/intmath v0.0.0-20160323211736-5dc6d854e46e
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.6
github.com/urfave/cli/v2 v2.27.5
github.com/uudashr/gocognit v1.0.5
github.com/wealdtech/go-bytesutil v1.1.1
github.com/wealdtech/go-eth2-util v1.6.3
@@ -88,7 +89,7 @@ require (
go.uber.org/automaxprocs v1.5.2
go.uber.org/mock v0.5.2
golang.org/x/crypto v0.44.0
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c
golang.org/x/sync v0.18.0
golang.org/x/tools v0.39.0
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1
@@ -105,13 +106,12 @@ require (
require (
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c // indirect
github.com/DataDog/zstd v1.5.7 // indirect
github.com/DataDog/zstd v1.5.5 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 // indirect
github.com/VictoriaMetrics/fastcache v1.13.0 // indirect
github.com/VictoriaMetrics/fastcache v1.12.2 // indirect
github.com/benbjohnson/clock v1.3.5 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.22.0 // indirect
github.com/bits-and-blooms/bitset v1.17.0 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/cp v1.1.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
@@ -119,28 +119,27 @@ require (
github.com/cockroachdb/errors v1.11.3 // indirect
github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce // indirect
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
github.com/cockroachdb/pebble v1.1.5 // indirect
github.com/cockroachdb/pebble v1.1.2 // indirect
github.com/cockroachdb/redact v1.1.5 // indirect
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect
github.com/consensys/bavard v0.1.22 // indirect
github.com/containerd/cgroups v1.1.0 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
github.com/crate-crypto/go-eth-kzg v1.4.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
github.com/dchest/siphash v1.2.3 // indirect
github.com/deckarep/golang-set/v2 v2.8.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
github.com/deckarep/golang-set/v2 v2.6.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
github.com/deepmap/oapi-codegen v1.8.2 // indirect
github.com/dlclark/regexp2 v1.7.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127 // indirect
github.com/elastic/gosigar v0.14.3 // indirect
github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab // indirect
github.com/ethereum/c-kzg-4844 v1.0.0 // indirect
github.com/ethereum/go-verkle v0.2.2 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/ferranbt/fastssz v0.1.4 // indirect
github.com/ferranbt/fastssz v0.1.3 // indirect
github.com/flynn/noise v1.1.0 // indirect
github.com/francoispqt/gojay v1.2.13 // indirect
github.com/getsentry/sentry-go v0.27.0 // indirect
@@ -150,7 +149,7 @@ require (
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/gofrs/flock v0.12.1 // indirect
github.com/gofrs/flock v0.8.1 // indirect
github.com/google/gopacket v1.1.19 // indirect
github.com/google/pprof v0.0.0-20250202011525-fc3143867406 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
@@ -158,8 +157,9 @@ require (
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect
github.com/hashicorp/go-bexpr v0.1.10 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/holiman/billy v0.0.0-20250707135307-f2f9b9aae7db // indirect
github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 // indirect
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
github.com/holiman/goevmlab v0.0.0-20241121133100-cfa6b078c8c4 // indirect
github.com/huin/goupnp v1.3.0 // indirect
github.com/influxdata/influxdb-client-go/v2 v2.4.0 // indirect
github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c // indirect
@@ -168,7 +168,7 @@ require (
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
github.com/koron/go-ssdp v0.0.5 // indirect
github.com/kr/text v0.2.0 // indirect
@@ -185,14 +185,15 @@ require (
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/miekg/dns v1.1.63 // indirect
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/mapstructure v1.4.1 // indirect
github.com/mitchellh/pointerstructure v1.2.0 // indirect
github.com/mmcloughlin/addchain v0.4.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
@@ -248,12 +249,12 @@ require (
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
github.com/tklauser/go-sysconf v0.3.15 // indirect
github.com/tklauser/numcpus v0.10.0 // indirect
github.com/tklauser/go-sysconf v0.3.13 // indirect
github.com/tklauser/numcpus v0.7.0 // indirect
github.com/wealdtech/go-eth2-types/v2 v2.8.2 // indirect
github.com/wlynxg/anet v0.0.5 // indirect
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 // indirect
go.opentelemetry.io/otel/metric v1.35.0 // indirect
@@ -274,6 +275,7 @@ require (
gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
lukechampine.com/blake3 v1.3.0 // indirect
rsc.io/tmplfunc v0.0.3 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect

128
go.sum
View File

@@ -48,22 +48,22 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs=
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DataDog/zstd v1.5.7 h1:ybO8RBeh29qrxIhCA9E8gKY6xfONU9T6G6aP9DTKfLE=
github.com/DataDog/zstd v1.5.7/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ=
github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/MariusVanDerWijden/FuzzyVM v0.0.0-20240516070431-7828990cad7d h1:RQtzNvriR3Yu5CvVBTJPwDmfItBT90TWZ3fFondhc08=
github.com/MariusVanDerWijden/FuzzyVM v0.0.0-20240516070431-7828990cad7d/go.mod h1:gWTykV/ZinShgltWofTEJY4TsletuvGhB6l4+Ai2F+E=
github.com/MariusVanDerWijden/tx-fuzz v1.4.0 h1:Tq4lXivsR8mtoP4RpasUDIUpDLHfN1YhFge/kzrzK78=
github.com/MariusVanDerWijden/tx-fuzz v1.4.0/go.mod h1:gmOVECg7o5FY5VU3DQ/fY0zTk/ExBdMkUGz0vA8qqms=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/OffchainLabs/go-bitfield v0.0.0-20251031151322-f427d04d8506 h1:d/SJkN8/9Ca+1YmuDiUJxAiV4w/a9S8NcsG7GMQSrVI=
github.com/OffchainLabs/go-bitfield v0.0.0-20251031151322-f427d04d8506/go.mod h1:6TZI4FU6zT8x6ZfWa1J8YQ2NgW0wLV/W3fHRca8ISBo=
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 h1:1zYrtlhrZ6/b6SAjLSfKzWtdgqK0U+HtH/VcBWh1BaU=
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6/go.mod h1:ioLG6R+5bUSO1oeGSDxOV3FADARuMoytZCSX6MEMQkI=
github.com/OffchainLabs/hashtree v0.2.3 h1:nM8dBAQZzHLzzM14FaAHXnHTAXZIst69v5xWuS48y/c=
github.com/OffchainLabs/hashtree v0.2.3/go.mod h1:b07+cRZs+eAR8TR57CB9TQlt5Gnl/06Xs76xt/1wq0M=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/sarama v1.26.1/go.mod h1:NbSGBSSndYaIhRcBtY9V0U7AyH+x71bG668AuWys/yU=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/VictoriaMetrics/fastcache v1.13.0 h1:AW4mheMR5Vd9FkAPUv+NH6Nhw+fmbTMGMsNAoA/+4G0=
github.com/VictoriaMetrics/fastcache v1.13.0/go.mod h1:hHXhl4DA2fTL2HTZDJFXWgW0LNjo6B+4aj2Wmng3TjU=
github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI=
github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI=
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@@ -71,8 +71,9 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8=
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc=
github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
@@ -99,8 +100,8 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bits-and-blooms/bitset v1.22.0 h1:Tquv9S8+SGaS3EhyA+up3FXzmkhxPGjQQCkcs2uw7w4=
github.com/bits-and-blooms/bitset v1.22.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/bits-and-blooms/bitset v1.17.0 h1:1X2TS7aHz1ELcC0yU1y2stUs/0ig5oMU6STFZGrhvHI=
github.com/bits-and-blooms/bitset v1.17.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
github.com/bradfitz/gomemcache v0.0.0-20170208213004-1952afaa557d/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ=
@@ -114,6 +115,7 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA
github.com/cespare/cp v1.1.1 h1:nCb6ZLdB7NRaqsm91JtQTAme2SKJzXVsdPIPkyJr1MU=
github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
@@ -143,15 +145,17 @@ github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/e
github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M=
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE=
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs=
github.com/cockroachdb/pebble v1.1.5 h1:5AAWCBWbat0uE0blr8qzufZP5tBjkRyy/jWe1QWLnvw=
github.com/cockroachdb/pebble v1.1.5/go.mod h1:17wO9el1YEigxkP/YtV8NtCivQDgoCyBg5c4VR/eOWo=
github.com/cockroachdb/pebble v1.1.2 h1:CUh2IPtR4swHlEj48Rhfzw6l/d0qA31fItcIszQVIsA=
github.com/cockroachdb/pebble v1.1.2/go.mod h1:4exszw1r40423ZsmkG/09AFEG83I0uDgfujJdbL6kYU=
github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30=
github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo=
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/consensys/gnark-crypto v0.18.0 h1:vIye/FqI50VeAr0B3dx+YjeIvmc3LWz4yEfbWBpTUf0=
github.com/consensys/gnark-crypto v0.18.0/go.mod h1:L3mXGFTe1ZN+RSJ+CLjUt9x7PNdx8ubaYfDROyp2Z8c=
github.com/consensys/bavard v0.1.22 h1:Uw2CGvbXSZWhqK59X0VG/zOjpTFuOMcPLStrp1ihI0A=
github.com/consensys/bavard v0.1.22/go.mod h1:k/zVjHHC4B+PQy1Pg7fgvG3ALicQw540Crag8qx+dZs=
github.com/consensys/gnark-crypto v0.14.0 h1:DDBdl4HaBtdQsq/wfMwJvZNE80sHidrK3Nfrefatm0E=
github.com/consensys/gnark-crypto v0.14.0/go.mod h1:CU4UijNPsHawiVGNxe9co07FkzCeWHHrb1li/n1XoU0=
github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE=
github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw=
@@ -166,10 +170,8 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo=
github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/crate-crypto/go-eth-kzg v1.4.0 h1:WzDGjHk4gFg6YzV0rJOAsTK4z3Qkz5jd4RE3DAvPFkg=
github.com/crate-crypto/go-eth-kzg v1.4.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI=
github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a h1:W8mUrRp6NOVl3J+MYp5kPMoUZPp7aOYHtaua31lwRHg=
github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a/go.mod h1:sTwzHBvIzm2RfVCGNEBZgRyjwK40bVoun3ZnGOCafNM=
github.com/crate-crypto/go-kzg-4844 v1.1.0 h1:EN/u9k2TF6OWSHrCCDBBU6GLNMq88OspHHlMnHfoyU4=
@@ -184,14 +186,12 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU=
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U=
github.com/dchest/siphash v1.2.3 h1:QXwFc8cFOR2dSa/gE6o/HokBMWtLUaNDVd+22aKHeEA=
github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc=
github.com/deckarep/golang-set/v2 v2.8.0 h1:swm0rlPCmdWn9mESxKOjWk8hXSqoxOp+ZlfuyaAdFlQ=
github.com/deckarep/golang-set/v2 v2.8.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8=
github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM=
github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=
github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M=
github.com/deepmap/oapi-codegen v1.8.2 h1:SegyeYGcdi0jLLrpbCMoJxnUUn8GBXHsvr4rbzjuhfU=
github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw=
@@ -223,8 +223,8 @@ github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaB
github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs=
github.com/elastic/gosigar v0.14.3 h1:xwkKwPia+hSfg9GqrCUKYdId102m9qTJIIr7egmK/uo=
github.com/elastic/gosigar v0.14.3/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs=
github.com/emicklei/dot v1.6.2 h1:08GN+DD79cy/tzN6uLCT84+2Wk9u+wvqP+Hkx/dIR8A=
github.com/emicklei/dot v1.6.2/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s=
github.com/emicklei/dot v0.11.0 h1:Ase39UD9T9fRBOb5ptgpixrxfx8abVzNWZi2+lr53PI=
github.com/emicklei/dot v0.11.0/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s=
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
@@ -234,12 +234,12 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA=
github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0=
github.com/ethereum/c-kzg-4844/v2 v2.1.5 h1:aVtoLK5xwJ6c5RiqO8g8ptJ5KU+2Hdquf6G3aXiHh5s=
github.com/ethereum/c-kzg-4844/v2 v2.1.5/go.mod h1:u59hRTTah4Co6i9fDWtiCjTrblJv0UwsqZKCc0GfgUs=
github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab h1:rvv6MJhy07IMfEKuARQ9TKojGqLVNxQajaXEp/BoqSk=
github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab/go.mod h1:IuLm4IsPipXKF7CW5Lzf68PIbZ5yl7FFd74l/E0o9A8=
github.com/ethereum/go-ethereum v1.16.7 h1:qeM4TvbrWK0UC0tgkZ7NiRsmBGwsjqc64BHo20U59UQ=
github.com/ethereum/go-ethereum v1.16.7/go.mod h1:Fs6QebQbavneQTYcA39PEKv2+zIjX7rPUZ14DER46wk=
github.com/ethereum/go-ethereum v1.15.9 h1:bRra1zi+/q+qyXZ6fylZOrlaF8kDdnlTtzNTmNHfX+g=
github.com/ethereum/go-ethereum v1.15.9/go.mod h1:+S9k+jFzlyVTNcYGvqFhzN/SFhI6vA+aOY4T5tLSPL0=
github.com/ethereum/go-verkle v0.2.2 h1:I2W0WjnrFUIzzVPwm8ykY+7pL2d4VhlsePn4j7cnFk8=
github.com/ethereum/go-verkle v0.2.2/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
@@ -248,8 +248,8 @@ github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4Nij
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/ferranbt/fastssz v0.0.0-20210120143747-11b9eff30ea9/go.mod h1:DyEu2iuLBnb/T51BlsiO3yLYdJC6UbGMrIkqK1KmQxM=
github.com/ferranbt/fastssz v0.1.4 h1:OCDB+dYDEQDvAgtAGnTSidK1Pe2tW3nFV40XyMkTeDY=
github.com/ferranbt/fastssz v0.1.4/go.mod h1:Ea3+oeoRGGLGm5shYAeDgu6PGUlcvQhE2fILyD9+tGg=
github.com/ferranbt/fastssz v0.1.3 h1:ZI+z3JH05h4kgmFXdHuR1aWYsgrg7o+Fw7/NCzM16Mo=
github.com/ferranbt/fastssz v0.1.3/go.mod h1:0Y9TEd/9XuFlh7mskMPfXiI2Dkw4Ddg9EyXt1W7MRvE=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg=
github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag=
@@ -325,8 +325,8 @@ github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=
github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0=
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@@ -373,8 +373,8 @@ github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8l
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.5-0.20231225225746-43d5d4cd4e0e h1:4bw4WeyTYPp0smaXiJZCNnLrvVBqirQVreixayXezGc=
github.com/golang/snappy v0.0.5-0.20231225225746-43d5d4cd4e0e/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
@@ -418,6 +418,7 @@ github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8q
github.com/google/pprof v0.0.0-20250202011525-fc3143867406 h1:wlQI2cYY0BsWmmPPAnxfQ8SDW0S3Jasn+4B8kXFxprg=
github.com/google/pprof v0.0.0-20250202011525-fc3143867406/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -485,10 +486,12 @@ github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/J
github.com/herumi/bls-eth-go-binary v0.0.0-20210130185500-57372fb27371/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U=
github.com/herumi/bls-eth-go-binary v1.31.0 h1:9eeW3EA4epCb7FIHt2luENpAW69MvKGL5jieHlBiP+w=
github.com/herumi/bls-eth-go-binary v1.31.0/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U=
github.com/holiman/billy v0.0.0-20250707135307-f2f9b9aae7db h1:IZUYC/xb3giYwBLMnr8d0TGTzPKFGNTCGgGLoyeX330=
github.com/holiman/billy v0.0.0-20250707135307-f2f9b9aae7db/go.mod h1:xTEYN9KCHxuYHs+NmrmzFcnvHMzLLNiGFafCb1n3Mfg=
github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 h1:X4egAf/gcS1zATw6wn4Ej8vjuVGxeHdan+bRb2ebyv4=
github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc=
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
github.com/holiman/goevmlab v0.0.0-20241121133100-cfa6b078c8c4 h1:JHZ8k9n9G9KXIo1qrvK5Cxah6ax5BR0qVTA9bFYl1oM=
github.com/holiman/goevmlab v0.0.0-20241121133100-cfa6b078c8c4/go.mod h1:+DBd7lup47uusCYWbkJPfHRG4LYjBHvyXU0c+z26/U4=
github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA=
github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
@@ -546,8 +549,8 @@ github.com/kisielk/errcheck v1.8.0/go.mod h1:1kLL+jV4e+CFfueBmI1dSK2ADDyQnlrnrY/
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.9.8/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.10.1/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
@@ -643,8 +646,8 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
@@ -678,11 +681,13 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F
github.com/mitchellh/mapstructure v0.0.0-20170523030023-d0303fe80992/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A=
github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4=
github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY=
github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU=
github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -990,8 +995,8 @@ github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3
github.com/spf13/jwalterweatherman v0.0.0-20170901151539-12bd96e66386/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.1-0.20170901120850-7aff26db30c1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA=
github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg=
@@ -1028,18 +1033,20 @@ github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:
github.com/thomaso-mirodin/intmath v0.0.0-20160323211736-5dc6d854e46e h1:cR8/SYRgyQCt5cNCMniB/ZScMkhI9nk8U5C7SbISXjo=
github.com/thomaso-mirodin/intmath v0.0.0-20160323211736-5dc6d854e46e/go.mod h1:Tu4lItkATkonrYuvtVjG0/rhy15qrNGNTjPdaphtZ/8=
github.com/tjfoc/gmsm v1.3.0/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ=
github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4=
github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0=
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-20250212181730-4c2b8e9e784b h1:EBoYk5zHOfuHDBqLFx4eSPRVcbnW+L3aFJzoCi8zRnk=
github.com/trailofbits/go-mutexasserts v0.0.0-20250212181730-4c2b8e9e784b/go.mod h1:4R6Qam+w871wOlyRq59zRLjhb5x9/De/wgPeaCTaCwI=
github.com/umbracle/gohashtree v0.0.2-alpha.0.20230207094856-5b775a815c10 h1:CQh33pStIp/E30b7TxDlXfM0145bn2e8boI30IxAhTg=
github.com/umbracle/gohashtree v0.0.2-alpha.0.20230207094856-5b775a815c10/go.mod h1:x/Pa0FF5Te9kdrlZKJK82YmAkvL8+f989USgz6Jiw7M=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli/v2 v2.27.6 h1:VdRdS98FNhKZ8/Az8B7MTyGQmpIr36O1EHybx/LaZ4g=
github.com/urfave/cli/v2 v2.27.6/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w=
github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
github.com/uudashr/gocognit v1.0.5 h1:rrSex7oHr3/pPLQ0xoWq108XMU8s678FJcQ+aSfOHa4=
github.com/uudashr/gocognit v1.0.5/go.mod h1:wgYz0mitoKOTysqxTDMOUXg+Jb5SvtihkfmugIZYpEA=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
@@ -1074,8 +1081,8 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
@@ -1177,8 +1184,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI=
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ=
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c h1:KL/ZBHXgKGVmuZBZ01Lt57yE5ws8ZPSkkihmEyq7FXc=
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
golang.org/x/exp/typeparams v0.0.0-20231108232855-2478ac86f678 h1:1P7xPZEwZMoBoz0Yze5Nx2/4pxj6nw9ZqHWXqP0iRgQ=
golang.org/x/exp/typeparams v0.0.0-20231108232855-2478ac86f678/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
@@ -1384,6 +1391,7 @@ golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
@@ -1685,6 +1693,8 @@ lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU=
rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=

View File

@@ -18,6 +18,7 @@ go_library(
importpath = "github.com/OffchainLabs/prysm/v7/runtime/debug",
visibility = ["//visibility:public"],
deps = [
"//cmd:go_default_library",
"@com_github_prometheus_client_golang//prometheus:go_default_library",
"@com_github_prometheus_client_golang//prometheus/promauto:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",

View File

@@ -18,6 +18,7 @@ package debug
import (
"bytes"
"context"
"errors"
"fmt"
"io"
@@ -37,6 +38,7 @@ import (
"sync"
"time"
"github.com/OffchainLabs/prysm/v7/cmd"
log "github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
)
@@ -78,6 +80,11 @@ var (
Name: "blockprofilerate",
Usage: "Turns on block profiling with the given rate.",
}
// HeapDumpThresholdFlag sets the memory threshold in MB for automatic heap dumps.
HeapDumpThresholdFlag = &cli.Uint64Flag{
Name: "heap-dump-threshold-mb",
Usage: "If set to a value > 0, automatically dump heap profile when heap memory exceeds this threshold in MB.",
}
)
// HandlerT implements the debugging API.
@@ -91,6 +98,20 @@ type HandlerT struct {
traceFile string
}
// memoryMonitor tracks heap memory and triggers dumps when threshold exceeded.
type memoryMonitor struct {
ctx context.Context
thresholdBytes uint64
dumpDir string
latestDumpTime time.Time
mu sync.Mutex
}
const (
heapDumpCooldownPeriod = 5 * time.Minute
heapCheckIntervalPeriod = 5 * time.Second
)
// MemStats returns detailed runtime memory statistics.
func (*HandlerT) MemStats() *runtime.MemStats {
s := new(runtime.MemStats)
@@ -105,6 +126,107 @@ func (*HandlerT) GcStats() *debug.GCStats {
return s
}
// startMemoryMonitoring initializes and starts the memory monitoring goroutine.
func startMemoryMonitoring(ctx context.Context, thresholdMB uint64, dumpDir string) error {
// Ensure dump directory exists
if err := os.MkdirAll(dumpDir, 0755); err != nil {
return fmt.Errorf("failed to create heap dump directory: %w", err)
}
monitor := &memoryMonitor{
ctx: ctx,
thresholdBytes: thresholdMB * 1024 * 1024,
dumpDir: dumpDir,
latestDumpTime: time.Time{}, // zero time means never dumped
}
go monitor.monitorLoop()
log.WithFields(log.Fields{
"thresholdMB": thresholdMB,
"cooldownPeriod": heapDumpCooldownPeriod,
"dumpDirectory": dumpDir,
"checkIntervalPeriod": heapCheckIntervalPeriod,
}).Info("Started heap dump monitoring")
return nil
}
// monitorLoop periodically checks heap memory and triggers dumps.
func (m *memoryMonitor) monitorLoop() {
ticker := time.NewTicker(heapCheckIntervalPeriod)
for {
select {
case <-m.ctx.Done():
log.Debug("Context done, stopping heap memory monitoring")
return
case <-ticker.C:
m.checkAndDumpIfNeeded()
}
}
}
// checkAndDumpIfNeeded checks current heap size and dumps if threshold exceeded.
func (m *memoryMonitor) checkAndDumpIfNeeded() {
var memStats runtime.MemStats
runtime.ReadMemStats(&memStats)
heapInUseMB := memStats.HeapInuse / (1024 * 1024)
// Use HeapInuse (currently allocated from OS) as the threshold metric
// This is more stable than HeapAlloc which fluctuates with GC
if memStats.HeapInuse < m.thresholdBytes {
return
}
m.mu.Lock()
defer m.mu.Unlock()
// Check cooldown period
if time.Since(m.latestDumpTime) < heapDumpCooldownPeriod {
log.WithFields(log.Fields{
"heapInUseMB": heapInUseMB,
"thresholdMB": m.thresholdBytes / (1024 * 1024),
"timeSinceLatestDump": time.Since(m.latestDumpTime).String(),
"cooldown": heapDumpCooldownPeriod,
}).Debug("Heap threshold exceeded but in cooldown period")
return
}
// Create timestamped filename
timestamp := time.Now().Format("20060102-150405")
basename := fmt.Sprintf("heap-%s-%dmb.prof", timestamp, heapInUseMB)
basepath := filepath.Join(m.dumpDir, basename)
log.WithFields(log.Fields{
"heapInUseMB": heapInUseMB,
"thresholdMB": m.thresholdBytes / (1024 * 1024),
}).Warning("Heap memory threshold exceeded, dumping profiles")
if err := Handler.WriteMemProfile(fmt.Sprintf("%s-heap.prof", basepath)); err != nil {
log.WithError(err).Error("Failed to write automatic heap dump")
return
}
if err := Handler.WriteBlockProfile(fmt.Sprintf("%s-block.prof", basepath)); err != nil {
log.WithError(err).Error("Failed to write automatic block dump")
return
}
if err := Handler.WriteGoroutineProfile(fmt.Sprintf("%s-goroutine.prof", basepath)); err != nil {
log.WithError(err).Error("Failed to write automatic goroutine dump")
return
}
if err := Handler.WriteMutexProfile(fmt.Sprintf("%s-mutex.prof", basepath)); err != nil {
log.WithError(err).Error("Failed to write automatic mutex dump")
return
}
m.latestDumpTime = time.Now()
}
// CPUProfile turns on CPU profiling for nsec seconds and writes
// profile data to file.
func (h *HandlerT) CPUProfile(file string, nsec uint) error {
@@ -253,6 +375,11 @@ func (*HandlerT) WriteMemProfile(file string) error {
return writeProfile("heap", file)
}
// WriteMutexProfile writes a goroutine profile to the given file.
func (*HandlerT) WriteGoroutineProfile(file string) error {
return writeProfile("goroutine", file)
}
// Stacks returns a printed representation of the stacks of all goroutines.
func (*HandlerT) Stacks() string {
buf := new(bytes.Buffer)
@@ -275,7 +402,11 @@ func (*HandlerT) SetGCPercent(v int) int {
func writeProfile(name, file string) error {
p := pprof.Lookup(name)
log.Info("Writing profile records", "count", p.Count(), "type", name, "dump", file)
log.WithFields(log.Fields{
"count": p.Count(),
"type": name,
"dump": file,
}).Info("Writing profile records")
f, err := os.Create(expandHome(file))
if err != nil {
return err
@@ -323,6 +454,15 @@ func Setup(ctx *cli.Context) error {
address := fmt.Sprintf("%s:%d", ctx.String(PProfAddrFlag.Name), ctx.Int(PProfPortFlag.Name))
startPProf(address)
}
// automatic heap dump monitoring
thresholdMB := ctx.Uint64(HeapDumpThresholdFlag.Name)
if thresholdMB > 0 {
dataDir := ctx.String(cmd.DataDirFlag.Name)
dumpDir := filepath.Join(dataDir, "pprof-dumps")
if err := startMemoryMonitoring(ctx.Context, thresholdMB, dumpDir); err != nil {
return fmt.Errorf("failed to start memory monitoring: %w", err)
}
}
return nil
}

View File

@@ -99,7 +99,7 @@ func GethCancunTime(genesisTime time.Time, cfg *clparams.BeaconChainConfig) *uin
}
// GethPragueTime calculates the absolute time of the prague (aka electra) fork block
// by adding the relative time of the electra fork epoch to the given genesis timestamp.
// by adding the relative time of the capella the fork epoch to the given genesis timestamp.
func GethPragueTime(genesisTime time.Time, cfg *clparams.BeaconChainConfig) *uint64 {
var pragueTime *uint64
if cfg.ElectraForkEpoch != math.MaxUint64 {
@@ -128,45 +128,6 @@ func GethOsakaTime(genesisTime time.Time, cfg *clparams.BeaconChainConfig) *uint
return osakaTime
}
// GethBPO1Time calculates the absolute time of the BPO1 activation
// by finding the first BlobSchedule entry with MaxBlobsPerBlock > 9 (Electra's limit)
// which corresponds to the first BPO increase.
func GethBPO1Time(genesisTime time.Time, cfg *clparams.BeaconChainConfig) *uint64 {
for _, entry := range cfg.BlobSchedule {
// BPO1 is the first entry that increases beyond Electra's 9 blobs
if entry.MaxBlobsPerBlock > uint64(cfg.DeprecatedMaxBlobsPerBlockElectra) {
startSlot, err := slots.EpochStart(entry.Epoch)
if err == nil {
startTime := slots.UnsafeStartTime(genesisTime, startSlot)
newTime := uint64(startTime.Unix())
return &newTime
}
}
}
return nil
}
// GethBPO2Time calculates the absolute time of the BPO2 activation
// by finding the second BlobSchedule entry with MaxBlobsPerBlock > 9.
func GethBPO2Time(genesisTime time.Time, cfg *clparams.BeaconChainConfig) *uint64 {
count := 0
for _, entry := range cfg.BlobSchedule {
// Count entries that are beyond Electra's limit
if entry.MaxBlobsPerBlock > uint64(cfg.DeprecatedMaxBlobsPerBlockElectra) {
count++
if count == 2 { // BPO2 is the second such entry
startSlot, err := slots.EpochStart(entry.Epoch)
if err == nil {
startTime := slots.UnsafeStartTime(genesisTime, startSlot)
newTime := uint64(startTime.Unix())
return &newTime
}
}
}
}
return nil
}
// GethTestnetGenesis creates a genesis.json for eth1 clients with a set of defaults suitable for ephemeral testnets,
// like in an e2e test. The parameters are minimal but the full value is returned unmarshaled so that it can be
// customized as desired.
@@ -188,8 +149,6 @@ func GethTestnetGenesis(genesis time.Time, cfg *clparams.BeaconChainConfig) *cor
if cfg.FuluForkEpoch == 0 {
osakaTime = &genesisTime
}
bpo1Time := GethBPO1Time(genesis, cfg)
bpo2Time := GethBPO2Time(genesis, cfg)
cc := &params.ChainConfig{
ChainID: big.NewInt(defaultTestChainId),
HomesteadBlock: bigz,
@@ -212,16 +171,18 @@ func GethTestnetGenesis(genesis time.Time, cfg *clparams.BeaconChainConfig) *cor
CancunTime: cancunTime,
PragueTime: pragueTime,
OsakaTime: osakaTime,
BPO1Time: bpo1Time,
BPO2Time: bpo2Time,
DepositContractAddress: common.HexToAddress(cfg.DepositContractAddress),
BlobScheduleConfig: &params.BlobScheduleConfig{
Cancun: params.DefaultCancunBlobConfig,
Prague: params.DefaultPragueBlobConfig,
Osaka: params.DefaultOsakaBlobConfig,
BPO1: params.DefaultBPO1BlobConfig,
BPO2: params.DefaultBPO2BlobConfig,
BPO3: params.DefaultBPO3BlobConfig,
Cancun: &params.BlobConfig{
Target: 3,
Max: 6,
UpdateFraction: 3338477,
},
Prague: &params.BlobConfig{
Target: 6,
Max: 9,
UpdateFraction: 5007716,
},
},
}
da := defaultDepositContractAllocation(cfg.DepositContractAddress)

View File

@@ -1,4 +1,4 @@
version: v1.7.0-alpha.1
version: v1.7.0-alpha.0
style: full
specrefs:
@@ -117,8 +117,6 @@ exceptions:
dataclasses:
# Not implemented
- BlobParameters#fulu
- ExpectedWithdrawals#capella
- ExpectedWithdrawals#electra
- LatestMessage#phase0
- LightClientStore#altair
- OptimisticStore#bellatrix
@@ -128,7 +126,6 @@ exceptions:
- LightClientStore#capella
# Not implemented: gloas (future fork)
- ExpectedWithdrawals#gloas
- LatestMessage#gloas
- Store#gloas

View File

@@ -34,26 +34,6 @@
blobs: List[Blob, MAX_BLOB_COMMITMENTS_PER_BLOCK]
</spec>
- name: ExpectedWithdrawals#capella
sources: []
spec: |
<spec dataclass="ExpectedWithdrawals" fork="capella" hash="73becb4c">
class ExpectedWithdrawals(object):
withdrawals: Sequence[Withdrawal]
processed_sweep_withdrawals_count: uint64
</spec>
- name: ExpectedWithdrawals#electra
sources: []
spec: |
<spec dataclass="ExpectedWithdrawals" fork="electra" hash="a3827f01">
class ExpectedWithdrawals(object):
withdrawals: Sequence[Withdrawal]
# [New in Electra:EIP7251]
processed_partial_withdrawals_count: uint64
processed_sweep_withdrawals_count: uint64
</spec>
- name: GetPayloadResponse#bellatrix
sources:
- file: consensus-types/blocks/get_payload.go

View File

@@ -2366,8 +2366,8 @@
- file: beacon-chain/state/state-native/getters_withdrawal.go
search: func (b *BeaconState) ExpectedWithdrawals(
spec: |
<spec fn="get_expected_withdrawals" fork="capella" hash="12088347">
def get_expected_withdrawals(state: BeaconState) -> ExpectedWithdrawals:
<spec fn="get_expected_withdrawals" fork="capella" hash="d6a98c14">
def get_expected_withdrawals(state: BeaconState) -> Tuple[Sequence[Withdrawal], uint64]:
withdrawal_index = state.next_withdrawal_index
withdrawals: List[Withdrawal] = []
@@ -2377,10 +2377,7 @@
)
withdrawals.extend(validators_sweep_withdrawals)
return ExpectedWithdrawals(
withdrawals,
processed_validators_sweep_count,
)
return withdrawals, processed_validators_sweep_count
</spec>
- name: get_expected_withdrawals#electra
@@ -2388,8 +2385,8 @@
- file: beacon-chain/state/state-native/getters_withdrawal.go
search: func (b *BeaconState) ExpectedWithdrawals(
spec: |
<spec fn="get_expected_withdrawals" fork="electra" hash="254541e3">
def get_expected_withdrawals(state: BeaconState) -> ExpectedWithdrawals:
<spec fn="get_expected_withdrawals" fork="electra" hash="cfce862b">
def get_expected_withdrawals(state: BeaconState) -> Tuple[Sequence[Withdrawal], uint64, uint64]:
withdrawal_index = state.next_withdrawal_index
withdrawals: List[Withdrawal] = []
@@ -2406,12 +2403,8 @@
)
withdrawals.extend(validators_sweep_withdrawals)
return ExpectedWithdrawals(
withdrawals,
# [New in Electra:EIP7251]
processed_partial_withdrawals_count,
processed_validators_sweep_count,
)
# [Modified in Electra:EIP7251]
return withdrawals, processed_partial_withdrawals_count, processed_validators_sweep_count
</spec>
- name: get_filtered_block_tree
@@ -4939,7 +4932,7 @@
- name: prepare_execution_payload#capella
sources: []
spec: |
<spec fn="prepare_execution_payload" fork="capella" hash="998e8b92">
<spec fn="prepare_execution_payload" fork="capella" hash="c258893e">
def prepare_execution_payload(
state: BeaconState,
safe_block_hash: Hash32,
@@ -4952,12 +4945,15 @@
parent_hash = state.latest_execution_payload_header.block_hash
# Set the forkchoice head and initiate the payload build process
# [New in Capella]
withdrawals, _ = get_expected_withdrawals(state)
payload_attributes = PayloadAttributes(
timestamp=compute_time_at_slot(state, state.slot),
prev_randao=get_randao_mix(state, get_current_epoch(state)),
suggested_fee_recipient=suggested_fee_recipient,
# [New in Capella]
withdrawals=get_expected_withdrawals(state).withdrawals,
withdrawals=withdrawals,
)
return execution_engine.notify_forkchoice_updated(
head_block_hash=parent_hash,
@@ -4970,7 +4966,7 @@
- name: prepare_execution_payload#deneb
sources: []
spec: |
<spec fn="prepare_execution_payload" fork="deneb" hash="c617aa1b">
<spec fn="prepare_execution_payload" fork="deneb" hash="59f61f3a">
def prepare_execution_payload(
state: BeaconState,
safe_block_hash: Hash32,
@@ -4982,11 +4978,13 @@
parent_hash = state.latest_execution_payload_header.block_hash
# Set the forkchoice head and initiate the payload build process
withdrawals, _ = get_expected_withdrawals(state)
payload_attributes = PayloadAttributes(
timestamp=compute_time_at_slot(state, state.slot),
prev_randao=get_randao_mix(state, get_current_epoch(state)),
suggested_fee_recipient=suggested_fee_recipient,
withdrawals=get_expected_withdrawals(state).withdrawals,
withdrawals=withdrawals,
# [New in Deneb:EIP4788]
parent_beacon_block_root=hash_tree_root(state.latest_block_header),
)
@@ -5001,7 +4999,7 @@
- name: prepare_execution_payload#electra
sources: []
spec: |
<spec fn="prepare_execution_payload" fork="electra" hash="c617aa1b">
<spec fn="prepare_execution_payload" fork="electra" hash="5414b883">
def prepare_execution_payload(
state: BeaconState,
safe_block_hash: Hash32,
@@ -5012,13 +5010,15 @@
# Verify consistency of the parent hash with respect to the previous execution payload header
parent_hash = state.latest_execution_payload_header.block_hash
# [Modified in EIP7251]
# Set the forkchoice head and initiate the payload build process
withdrawals, _, _ = get_expected_withdrawals(state)
payload_attributes = PayloadAttributes(
timestamp=compute_time_at_slot(state, state.slot),
prev_randao=get_randao_mix(state, get_current_epoch(state)),
suggested_fee_recipient=suggested_fee_recipient,
withdrawals=get_expected_withdrawals(state).withdrawals,
# [New in Deneb:EIP4788]
withdrawals=withdrawals,
parent_beacon_block_root=hash_tree_root(state.latest_block_header),
)
return execution_engine.notify_forkchoice_updated(
@@ -6272,8 +6272,8 @@
- name: process_operations#electra
sources:
- file: beacon-chain/core/transition/electra.go
search: func electraOperations(
- file: beacon-chain/core/electra/transition_no_verify_sig.go
search: func ProcessOperations(
spec: |
<spec fn="process_operations" fork="electra" hash="643f18b4">
def process_operations(state: BeaconState, body: BeaconBlockBody) -> None:
@@ -7071,18 +7071,18 @@
- file: beacon-chain/core/blocks/withdrawals.go
search: func ProcessWithdrawals(
spec: |
<spec fn="process_withdrawals" fork="capella" hash="47327ef6">
<spec fn="process_withdrawals" fork="capella" hash="901f9fc4">
def process_withdrawals(state: BeaconState, payload: ExecutionPayload) -> None:
# Get expected withdrawals
expected = get_expected_withdrawals(state)
assert payload.withdrawals == expected.withdrawals
withdrawals, processed_validators_sweep_count = get_expected_withdrawals(state)
assert payload.withdrawals == withdrawals
# Apply expected withdrawals
apply_withdrawals(state, expected.withdrawals)
apply_withdrawals(state, withdrawals)
# Update withdrawals fields in the state
update_next_withdrawal_index(state, expected.withdrawals)
update_next_withdrawal_validator_index(state, expected.withdrawals)
update_next_withdrawal_index(state, withdrawals)
update_next_withdrawal_validator_index(state, processed_validators_sweep_count)
</spec>
- name: process_withdrawals#electra
@@ -7090,20 +7090,23 @@
- file: beacon-chain/core/blocks/withdrawals.go
search: func ProcessWithdrawals(
spec: |
<spec fn="process_withdrawals" fork="electra" hash="24a50daa">
<spec fn="process_withdrawals" fork="electra" hash="67870972">
def process_withdrawals(state: BeaconState, payload: ExecutionPayload) -> None:
# [Modified in Electra:EIP7251]
# Get expected withdrawals
expected = get_expected_withdrawals(state)
assert payload.withdrawals == expected.withdrawals
withdrawals, processed_partial_withdrawals_count, processed_validators_sweep_count = (
get_expected_withdrawals(state)
)
assert payload.withdrawals == withdrawals
# Apply expected withdrawals
apply_withdrawals(state, expected.withdrawals)
apply_withdrawals(state, withdrawals)
# Update withdrawals fields in the state
update_next_withdrawal_index(state, expected.withdrawals)
update_next_withdrawal_index(state, withdrawals)
# [New in Electra:EIP7251]
update_pending_partial_withdrawals(state, expected.processed_partial_withdrawals_count)
update_next_withdrawal_validator_index(state, expected.withdrawals)
update_pending_partial_withdrawals(state, processed_partial_withdrawals_count)
update_next_withdrawal_validator_index(state, processed_validators_sweep_count)
</spec>
- name: queue_excess_active_balance

View File

@@ -5,7 +5,6 @@ load("@prysm//tools/go:def.bzl", "go_test")
# gazelle:exclude mainnet_scenario_e2e_test.go
# gazelle:exclude minimal_scenario_e2e_test.go
# gazelle:exclude minimal_builder_e2e_test.go
# gazelle:exclude minimal_postmerge_e2e_test.go
# Presubmit tests represent the group of endtoend tests that are run on pull
# requests and must be passing before a pull request can merge.
@@ -28,7 +27,6 @@ test_suite(
],
tests = [
":go_builder_test",
":go_minimal_postmerge_test",
":go_mainnet_test",
],
)
@@ -90,7 +88,7 @@ common_deps = [
# gazelle:ignore
go_test(
name = "go_default_test",
size = "enormous",
size = "large",
testonly = True,
srcs = [
"component_handler_test.go",
@@ -155,39 +153,6 @@ go_test(
deps = common_deps,
)
# Full e2e test from post-merge (Bellatrix) through all forks (post-submit only, takes longer)
go_test(
name = "go_minimal_postmerge_test",
size = "enormous",
testonly = True,
srcs = [
"component_handler_test.go",
"endtoend_setup_test.go",
"endtoend_test.go",
"minimal_postmerge_e2e_test.go",
],
args = ["-test.v"],
data = [
"//:prysm_sh",
"//cmd/beacon-chain",
"//cmd/validator",
"//config/params:custom_configs",
"//tools/bootnode",
"@com_github_ethereum_go_ethereum//cmd/geth",
"@web3signer",
],
eth_network = "minimal",
flaky = True,
shard_count = 2,
tags = [
"e2e",
"manual",
"minimal",
"requires-network",
],
deps = common_deps,
)
go_test(
name = "go_mainnet_test",
size = "large",

View File

@@ -15,7 +15,6 @@ go_library(
importpath = "github.com/OffchainLabs/prysm/v7/testing/endtoend/components/eth1",
visibility = ["//testing/endtoend:__subpackages__"],
deps = [
"//beacon-chain/startup:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//contracts/deposit:go_default_library",
@@ -39,6 +38,8 @@ go_library(
"@com_github_ethereum_go_ethereum//ethclient/gethclient:go_default_library",
"@com_github_ethereum_go_ethereum//rpc:go_default_library",
"@com_github_holiman_uint256//:go_default_library",
"@com_github_mariusvanderwijden_fuzzyvm//filler:go_default_library",
"@com_github_mariusvanderwijden_tx_fuzz//:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@io_bazel_rules_go//go/tools/bazel:go_default_library",

View File

@@ -267,10 +267,6 @@ func (d *Depositor) txops(ctx context.Context) (*bind.TransactOpts, error) {
return nil, err
}
txo.Nonce = big.NewInt(0).SetUint64(nonce)
// Set a high gas price to ensure deposit transactions can replace any pending
// transactions from the transaction generator that may be using the same nonce.
// The transaction generator uses 1e11 (100 Gwei), so we use 2e11 (200 Gwei).
txo.GasPrice = big.NewInt(2e11)
return txo, nil
}

View File

@@ -3,7 +3,6 @@ package eth1
import (
"context"
"math/big"
"strings"
"time"
"github.com/OffchainLabs/prysm/v7/testing/endtoend/params"
@@ -32,6 +31,10 @@ var _ e2etypes.EngineProxy = (*Proxy)(nil)
// WaitForBlocks waits for a certain amount of blocks to be mined by the ETH1 chain before returning.
func WaitForBlocks(ctx context.Context, web3 *ethclient.Client, key *keystore.Key, blocksToWait uint64) error {
nonce, err := web3.PendingNonceAt(ctx, key.Address)
if err != nil {
return err
}
chainID, err := web3.NetworkID(ctx)
if err != nil {
return err
@@ -46,36 +49,19 @@ func WaitForBlocks(ctx context.Context, web3 *ethclient.Client, key *keystore.Ke
if ctx.Err() != nil {
return ctx.Err()
}
// Get fresh nonce each iteration to handle any pending transactions
nonce, err := web3.PendingNonceAt(ctx, key.Address)
if err != nil {
return err
}
gasPrice, err := web3.SuggestGasPrice(ctx)
if err != nil {
return err
}
// Bump gas price by 20% to ensure we can replace any pending transactions
gasPrice = new(big.Int).Mul(gasPrice, big.NewInt(120))
gasPrice = new(big.Int).Div(gasPrice, big.NewInt(100))
spamTX := types.NewTransaction(nonce, key.Address, big.NewInt(0), params.SpamTxGasLimit, gasPrice, []byte{})
signed, err := types.SignTx(spamTX, types.NewEIP155Signer(chainID), key.PrivateKey)
if err != nil {
return err
}
if err = web3.SendTransaction(ctx, signed); err != nil {
// If replacement error, try again with next iteration which will get fresh nonce
if strings.Contains(err.Error(), "replacement transaction underpriced") {
time.Sleep(timeGapPerMiningTX)
block, err = web3.BlockByNumber(ctx, nil)
if err != nil {
return err
}
continue
}
return err
}
nonce++
time.Sleep(timeGapPerMiningTX)
block, err = web3.BlockByNumber(ctx, nil)
if err != nil {

View File

@@ -10,7 +10,8 @@ import (
"os"
"time"
"github.com/OffchainLabs/prysm/v7/beacon-chain/startup"
"github.com/MariusVanDerWijden/FuzzyVM/filler"
txfuzz "github.com/MariusVanDerWijden/tx-fuzz"
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/crypto/rand"
@@ -34,12 +35,11 @@ const txCount = 20
var fundedAccount *keystore.Key
type TransactionGenerator struct {
keystore string
seed int64
started chan struct{}
cancel context.CancelFunc
paused bool
useLargeBlobs bool // Use large blob transactions (6 blobs per tx) for BPO testing
keystore string
seed int64
started chan struct{}
cancel context.CancelFunc
paused bool
}
func (t *TransactionGenerator) UnderlyingProcess() *os.Process {
@@ -48,8 +48,8 @@ func (t *TransactionGenerator) UnderlyingProcess() *os.Process {
return &os.Process{}
}
func NewTransactionGenerator(keystore string, seed int64, useLargeBlobs bool) *TransactionGenerator {
return &TransactionGenerator{keystore: keystore, seed: seed, useLargeBlobs: useLargeBlobs}
func NewTransactionGenerator(keystore string, seed int64) *TransactionGenerator {
return &TransactionGenerator{keystore: keystore, seed: seed}
}
func (t *TransactionGenerator) Start(ctx context.Context) error {
@@ -67,7 +67,7 @@ func (t *TransactionGenerator) Start(ctx context.Context) error {
newGen := rand.NewDeterministicGenerator()
if seed == 0 {
seed = newGen.Int63()
logrus.WithField("Seed", seed).Info("Transaction generator")
logrus.Infof("Seed for transaction generator is: %d", seed)
}
// Set seed so that all transactions can be
// deterministically generated.
@@ -86,21 +86,12 @@ func (t *TransactionGenerator) Start(ctx context.Context) error {
return err
}
fundedAccount = newKey
// Ensure funding tx is mined before generating txs that rely on balance.
// Mine 1 block using the miner key to include the funding transfer.
backend := ethclient.NewClient(client)
defer backend.Close()
if err := WaitForBlocks(ctx, backend, mineKey, 1); err != nil {
return errors.Wrap(err, "failed to mine block for funding tx")
}
// Ensure the funded account has a comfortable minimum balance for blob and fuzzed txs.
minWei := new(big.Int).Mul(big.NewInt(1000), big.NewInt(0).SetUint64(params.BeaconConfig().GweiPerEth))
minWei.Mul(minWei, big.NewInt(1e9)) // 1000 ETH in wei
if err := ensureMinBalance(ctx, client, backend, mineKey, fundedAccount, minWei); err != nil {
rnd := make([]byte, 10000)
_, err = mathRand.Read(rnd) // #nosec G404
if err != nil {
return err
}
f := filler.NewFiller(rnd)
// Broadcast Transactions every slot
txPeriod := time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second
ticker := time.NewTicker(txPeriod)
@@ -114,7 +105,7 @@ func (t *TransactionGenerator) Start(ctx context.Context) error {
continue
}
backend := ethclient.NewClient(client)
err = SendTransaction(client, mineKey.PrivateKey, gasPrice, mineKey.Address.String(), txCount, backend, false, t.useLargeBlobs)
err = SendTransaction(client, mineKey.PrivateKey, f, gasPrice, mineKey.Address.String(), txCount, backend, false)
if err != nil {
return err
}
@@ -128,7 +119,7 @@ func (s *TransactionGenerator) Started() <-chan struct{} {
return s.started
}
func SendTransaction(client *rpc.Client, key *ecdsa.PrivateKey, gasPrice *big.Int, addr string, txCount uint64, backend *ethclient.Client, al bool, useLargeBlobs bool) error {
func SendTransaction(client *rpc.Client, key *ecdsa.PrivateKey, f *filler.Filler, gasPrice *big.Int, addr string, N uint64, backend *ethclient.Client, al bool) error {
sender := common.HexToAddress(addr)
nonce, err := backend.PendingNonceAt(context.Background(), fundedAccount.Address)
if err != nil {
@@ -145,63 +136,30 @@ func SendTransaction(client *rpc.Client, key *ecdsa.PrivateKey, gasPrice *big.In
if expectedPrice.Cmp(gasPrice) > 0 {
gasPrice = expectedPrice
}
// Check if we're post-Fulu fork
clock := startup.NewClock(e2e.TestParams.CLGenesisTime, [32]byte{})
isPostFulu := clock.CurrentEpoch() >= params.BeaconConfig().FuluForkEpoch
g, _ := errgroup.WithContext(context.Background())
txs := make([]*types.Transaction, 10)
// Send blob transactions - use different versions pre/post Fulu
if isPostFulu {
logrus.Info("Sending blob transactions with cell proofs")
// Reduced from 10 to 5 to reduce load and prevent builder/EL timeouts
for index := range uint64(5) {
g.Go(func() error {
tx, err := RandomBlobCellTx(client, fundedAccount.Address, nonce+index, gasPrice, chainid, al, useLargeBlobs)
if err != nil {
return errors.Wrap(err, "Could not create blob cell tx")
}
signedTx, err := types.SignTx(tx, types.NewCancunSigner(chainid), fundedAccount.PrivateKey)
if err != nil {
return errors.Wrap(err, "Could not sign blob cell tx")
}
txs[index] = signedTx
for i := range uint64(10) {
index := i
g.Go(func() error {
tx, err := RandomBlobTx(client, f, fundedAccount.Address, nonce+index, gasPrice, chainid, al)
if err != nil {
logrus.WithError(err).Error("Could not create blob tx")
// In the event the transaction constructed is not valid, we continue with the routine
// rather than complete stop it.
//nolint:nilerr
return nil
})
}
} else {
logrus.Info("Sending blob transactions with sidecars")
// Reduced from 10 to 5 to reduce load and prevent builder/EL timeouts
for index := range uint64(5) {
g.Go(func() error {
tx, err := RandomBlobTx(client, fundedAccount.Address, nonce+index, gasPrice, chainid, al, useLargeBlobs)
if err != nil {
logrus.WithError(err).Error("Could not create blob tx")
// In the event the transaction constructed is not valid, we continue with the routine
// rather than complete stop it.
//nolint:nilerr
return nil
}
signedTx, err := types.SignTx(tx, types.NewCancunSigner(chainid), fundedAccount.PrivateKey)
if err != nil {
logrus.WithError(err).Error("Could not sign blob tx")
// We continue on in the event there is a reason we can't sign this
// transaction(unlikely).
//nolint:nilerr
return nil
}
txs[index] = signedTx
}
signedTx, err := types.SignTx(tx, types.NewCancunSigner(chainid), fundedAccount.PrivateKey)
if err != nil {
logrus.WithError(err).Error("Could not sign blob tx")
// We continue on in the event there is a reason we can't sign this
// transaction(unlikely).
//nolint:nilerr
return nil
})
}
}
txs[index] = signedTx
return nil
})
}
if err := g.Wait(); err != nil {
@@ -211,7 +169,6 @@ func SendTransaction(client *rpc.Client, key *ecdsa.PrivateKey, gasPrice *big.In
if tx == nil {
continue
}
err = backend.SendTransaction(context.Background(), tx)
if err != nil {
// Do nothing
@@ -224,20 +181,17 @@ func SendTransaction(client *rpc.Client, key *ecdsa.PrivateKey, gasPrice *big.In
return err
}
txs = make([]*types.Transaction, txCount)
for index := range txCount {
txs = make([]*types.Transaction, N)
for i := range N {
index := i
g.Go(func() error {
tx, err := randomValidTx(sender, nonce+index, gasPrice, chainid, al)
tx, err := txfuzz.RandomValidTx(client, f, sender, nonce+index, gasPrice, chainid, al)
if err != nil {
// In the event the transaction constructed is not valid, we continue with the routine
// rather than complete stop it.
//nolint:nilerr
return nil
}
// Clamp gas to avoid exceeding common EL per-tx gas caps (e.g. 16,777,216) due to EIP-7825: Transaction Gas Limit Cap
tx = clampTxGas(tx, 16_000_000)
signedTx, err := types.SignTx(tx, types.NewLondonSigner(chainid), key)
if err != nil {
// We continue on in the event there is a reason we can't sign this
@@ -283,13 +237,11 @@ func (t *TransactionGenerator) Stop() error {
return nil
}
func RandomBlobCellTx(rpc *rpc.Client, sender common.Address, nonce uint64, gasPrice, chainID *big.Int, al bool, useLargeBlobs bool) (*types.Transaction, error) {
func RandomBlobTx(rpc *rpc.Client, f *filler.Filler, sender common.Address, nonce uint64, gasPrice, chainID *big.Int, al bool) (*types.Transaction, error) {
// Set fields if non-nil
if rpc != nil {
client := ethclient.NewClient(rpc)
var err error
if gasPrice == nil {
gasPrice, err = client.SuggestGasPrice(context.Background())
if err != nil {
@@ -303,133 +255,27 @@ func RandomBlobCellTx(rpc *rpc.Client, sender common.Address, nonce uint64, gasP
}
}
}
gas := uint64(100000)
to := randomAddress()
// Generate random EVM bytecode (similar to what tx-fuzz RandomCode did)
code := generateRandomEVMCode(mathRand.Intn(128)) // #nosec G404
code := txfuzz.RandomCode(f)
value := big.NewInt(0)
if len(code) > 128 {
code = code[:128]
}
mod := 2
if al {
mod = 1
}
// Helper to get blob data based on config
getBlobData := func() ([]byte, error) {
if useLargeBlobs {
return randomBlobDataLarge()
}
return randomBlobData()
}
// #nosec G404 -- Test code uses deterministic randomness
switch mathRand.Intn(mod) {
case 0:
// Blob transaction with cell proofs (Version 1 sidecar)
tip, feecap, err := getCaps(rpc, gasPrice)
if err != nil {
return nil, errors.Wrap(err, "getCaps")
}
data, err := getBlobData()
if err != nil {
return nil, errors.Wrap(err, "getBlobData")
}
return New4844CellTx(nonce, &to, gas, chainID, tip, feecap, value, code, big.NewInt(1000000), data, make(types.AccessList, 0))
case 1:
// Blob transaction with cell proofs and access list
tx := types.NewTx(&types.LegacyTx{
Nonce: nonce,
To: &to,
Value: value,
Gas: gas,
GasPrice: gasPrice,
Data: code,
})
// Use legacy GasPrice for access list simulation to satisfy post-London requirement.
msg := ethereum.CallMsg{
From: sender,
To: tx.To(),
Gas: tx.Gas(),
GasPrice: gasPrice,
Value: tx.Value(),
Data: tx.Data(),
AccessList: nil,
}
geth := gethclient.New(rpc)
al, _, _, err := geth.CreateAccessList(context.Background(), msg)
if err != nil {
return nil, errors.Wrap(err, "CreateAccessList")
}
tip, feecap, err := getCaps(rpc, gasPrice)
if err != nil {
return nil, errors.Wrap(err, "getCaps")
}
data, err := getBlobData()
if err != nil {
return nil, errors.Wrap(err, "getBlobData")
}
return New4844CellTx(nonce, &to, gas, chainID, tip, feecap, value, code, big.NewInt(1000000), data, *al)
}
return nil, nil
}
func RandomBlobTx(rpc *rpc.Client, sender common.Address, nonce uint64, gasPrice, chainID *big.Int, al bool, useLargeBlobs bool) (*types.Transaction, error) {
// Set fields if non-nil
if rpc != nil {
client := ethclient.NewClient(rpc)
var err error
if gasPrice == nil {
gasPrice, err = client.SuggestGasPrice(context.Background())
if err != nil {
gasPrice = big.NewInt(1)
}
}
if chainID == nil {
chainID, err = client.ChainID(context.Background())
if err != nil {
chainID = big.NewInt(1)
}
}
}
gas := uint64(100000)
to := randomAddress()
// Generate random EVM bytecode (similar to what tx-fuzz RandomCode did)
code := generateRandomEVMCode(mathRand.Intn(128)) // #nosec G404
value := big.NewInt(0)
mod := 2
if al {
mod = 1
}
// Helper to get blob data based on config
getBlobData := func() ([]byte, error) {
if useLargeBlobs {
return randomBlobDataLarge()
}
return randomBlobData()
}
// #nosec G404 -- Test code uses deterministic randomness
switch mathRand.Intn(mod) {
switch f.Byte() % byte(mod) {
case 0:
// 4844 transaction without AL
tip, feecap, err := getCaps(rpc, gasPrice)
if err != nil {
return nil, errors.Wrap(err, "getCaps")
}
data, err := getBlobData()
data, err := randomBlobData()
if err != nil {
return nil, errors.Wrap(err, "getBlobData")
return nil, errors.Wrap(err, "randomBlobData")
}
return New4844Tx(nonce, &to, gas, chainID, tip, feecap, value, code, big.NewInt(1000000), data, make(types.AccessList, 0)), nil
case 1:
@@ -443,18 +289,18 @@ func RandomBlobTx(rpc *rpc.Client, sender common.Address, nonce uint64, gasPrice
Data: code,
})
// Use legacy GasPrice for access list simulation to satisfy post-London requirement.
// TODO: replace call with al, err := txfuzz.CreateAccessList(rpc, tx, sender) when txfuzz is fixed in new release
// an error occurs mentioning error="CreateAccessList: both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified"
msg := ethereum.CallMsg{
From: sender,
To: tx.To(),
Gas: tx.Gas(),
GasPrice: gasPrice,
GasPrice: tx.GasPrice(),
Value: tx.Value(),
Data: tx.Data(),
AccessList: nil,
}
geth := gethclient.New(rpc)
al, _, _, err := geth.CreateAccessList(context.Background(), msg)
if err != nil {
return nil, errors.Wrap(err, "CreateAccessList")
@@ -463,52 +309,15 @@ func RandomBlobTx(rpc *rpc.Client, sender common.Address, nonce uint64, gasPrice
if err != nil {
return nil, errors.Wrap(err, "getCaps")
}
data, err := getBlobData()
data, err := randomBlobData()
if err != nil {
return nil, errors.Wrap(err, "getBlobData")
return nil, errors.Wrap(err, "randomBlobData")
}
return New4844Tx(nonce, &to, gas, chainID, tip, feecap, value, code, big.NewInt(1000000), data, *al), nil
}
return nil, errors.New("asdf")
}
func New4844CellTx(nonce uint64, to *common.Address, gasLimit uint64, chainID, tip, feeCap, value *big.Int, code []byte, blobFeeCap *big.Int, blobData []byte, al types.AccessList) (*types.Transaction, error) {
blobs, comms, _, versionedHashes, err := EncodeBlobs(blobData)
if err != nil {
return nil, errors.Wrap(err, "failed to encode blobs")
}
// Create a Version 0 sidecar first
sidecar := &types.BlobTxSidecar{
Version: types.BlobSidecarVersion0,
Blobs: blobs,
Commitments: comms,
Proofs: make([]kzg4844.Proof, len(blobs)), // Placeholder, will be replaced by ToV1
}
// Convert to Version 1 which will compute and attach cell proofs
if err := sidecar.ToV1(); err != nil {
return nil, errors.Wrap(err, "failed to convert sidecar to V1")
}
tx := types.NewTx(&types.BlobTx{
ChainID: uint256.MustFromBig(chainID),
Nonce: nonce,
GasTipCap: uint256.MustFromBig(tip),
GasFeeCap: uint256.MustFromBig(feeCap),
Gas: gasLimit,
To: *to,
Value: uint256.MustFromBig(value),
Data: code,
AccessList: al,
BlobFeeCap: uint256.MustFromBig(blobFeeCap),
BlobHashes: versionedHashes,
Sidecar: sidecar,
})
return tx, nil
}
func New4844Tx(nonce uint64, to *common.Address, gasLimit uint64, chainID, tip, feeCap, value *big.Int, code []byte, blobFeeCap *big.Int, blobData []byte, al types.AccessList) *types.Transaction {
blobs, comms, proofs, versionedHashes, err := EncodeBlobs(blobData)
if err != nil {
@@ -535,91 +344,15 @@ func New4844Tx(nonce uint64, to *common.Address, gasLimit uint64, chainID, tip,
return tx
}
// clampTxGas returns a copy of tx with Gas reduced to cap if it exceeds cap.
// This avoids EL errors like "transaction gas limit too high" on networks with
// per-transaction gas caps (commonly ~16,777,216).
func clampTxGas(tx *types.Transaction, gasCap uint64) *types.Transaction {
if tx == nil || tx.Gas() <= gasCap {
return tx
}
to := tx.To()
switch tx.Type() {
case types.LegacyTxType:
return types.NewTx(&types.LegacyTx{
Nonce: tx.Nonce(),
To: to,
Value: tx.Value(),
Gas: gasCap,
GasPrice: tx.GasPrice(),
Data: tx.Data(),
})
case types.AccessListTxType:
return types.NewTx(&types.AccessListTx{
ChainID: tx.ChainId(),
Nonce: tx.Nonce(),
To: to,
Value: tx.Value(),
Gas: gasCap,
GasPrice: tx.GasPrice(),
Data: tx.Data(),
AccessList: tx.AccessList(),
})
case types.DynamicFeeTxType:
return types.NewTx(&types.DynamicFeeTx{
ChainID: tx.ChainId(),
Nonce: tx.Nonce(),
To: to,
Value: tx.Value(),
Gas: gasCap,
Data: tx.Data(),
AccessList: tx.AccessList(),
GasTipCap: tx.GasTipCap(),
GasFeeCap: tx.GasFeeCap(),
})
case types.BlobTxType:
// Leave blob txs unchanged here; blob tx construction paths set gas explicitly.
return tx
default:
return tx
}
}
// ensureMinBalance tops up dest account from miner if its balance is below minWei.
func ensureMinBalance(ctx context.Context, rpcCli *rpc.Client, backend *ethclient.Client, minerKey, destKey *keystore.Key, minWei *big.Int) error {
bal, err := backend.BalanceAt(ctx, destKey.Address, nil)
if err != nil {
return err
}
if bal.Cmp(minWei) >= 0 {
return nil
}
if err := fundAccount(rpcCli, minerKey, destKey); err != nil {
return err
}
if err := WaitForBlocks(ctx, backend, minerKey, 1); err != nil {
return errors.Wrap(err, "failed to mine block for top-up tx")
}
return nil
}
func encodeBlobs(data []byte) []kzg4844.Blob {
blobs := []kzg4844.Blob{{}}
blobIndex := 0
fieldIndex := -1
numOfElems := fieldparams.BlobLength / 32
// Allow up to 6 blobs per transaction to properly test BPO limits.
// With 10 blob txs per slot × 6 blobs = 60 max blobs submitted,
// which exceeds the highest BPO limit (21) and ensures we can hit it.
const maxBlobsPerTx = 6
for i := 0; i < len(data); i += 31 {
fieldIndex++
if fieldIndex == numOfElems {
if blobIndex >= maxBlobsPerTx-1 {
if blobIndex >= 1 {
break
}
blobs = append(blobs, kzg4844.Blob{})
@@ -672,7 +405,6 @@ func kZGToVersionedHash(kzg kzg4844.Commitment) common.Hash {
}
func randomBlobData() ([]byte, error) {
// Generate random data for up to 1 blob. This is used for pre-Fulu tests.
size := mathRand.Intn(fieldparams.BlobSize) // #nosec G404
data := make([]byte, size)
n, err := mathRand.Read(data) // #nosec G404
@@ -685,29 +417,6 @@ func randomBlobData() ([]byte, error) {
return data, nil
}
// randomBlobDataLarge generates 6 blobs worth of data for BPO testing.
// This is used post-Fulu to ensure we can test increased blob limits.
// With 5 blob txs per slot × 6 blobs = 30 max blobs submitted,
// which exceeds the highest BPO limit (21) and ensures we can hit it.
// The data is mostly zeros with only the first 1KB randomized for uniqueness,
// which is sufficient for testing without the overhead of generating ~786KB of random data.
func randomBlobDataLarge() ([]byte, error) {
const numBlobs = 6
size := (numBlobs-1)*fieldparams.BlobSize + 1
data := make([]byte, size) // Zero-initialized by Go
// Only randomize first 1KB for uniqueness - no need for full randomness in tests
const randomSize = 1024
n, err := mathRand.Read(data[:randomSize]) // #nosec G404
if err != nil {
return nil, err
}
if n != randomSize {
return nil, fmt.Errorf("could not create random blob data: %w", err)
}
return data, nil
}
func randomAddress() common.Address {
rNum := mathRand.Int31n(5) // #nosec G404
switch rNum {
@@ -759,8 +468,7 @@ func fundAccount(client *rpc.Client, sourceKey, destKey *keystore.Key) error {
if err != nil {
return err
}
// Increased funding to 100 million ETH to handle extended test runs with blob transactions
val, ok := big.NewInt(0).SetString("100000000000000000000000000", 10)
val, ok := big.NewInt(0).SetString("10000000000000000000000000", 10)
if !ok {
return errors.New("could not set big int for value")
}
@@ -771,132 +479,3 @@ func fundAccount(client *rpc.Client, sourceKey, destKey *keystore.Key) error {
}
return backend.SendTransaction(context.Background(), signedTx)
}
// generateRandomEVMCode generates random but valid-looking EVM bytecode
// This mimics what tx-fuzz's RandomCode did (which used FuzzyVM's generator)
func generateRandomEVMCode(maxLen int) []byte {
if maxLen == 0 {
return []byte{}
}
// Common EVM opcodes that are safe for testing
// Including: PUSH, DUP, SWAP, arithmetic, logic, and STOP
safeOpcodes := []byte{
0x00, // STOP
0x01, // ADD
0x02, // MUL
0x03, // SUB
0x04, // DIV
0x10, // LT
0x11, // GT
0x14, // EQ
0x16, // AND
0x17, // OR
0x18, // XOR
0x50, // POP
0x52, // MSTORE
0x54, // SLOAD
0x55, // SSTORE
0x56, // JUMP
0x57, // JUMPI
0x58, // PC
0x59, // MSIZE
0x5A, // GAS
0x60, // PUSH1
0x80, // DUP1
0x90, // SWAP1
}
code := make([]byte, 0, maxLen)
for i := 0; i < maxLen; i++ {
opcode := safeOpcodes[mathRand.Intn(len(safeOpcodes))] // #nosec G404
code = append(code, opcode)
// If PUSH1, add a random byte
if opcode == 0x60 && i+1 < maxLen {
code = append(code, byte(mathRand.Intn(256))) // #nosec G404
i++
}
}
return code
}
// randomValidTx generates a random valid transaction
// This replaces tx-fuzz's RandomValidTx functionality
func randomValidTx(sender common.Address, nonce uint64, gasPrice, chainID *big.Int, forceAccessList bool) (*types.Transaction, error) {
gas := uint64(21000 + mathRand.Intn(100000)) // #nosec G404
to := randomAddress()
code := generateRandomEVMCode(mathRand.Intn(256)) // #nosec G404
value := big.NewInt(0)
// Randomly choose transaction type
// 0: Legacy, 1: AccessList, 2: DynamicFee
txType := mathRand.Intn(3) // #nosec G404
if forceAccessList {
txType = 1 // Force AccessList type
}
switch txType {
case 0:
// Legacy transaction
return types.NewTx(&types.LegacyTx{
Nonce: nonce,
To: &to,
Value: value,
Gas: gas,
GasPrice: gasPrice,
Data: code,
}), nil
case 1:
// AccessList transaction
accessList := make(types.AccessList, 0)
// Optionally add some random access list entries
// #nosec G404 -- Test code uses deterministic randomness
if mathRand.Intn(2) == 0 {
// #nosec G404 -- Test code uses deterministic randomness
numEntries := mathRand.Intn(3) + 1
for range numEntries {
addr := randomAddress()
storageKeys := make([]common.Hash, mathRand.Intn(3)) // #nosec G404
for j := range storageKeys {
b := make([]byte, 32)
_, _ = mathRand.Read(b) // #nosec G404
storageKeys[j] = common.BytesToHash(b)
}
accessList = append(accessList, types.AccessTuple{
Address: addr,
StorageKeys: storageKeys,
})
}
}
return types.NewTx(&types.AccessListTx{
ChainID: chainID,
Nonce: nonce,
To: &to,
Value: value,
Gas: gas,
GasPrice: gasPrice,
Data: code,
AccessList: accessList,
}), nil
case 2:
// DynamicFee transaction (EIP-1559)
tip := new(big.Int).Div(gasPrice, big.NewInt(10)) // 10% tip
feeCap := new(big.Int).Add(gasPrice, tip)
accessList := make(types.AccessList, 0)
return types.NewTx(&types.DynamicFeeTx{
ChainID: chainID,
Nonce: nonce,
To: &to,
Value: value,
Gas: gas,
GasTipCap: tip,
GasFeeCap: feeCap,
Data: code,
AccessList: accessList,
}), nil
}
return nil, errors.New("invalid transaction type")
}

View File

@@ -21,7 +21,7 @@ func e2eMinimal(t *testing.T, cfg *params.BeaconChainConfig, cfgo ...types.E2ECo
require.NoError(t, e2eParams.Init(t, e2eParams.StandardBeaconCount))
var err error
epochsToRun := 18
epochsToRun := 16
epochStr, longRunning := os.LookupEnv("E2E_EPOCHS")
if longRunning {
epochsToRun, err = strconv.Atoi(epochStr)
@@ -35,10 +35,6 @@ func e2eMinimal(t *testing.T, cfg *params.BeaconChainConfig, cfgo ...types.E2ECo
}
tracingPort := e2eParams.TestParams.Ports.JaegerTracingPort
tracingEndpoint := fmt.Sprintf("127.0.0.1:%d", tracingPort)
// Default exit epoch used for voluntary exit tests.
// Can be overridden via WithExitEpoch option for shorter test runs.
exitEpoch := primitives.Epoch(7)
evals := []types.Evaluator{
ev.PeersConnect,
ev.HealthzCheck,
@@ -48,7 +44,10 @@ func e2eMinimal(t *testing.T, cfg *params.BeaconChainConfig, cfgo ...types.E2ECo
ev.FinalizationOccurs(3),
ev.VerifyBlockGraffiti,
ev.PeersCheck,
// Exit-related evaluators are added after processing options to allow custom exit epoch.
ev.ProposeVoluntaryExit,
ev.ValidatorsHaveExited,
ev.SubmitWithdrawal,
ev.ValidatorsHaveWithdrawn,
ev.ProcessesDepositsInBlocks,
ev.ActivatesDepositedValidators,
ev.DepositedValidatorsAreActive,
@@ -65,11 +64,6 @@ func e2eMinimal(t *testing.T, cfg *params.BeaconChainConfig, cfgo ...types.E2ECo
evals = addIfForkSet(evals, cfg.CapellaForkEpoch, ev.CapellaForkTransition)
evals = addIfForkSet(evals, cfg.DenebForkEpoch, ev.DenebForkTransition)
evals = addIfForkSet(evals, cfg.ElectraForkEpoch, ev.ElectraForkTransition)
evals = addIfForkSet(evals, cfg.FuluForkEpoch, ev.FuluForkTransition)
// Blob evaluators - run from Deneb onwards
evals = addIfForkSet(evals, cfg.DenebForkEpoch, ev.BlobsIncludedInBlocks)
// BPO (Blob Parameter Optimization) evaluator - runs from Fulu onwards
evals = addIfForkSet(evals, cfg.FuluForkEpoch, ev.BlobLimitsRespected)
testConfig := &types.E2EConfig{
BeaconFlags: []string{
@@ -93,18 +87,6 @@ func e2eMinimal(t *testing.T, cfg *params.BeaconChainConfig, cfgo ...types.E2ECo
for _, o := range cfgo {
o(testConfig)
}
// Add exit-related evaluators using custom exit epoch if configured, otherwise use default.
if testConfig.ExitEpoch > 0 {
exitEpoch = testConfig.ExitEpoch
}
testConfig.Evaluators = append(testConfig.Evaluators,
ev.ProposeVoluntaryExitAtEpoch(exitEpoch),
ev.ValidatorsHaveExitedAtEpoch(exitEpoch+1),
ev.SubmitWithdrawalAtEpoch(exitEpoch+1),
ev.ValidatorsHaveWithdrawnAfterExitAtEpoch(exitEpoch),
)
if testConfig.UseBuilder {
testConfig.Evaluators = append(testConfig.Evaluators, ev.BuilderIsActive)
}
@@ -158,11 +140,6 @@ func e2eMainnet(t *testing.T, usePrysmSh, useMultiClient bool, cfg *params.Beaco
evals = addIfForkSet(evals, cfg.CapellaForkEpoch, ev.CapellaForkTransition)
evals = addIfForkSet(evals, cfg.DenebForkEpoch, ev.DenebForkTransition)
evals = addIfForkSet(evals, cfg.ElectraForkEpoch, ev.ElectraForkTransition)
evals = addIfForkSet(evals, cfg.FuluForkEpoch, ev.FuluForkTransition)
// Blob evaluators - run from Deneb onwards
evals = addIfForkSet(evals, cfg.DenebForkEpoch, ev.BlobsIncludedInBlocks)
// BPO (Blob Parameter Optimization) evaluator - runs from Fulu onwards
evals = addIfForkSet(evals, cfg.FuluForkEpoch, ev.BlobLimitsRespected)
testConfig := &types.E2EConfig{
BeaconFlags: []string{
@@ -231,11 +208,6 @@ func scenarioEvals(cfg *params.BeaconChainConfig) []types.Evaluator {
evals = addIfForkSet(evals, cfg.CapellaForkEpoch, ev.CapellaForkTransition)
evals = addIfForkSet(evals, cfg.DenebForkEpoch, ev.DenebForkTransition)
evals = addIfForkSet(evals, cfg.ElectraForkEpoch, ev.ElectraForkTransition)
evals = addIfForkSet(evals, cfg.FuluForkEpoch, ev.FuluForkTransition)
// Blob evaluators - run from Deneb onwards
evals = addIfForkSet(evals, cfg.DenebForkEpoch, ev.BlobsIncludedInBlocks)
// BPO (Blob Parameter Optimization) evaluator - runs from Fulu onwards
evals = addIfForkSet(evals, cfg.FuluForkEpoch, ev.BlobLimitsRespected)
return evals
}
@@ -257,10 +229,5 @@ func scenarioEvalsMulti(cfg *params.BeaconChainConfig) []types.Evaluator {
evals = addIfForkSet(evals, cfg.CapellaForkEpoch, ev.CapellaForkTransition)
evals = addIfForkSet(evals, cfg.DenebForkEpoch, ev.DenebForkTransition)
evals = addIfForkSet(evals, cfg.ElectraForkEpoch, ev.ElectraForkTransition)
evals = addIfForkSet(evals, cfg.FuluForkEpoch, ev.FuluForkTransition)
// Blob evaluators - run from Deneb onwards
evals = addIfForkSet(evals, cfg.DenebForkEpoch, ev.BlobsIncludedInBlocks)
// BPO (Blob Parameter Optimization) evaluator - runs from Fulu onwards
evals = addIfForkSet(evals, cfg.FuluForkEpoch, ev.BlobLimitsRespected)
return evals
}

View File

@@ -225,9 +225,9 @@ func (r *testRunner) testDepositsAndTx(ctx context.Context, g *errgroup.Group,
if err := helpers.ComponentsStarted(ctx, []e2etypes.ComponentRunner{r.depositor}); err != nil {
return errors.Wrap(err, "testDepositsAndTx unable to run, depositor did not Start")
}
go func() {
if r.config.TestDeposits {
log.Info("Running deposit tests")
go func() {
if r.config.TestDeposits {
log.Info("Running deposit tests")
// The validators with an index < minGenesisActiveCount all have deposits already from the chain start.
// Skip all of those chain start validators by seeking to minGenesisActiveCount in the validator list
// for further deposit testing.
@@ -238,12 +238,9 @@ func (r *testRunner) testDepositsAndTx(ctx context.Context, g *errgroup.Group,
r.t.Error(errors.Wrap(err, "depositor.SendAndMine failed"))
}
}
}
// Only generate background transactions when relevant for the test.
if r.config.TestDeposits || r.config.TestFeature || r.config.UseBuilder {
r.testTxGeneration(ctx, g, keystorePath, []e2etypes.ComponentRunner{})
}
}()
}
r.testTxGeneration(ctx, g, keystorePath, []e2etypes.ComponentRunner{})
}()
if r.config.TestDeposits {
return depositCheckValidator.Start(ctx)
}
@@ -252,7 +249,7 @@ func (r *testRunner) testDepositsAndTx(ctx context.Context, g *errgroup.Group,
}
func (r *testRunner) testTxGeneration(ctx context.Context, g *errgroup.Group, keystorePath string, requiredNodes []e2etypes.ComponentRunner) {
txGenerator := eth1.NewTransactionGenerator(keystorePath, r.config.Seed, r.config.UseLargeBlobs)
txGenerator := eth1.NewTransactionGenerator(keystorePath, r.config.Seed)
r.comHandler.txGen = txGenerator
g.Go(func() error {
if err := helpers.ComponentsStarted(ctx, requiredNodes); err != nil {

View File

@@ -4,7 +4,6 @@ go_library(
name = "go_default_library",
testonly = True,
srcs = [
"blob_limits.go",
"builder.go",
"data.go",
"execution_engine.go",

View File

@@ -303,7 +303,7 @@ var (
}())),
"/validator/duties/sync/{param1}": newMetadata[structs.GetSyncCommitteeDutiesResponse](
v1PathTemplate,
withStart(params.E2ETestConfig().AltairForkEpoch),
withStart(params.AltairE2EForkEpoch),
withParams(func(currentEpoch primitives.Epoch) []string {
return []string{fmt.Sprintf("%v", currentEpoch)}
}),

View File

@@ -1,246 +0,0 @@
package evaluators
import (
"context"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v7/runtime/version"
"github.com/OffchainLabs/prysm/v7/testing/endtoend/policies"
e2etypes "github.com/OffchainLabs/prysm/v7/testing/endtoend/types"
"github.com/OffchainLabs/prysm/v7/time/slots"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"google.golang.org/grpc"
"google.golang.org/protobuf/types/known/emptypb"
)
// Minimum blob utilization percentage required to pass the evaluator.
// We expect the transaction generator to produce enough blobs to hit at least this threshold.
const minBlobUtilizationPercent = 50
// BlobsIncludedInBlocks verifies that blocks contain blobs and that the blob count
// does not exceed the maximum allowed for the epoch (respecting BPO schedule).
var BlobsIncludedInBlocks = e2etypes.Evaluator{
Name: "blobs_included_in_blocks_epoch_%d",
Policy: func(currentEpoch primitives.Epoch) bool {
// Only run from Deneb onwards
return policies.OnwardsNthEpoch(params.BeaconConfig().DenebForkEpoch)(currentEpoch)
},
Evaluation: blobsIncludedInBlocks,
}
// BlobLimitsRespected verifies that the BPO (Blob Parameter Optimization) limits
// are correctly enforced after Fulu fork, checking that:
// 1. Blocks don't exceed MaxBlobsPerBlock for their respective epoch
// 2. We're utilizing the increased capacity (at least 50% utilization)
// 3. When BPO activates (limit increases), blocks actually use the new higher limit
var BlobLimitsRespected = e2etypes.Evaluator{
Name: "blob_limits_respected_epoch_%d",
Policy: func(currentEpoch primitives.Epoch) bool {
// Only run from Fulu onwards where BPO is active
return policies.OnwardsNthEpoch(params.BeaconConfig().FuluForkEpoch)(currentEpoch)
},
Evaluation: blobLimitsRespected,
}
func blobsIncludedInBlocks(_ *e2etypes.EvaluationContext, conns ...*grpc.ClientConn) error {
conn := conns[0]
client := ethpb.NewBeaconChainClient(conn)
chainHead, err := client.GetChainHead(context.Background(), &emptypb.Empty{})
if err != nil {
return errors.Wrap(err, "failed to get chain head")
}
// Check blocks from the previous epoch
epoch := chainHead.HeadEpoch
if epoch > 0 {
epoch = epoch - 1
}
// Skip if we're before Deneb
if epoch < params.BeaconConfig().DenebForkEpoch {
return nil
}
req := &ethpb.ListBlocksRequest{QueryFilter: &ethpb.ListBlocksRequest_Epoch{Epoch: epoch}}
blks, err := client.ListBeaconBlocks(context.Background(), req)
if err != nil {
return errors.Wrap(err, "failed to get blocks from beacon-chain")
}
blocksWithBlobs := 0
for _, ctr := range blks.BlockContainers {
blk, err := blocks.BeaconBlockContainerToSignedBeaconBlock(ctr)
if err != nil {
return errors.Wrap(err, "failed to convert block container to signed beacon block")
}
if blk == nil || blk.IsNil() {
continue
}
// Skip blocks before Deneb
if blk.Version() < version.Deneb {
continue
}
commitments, err := blk.Block().Body().BlobKzgCommitments()
if err != nil {
return errors.Wrap(err, "failed to get blob kzg commitments")
}
if len(commitments) > 0 {
blocksWithBlobs++
}
}
// We expect at least some blocks to have blobs since we're sending blob transactions
if blocksWithBlobs == 0 {
return errors.Errorf("no blocks with blobs found in epoch %d", epoch)
}
return nil
}
func blobLimitsRespected(_ *e2etypes.EvaluationContext, conns ...*grpc.ClientConn) error {
conn := conns[0]
nodeClient := ethpb.NewNodeClient(conn)
beaconClient := ethpb.NewBeaconChainClient(conn)
genesis, err := nodeClient.GetGenesis(context.Background(), &emptypb.Empty{})
if err != nil {
return errors.Wrap(err, "failed to get genesis")
}
currSlot := slots.CurrentSlot(genesis.GenesisTime.AsTime())
currEpoch := slots.ToEpoch(currSlot)
// Check the previous epoch to ensure blocks are finalized
epochToCheck := currEpoch
if epochToCheck > 0 {
epochToCheck = epochToCheck - 1
}
// Skip if we're before Fulu
if epochToCheck < params.BeaconConfig().FuluForkEpoch {
return nil
}
req := &ethpb.ListBlocksRequest{QueryFilter: &ethpb.ListBlocksRequest_Epoch{Epoch: epochToCheck}}
blks, err := beaconClient.ListBeaconBlocks(context.Background(), req)
if err != nil {
return errors.Wrap(err, "failed to get blocks from beacon-chain")
}
cfg := params.BeaconConfig()
maxBlobsForEpoch := cfg.MaxBlobsPerBlockAtEpoch(epochToCheck)
// Get the previous epoch's limit to detect BPO transitions
var prevEpochMaxBlobs int
if epochToCheck > 0 {
prevEpochMaxBlobs = cfg.MaxBlobsPerBlockAtEpoch(epochToCheck - 1)
}
// Check if this is a BPO transition epoch (limit increased from previous epoch)
isBPOTransitionEpoch := maxBlobsForEpoch > prevEpochMaxBlobs
var totalBlobs int
var maxBlobsInBlock int
var blockCount int
for _, ctr := range blks.BlockContainers {
blk, err := blocks.BeaconBlockContainerToSignedBeaconBlock(ctr)
if err != nil {
return errors.Wrap(err, "failed to convert block container to signed beacon block")
}
if blk == nil || blk.IsNil() {
continue
}
// Skip blocks before Deneb (shouldn't happen if we're checking post-Fulu epochs)
if blk.Version() < version.Deneb {
continue
}
slot := blk.Block().Slot()
blockEpoch := slots.ToEpoch(slot)
commitments, err := blk.Block().Body().BlobKzgCommitments()
if err != nil {
return errors.Wrap(err, "failed to get blob kzg commitments")
}
blobCount := len(commitments)
// Verify we don't exceed the limit
if blobCount > maxBlobsForEpoch {
return errors.Errorf(
"block at slot %d (epoch %d) has %d blobs, exceeding max allowed %d for this epoch",
slot, blockEpoch, blobCount, maxBlobsForEpoch,
)
}
totalBlobs += blobCount
blockCount++
if blobCount > maxBlobsInBlock {
maxBlobsInBlock = blobCount
}
}
// Calculate utilization
if blockCount == 0 {
return errors.Errorf("no blocks found in epoch %d", epochToCheck)
}
utilizationPercent := (maxBlobsInBlock * 100) / maxBlobsForEpoch
logrus.WithFields(logrus.Fields{
"epoch": epochToCheck,
"maxBlobsForEpoch": maxBlobsForEpoch,
"prevEpochMaxBlobs": prevEpochMaxBlobs,
"maxBlobsInBlock": maxBlobsInBlock,
"totalBlobs": totalBlobs,
"blockCount": blockCount,
"utilizationPercent": utilizationPercent,
"isBPOTransitionEpoch": isBPOTransitionEpoch,
}).Info("Blob utilization stats for epoch")
// For BPO transition epochs, verify that BPO actually activated by checking
// that at least one block exceeded the previous epoch's limit
if isBPOTransitionEpoch {
if maxBlobsInBlock <= prevEpochMaxBlobs {
return errors.Errorf(
"BPO transition at epoch %d: limit increased from %d to %d, but no block exceeded the old limit. "+
"Max blobs in any block was %d. This indicates BPO may not be working correctly or "+
"the transaction generator is not producing enough blobs to test the increased limit.",
epochToCheck, prevEpochMaxBlobs, maxBlobsForEpoch, maxBlobsInBlock,
)
}
logrus.WithFields(logrus.Fields{
"epoch": epochToCheck,
"prevLimit": prevEpochMaxBlobs,
"newLimit": maxBlobsForEpoch,
"maxBlobsInBlock": maxBlobsInBlock,
}).Info("BPO activation verified: blocks are using capacity beyond previous limit")
}
// For all BPO epochs (where limit > Electra's 9), verify we're utilizing the capacity
electraMax := cfg.DeprecatedMaxBlobsPerBlockElectra
if maxBlobsForEpoch > electraMax {
if utilizationPercent < minBlobUtilizationPercent {
return errors.Errorf(
"BPO epoch %d has max blobs %d but only achieved %d%% utilization (max blobs in any block: %d). "+
"Expected at least %d%% utilization to verify BPO is working. "+
"This may indicate the transaction generator is not producing enough blobs.",
epochToCheck, maxBlobsForEpoch, utilizationPercent, maxBlobsInBlock, minBlobUtilizationPercent,
)
}
}
return nil
}

View File

@@ -11,6 +11,7 @@ import (
"github.com/OffchainLabs/prysm/v7/testing/endtoend/policies"
e2etypes "github.com/OffchainLabs/prysm/v7/testing/endtoend/types"
"github.com/OffchainLabs/prysm/v7/time/slots"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/pkg/errors"
"google.golang.org/grpc"
"google.golang.org/protobuf/types/known/emptypb"
@@ -26,11 +27,6 @@ var BuilderIsActive = e2etypes.Evaluator{
Evaluation: builderActive,
}
// maxNonBuilderBlocks is the maximum number of blocks that can be built locally
// instead of by the builder before the test fails. This allows tolerance for
// occasional builder timeouts or failures.
const maxNonBuilderBlocks = 2
func builderActive(_ *e2etypes.EvaluationContext, conns ...*grpc.ClientConn) error {
conn := conns[0]
client := ethpb.NewNodeClient(conn)
@@ -53,10 +49,6 @@ func builderActive(_ *e2etypes.EvaluationContext, conns ...*grpc.ClientConn) err
if err != nil {
return err
}
nonBuilderBlocks := 0
builderBlocks := 0
blockCtrs, err := beaconClient.ListBeaconBlocks(context.Background(), &ethpb.ListBlocksRequest{QueryFilter: &ethpb.ListBlocksRequest_Epoch{Epoch: lowestBound}})
if err != nil {
return errors.Wrap(err, "failed to get beacon blocks")
@@ -92,18 +84,13 @@ func builderActive(_ *e2etypes.EvaluationContext, conns ...*grpc.ClientConn) err
continue
}
if string(execPayload.ExtraData()) != "prysm-builder" {
nonBuilderBlocks++
continue
return errors.Errorf("%s block with slot %d was not built by the builder. It has an extra data of %s and txRoot of %s", version.String(b.Version()), b.Block().Slot(), string(execPayload.ExtraData()), hexutil.Encode(txRoot))
}
builderBlocks++
if execPayload.GasLimit() == 0 {
return errors.Errorf("%s block with slot %d has a gas limit of 0, when it should be in the 30M range", version.String(b.Version()), b.Block().Slot())
}
}
if lowestBound == currEpoch {
if nonBuilderBlocks > maxNonBuilderBlocks {
return errors.Errorf("too many non-builder blocks: %d (max allowed: %d), builder blocks: %d", nonBuilderBlocks, maxNonBuilderBlocks, builderBlocks)
}
return nil
}
blockCtrs, err = beaconClient.ListBeaconBlocks(context.Background(), &ethpb.ListBlocksRequest{QueryFilter: &ethpb.ListBlocksRequest_Epoch{Epoch: currEpoch}})
@@ -140,16 +127,11 @@ func builderActive(_ *e2etypes.EvaluationContext, conns ...*grpc.ClientConn) err
continue
}
if string(execPayload.ExtraData()) != "prysm-builder" {
nonBuilderBlocks++
continue
return errors.Errorf("%s block with slot %d was not built by the builder. It has an extra data of %s and txRoot of %s", version.String(b.Version()), b.Block().Slot(), string(execPayload.ExtraData()), hexutil.Encode(txRoot))
}
builderBlocks++
if execPayload.GasLimit() == 0 {
return errors.Errorf("%s block with slot %d has a gas limit of 0, when it should be in the 30M range", version.String(b.Version()), b.Block().Slot())
}
}
if nonBuilderBlocks > maxNonBuilderBlocks {
return errors.Errorf("too many non-builder blocks: %d (max allowed: %d), builder blocks: %d", nonBuilderBlocks, maxNonBuilderBlocks, builderBlocks)
}
return nil
}

View File

@@ -88,28 +88,11 @@ var ElectraForkTransition = e2etypes.Evaluator{
Evaluation: electraForkOccurs,
}
// FuluForkTransition ensures that the fulu hard fork has occurred successfully
var FuluForkTransition = e2etypes.Evaluator{
Name: "fulu_fork_transition_%d",
Policy: func(e primitives.Epoch) bool {
// Only run if we started before Fulu
if e2etypes.GenesisFork() >= version.Fulu {
return false
}
fEpoch := params.BeaconConfig().FuluForkEpoch
return policies.OnEpoch(fEpoch)(e)
},
Evaluation: fuluForkOccurs,
}
func altairForkOccurs(_ *e2etypes.EvaluationContext, conns ...*grpc.ClientConn) error {
conn := conns[0]
client := ethpb.NewBeaconNodeValidatorClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), streamDeadline)
defer cancel()
stream, err := client.StreamBlocksAltair(ctx, &ethpb.StreamBlocksRequest{VerifiedOnly: true})
if err != nil {
return errors.Wrap(err, "failed to get stream")
@@ -118,7 +101,6 @@ func altairForkOccurs(_ *e2etypes.EvaluationContext, conns ...*grpc.ClientConn)
if err != nil {
return err
}
if errors.Is(ctx.Err(), context.Canceled) {
return errors.New("context canceled prematurely")
}
@@ -139,24 +121,20 @@ func altairForkOccurs(_ *e2etypes.EvaluationContext, conns ...*grpc.ClientConn)
if err != nil {
return err
}
if err := blocks.BeaconBlockIsNil(blk); err != nil {
return err
}
if blk.Block().Slot() < fSlot {
return errors.Errorf("wanted a block >= %d but received %d", fSlot, blk.Block().Slot())
}
return nil
}
func bellatrixForkOccurs(_ *e2etypes.EvaluationContext, conns ...*grpc.ClientConn) error {
conn := conns[0]
client := ethpb.NewBeaconNodeValidatorClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), streamDeadline)
defer cancel()
stream, err := client.StreamBlocksAltair(ctx, &ethpb.StreamBlocksRequest{VerifiedOnly: true})
if err != nil {
return errors.Wrap(err, "failed to get stream")
@@ -165,7 +143,6 @@ func bellatrixForkOccurs(_ *e2etypes.EvaluationContext, conns ...*grpc.ClientCon
if err != nil {
return err
}
if errors.Is(ctx.Err(), context.Canceled) {
return errors.New("context canceled prematurely")
}
@@ -189,7 +166,6 @@ func bellatrixForkOccurs(_ *e2etypes.EvaluationContext, conns ...*grpc.ClientCon
if err != nil {
return err
}
if err := blocks.BeaconBlockIsNil(blk); err != nil {
return err
}
@@ -212,7 +188,6 @@ func capellaForkOccurs(_ *e2etypes.EvaluationContext, conns ...*grpc.ClientConn)
if err != nil {
return err
}
if errors.Is(ctx.Err(), context.Canceled) {
return errors.New("context canceled prematurely")
}
@@ -234,7 +209,6 @@ func capellaForkOccurs(_ *e2etypes.EvaluationContext, conns ...*grpc.ClientConn)
if err != nil {
return err
}
if err := blocks.BeaconBlockIsNil(blk); err != nil {
return err
}
@@ -257,7 +231,6 @@ func denebForkOccurs(_ *e2etypes.EvaluationContext, conns ...*grpc.ClientConn) e
if err != nil {
return err
}
if errors.Is(ctx.Err(), context.Canceled) {
return errors.New("context canceled prematurely")
}
@@ -279,7 +252,6 @@ func denebForkOccurs(_ *e2etypes.EvaluationContext, conns ...*grpc.ClientConn) e
if err != nil {
return err
}
if err := blocks.BeaconBlockIsNil(blk); err != nil {
return err
}
@@ -302,7 +274,6 @@ func electraForkOccurs(_ *e2etypes.EvaluationContext, conns ...*grpc.ClientConn)
if err != nil {
return err
}
if errors.Is(ctx.Err(), context.Canceled) {
return errors.New("context canceled prematurely")
}
@@ -324,7 +295,6 @@ func electraForkOccurs(_ *e2etypes.EvaluationContext, conns ...*grpc.ClientConn)
if err != nil {
return err
}
if err := blocks.BeaconBlockIsNil(blk); err != nil {
return err
}
@@ -333,57 +303,3 @@ func electraForkOccurs(_ *e2etypes.EvaluationContext, conns ...*grpc.ClientConn)
}
return nil
}
func fuluForkOccurs(_ *e2etypes.EvaluationContext, conns ...*grpc.ClientConn) error {
conn := conns[0]
client := ethpb.NewBeaconNodeValidatorClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), streamDeadline)
defer cancel()
stream, err := client.StreamBlocksAltair(ctx, &ethpb.StreamBlocksRequest{VerifiedOnly: true})
if err != nil {
return errors.Wrap(err, "failed to get stream")
}
fSlot, err := slots.EpochStart(params.BeaconConfig().FuluForkEpoch)
if err != nil {
return err
}
if errors.Is(ctx.Err(), context.Canceled) {
return errors.New("context canceled prematurely")
}
res, err := stream.Recv()
if err != nil {
return err
}
if res == nil || res.Block == nil {
return errors.New("nil block returned by beacon node")
}
if res.GetBlock() == nil {
return errors.New("nil block returned by beacon node")
}
if res.GetFuluBlock() == nil {
return errors.Errorf("non-fulu block returned after the fork with type %T", res.Block)
}
blk, err := blocks.NewSignedBeaconBlock(res.GetFuluBlock())
if err != nil {
return err
}
if err := blocks.BeaconBlockIsNil(blk); err != nil {
return err
}
if blk.Block().Slot() < fSlot {
return errors.Errorf("wanted a block at slot >= %d but received %d", fSlot, blk.Block().Slot())
}
return nil
}

View File

@@ -117,10 +117,7 @@ func metricsTest(_ *types.EvaluationContext, conns ...*grpc.ClientConn) error {
return err
}
timeSlot := slots.CurrentSlot(genesisResp.GenesisTime.AsTime())
// Allow 1 slot tolerance due to race between calculating current slot
// and fetching chain head - a slot boundary may occur between these calls.
// Check: chainHead.HeadSlot <= timeSlot <= chainHead.HeadSlot + 1
if uint64(chainHead.HeadSlot) > uint64(timeSlot) || uint64(timeSlot) > uint64(chainHead.HeadSlot)+1 {
if uint64(chainHead.HeadSlot) != uint64(timeSlot) {
return fmt.Errorf("expected metrics slot to equal chain head slot, expected %d, received %d", timeSlot, chainHead.HeadSlot)
}

View File

@@ -40,9 +40,7 @@ var depositsInBlockStart = params.E2ETestConfig().EpochsPerEth1VotingPeriod * 2
// deposits included + finalization + MaxSeedLookahead for activation.
var depositActivationStartEpoch = depositsInBlockStart + 2 + params.E2ETestConfig().MaxSeedLookahead
var depositEndEpoch = depositActivationStartEpoch + primitives.Epoch(math.Ceil(float64(depositValCount)/float64(params.E2ETestConfig().MinPerEpochChurnLimit)))
// Default exit submission epoch for standard tests.
var defaultExitSubmissionEpoch = primitives.Epoch(7)
var exitSubmissionEpoch = primitives.Epoch(7)
// ProcessesDepositsInBlocks ensures the expected amount of deposits are accepted into blocks.
// Note: This evaluator only works for pre-Electra genesis since Electra uses EIP-6110 deposit requests.
@@ -94,90 +92,55 @@ var DepositedValidatorsAreActive = e2etypes.Evaluator{
}
// ProposeVoluntaryExit sends a voluntary exit from randomly selected validator in the genesis set.
// Uses the default exit submission epoch (7).
var ProposeVoluntaryExit = ProposeVoluntaryExitAtEpoch(defaultExitSubmissionEpoch)
// ProposeVoluntaryExitAtEpoch sends a voluntary exit at the specified epoch.
var ProposeVoluntaryExitAtEpoch = func(epoch primitives.Epoch) e2etypes.Evaluator {
return e2etypes.Evaluator{
Name: "propose_voluntary_exit_epoch_%d",
Policy: policies.OnEpoch(epoch),
Evaluation: proposeVoluntaryExit,
}
var ProposeVoluntaryExit = e2etypes.Evaluator{
Name: "propose_voluntary_exit_epoch_%d",
Policy: policies.OnEpoch(exitSubmissionEpoch),
Evaluation: proposeVoluntaryExit,
}
// ValidatorsHaveExited checks the beacon state for the exited validator and ensures its marked as exited.
// Uses the default exit submission epoch + 1 (epoch 8).
var ValidatorsHaveExited = ValidatorsHaveExitedAtEpoch(defaultExitSubmissionEpoch + 1)
// ValidatorsHaveExitedAtEpoch checks validators have exited at the specified epoch.
var ValidatorsHaveExitedAtEpoch = func(epoch primitives.Epoch) e2etypes.Evaluator {
return e2etypes.Evaluator{
Name: "voluntary_has_exited_%d",
Policy: policies.OnEpoch(epoch),
Evaluation: validatorsHaveExited,
}
var ValidatorsHaveExited = e2etypes.Evaluator{
Name: "voluntary_has_exited_%d",
Policy: policies.OnEpoch(8),
Evaluation: validatorsHaveExited,
}
// SubmitWithdrawal sends a withdrawal from a previously exited validator.
// Uses default timing based on exit submission epoch.
var SubmitWithdrawal = SubmitWithdrawalAtEpoch(defaultExitSubmissionEpoch + 1)
// SubmitWithdrawalAtEpoch sends a withdrawal at the specified epoch.
// For pre-Deneb genesis, it runs around the Capella fork epoch instead.
var SubmitWithdrawalAtEpoch = func(epoch primitives.Epoch) e2etypes.Evaluator {
return e2etypes.Evaluator{
Name: "submit_withdrawal_epoch_%d",
Policy: func(currentEpoch primitives.Epoch) bool {
fEpoch := params.BeaconConfig().CapellaForkEpoch
// If Capella is disabled (starting at Deneb+), run at the specified epoch
if e2etypes.GenesisFork() >= version.Deneb {
return policies.OnEpoch(epoch)(currentEpoch)
}
return policies.BetweenEpochs(fEpoch-2, fEpoch+1)(currentEpoch)
},
Evaluation: submitWithdrawal,
}
var SubmitWithdrawal = e2etypes.Evaluator{
Name: "submit_withdrawal_epoch_%d",
Policy: func(currentEpoch primitives.Epoch) bool {
fEpoch := params.BeaconConfig().CapellaForkEpoch
// If Capella is disabled (starting at Deneb+), run after exit submission
if e2etypes.GenesisFork() >= version.Deneb {
return policies.OnEpoch(exitSubmissionEpoch + 1)(currentEpoch)
}
return policies.BetweenEpochs(fEpoch-2, fEpoch+1)(currentEpoch)
},
Evaluation: submitWithdrawal,
}
// ValidatorsHaveWithdrawn checks the beacon state for the withdrawn validator and ensures it has been withdrawn.
// Uses default timing based on exit submission epoch.
var ValidatorsHaveWithdrawn = ValidatorsHaveWithdrawnAfterExitAtEpoch(defaultExitSubmissionEpoch)
var ValidatorsHaveWithdrawn = e2etypes.Evaluator{
Name: "validator_has_withdrawn_%d",
Policy: func(currentEpoch primitives.Epoch) bool {
// TODO: Fix this for mainnet configs.
if params.BeaconConfig().ConfigName != params.EndToEndName {
return false
}
// Only run this for minimal setups after capella
fEpoch := params.BeaconConfig().CapellaForkEpoch
// If Capella is disabled (starting at Deneb+), run after withdrawal submission
var validWithdrawnEpoch primitives.Epoch
if e2etypes.GenesisFork() >= version.Deneb {
validWithdrawnEpoch = exitSubmissionEpoch + 2
} else {
validWithdrawnEpoch = fEpoch + 1
}
// ValidatorsHaveWithdrawnAfterExitAtEpoch checks validators have withdrawn after exiting at the specified epoch.
// For pre-Deneb genesis, it runs at CapellaForkEpoch + 1 instead.
var ValidatorsHaveWithdrawnAfterExitAtEpoch = func(exitSubmitEpoch primitives.Epoch) e2etypes.Evaluator {
return e2etypes.Evaluator{
Name: "validator_has_withdrawn_%d",
Policy: func(currentEpoch primitives.Epoch) bool {
// TODO: Fix this for mainnet configs.
if params.BeaconConfig().ConfigName != params.EndToEndName {
return false
}
// Only run this for minimal setups after capella
fEpoch := params.BeaconConfig().CapellaForkEpoch
// If Capella is disabled (starting at Deneb+), run after withdrawal submission
var validWithdrawnEpoch primitives.Epoch
if e2etypes.GenesisFork() >= version.Deneb {
// Exit submitted at exitSubmitEpoch
// Exit epoch = exitSubmitEpoch + 1 + MAX_SEED_LOOKAHEAD
// Withdrawable epoch = exit epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY
// Add 1 more epoch for the sweep to process
exitEpoch := exitSubmitEpoch + 1 + primitives.Epoch(params.BeaconConfig().MaxSeedLookahead)
withdrawableEpoch := exitEpoch + primitives.Epoch(params.BeaconConfig().MinValidatorWithdrawabilityDelay)
validWithdrawnEpoch = withdrawableEpoch + 1
} else {
// For pre-Deneb genesis, give 2 epochs after Capella for:
// 1. BLS-to-exec changes to be processed (submitted in epoch before Capella)
// 2. Withdrawal sweep to reach all exited validators
validWithdrawnEpoch = fEpoch + 2
}
requiredPolicy := policies.OnEpoch(validWithdrawnEpoch)
return requiredPolicy(currentEpoch)
},
Evaluation: validatorsAreWithdrawn,
}
requiredPolicy := policies.OnEpoch(validWithdrawnEpoch)
return requiredPolicy(currentEpoch)
},
Evaluation: validatorsAreWithdrawn,
}
// ValidatorsVoteWithTheMajority verifies whether validator vote for eth1data using the majority algorithm.
@@ -388,7 +351,8 @@ func depositedValidatorsAreActive(ec *e2etypes.EvaluationContext, conns ...*grpc
continue // we aren't checking for this validator
}
// ignore voluntary exits when checking balance and active status
if _, exited := ec.ExitedVals[key]; exited {
exited := ec.ExitedVals[key]
if exited {
nexits++
delete(expected, key)
continue
@@ -493,7 +457,7 @@ func proposeVoluntaryExit(ec *e2etypes.EvaluationContext, conns ...*grpc.ClientC
return errors.Wrap(err, "could not propose exit")
}
pubk := bytesutil.ToBytes48(deposits[exitedIndex].Data.PublicKey)
ec.ExitedVals[pubk] = chainHead.HeadEpoch // Store submission epoch
ec.ExitedVals[pubk] = true
return nil
}
@@ -507,7 +471,7 @@ func proposeVoluntaryExit(ec *e2etypes.EvaluationContext, conns ...*grpc.ClientC
// Send an exit for a non-exited validator.
for i := 0; i < numOfExits; {
randIndex := primitives.ValidatorIndex(rand.Uint64() % params.BeaconConfig().MinGenesisActiveValidatorCount)
if _, alreadyExited := ec.ExitedVals[bytesutil.ToBytes48(privKeys[randIndex].PublicKey().Marshal())]; alreadyExited {
if ec.ExitedVals[bytesutil.ToBytes48(privKeys[randIndex].PublicKey().Marshal())] {
continue
}
if err := sendExit(randIndex); err != nil {
@@ -603,14 +567,6 @@ func validatorsVoteWithTheMajority(ec *e2etypes.EvaluationContext, conns ...*grp
b := blk.GetBlindedElectraBlock().Message
slot = b.Slot
vote = b.Body.Eth1Data.BlockHash
case *ethpb.BeaconBlockContainer_FuluBlock:
b := blk.GetFuluBlock().Block
slot = b.Slot
vote = b.Body.Eth1Data.BlockHash
case *ethpb.BeaconBlockContainer_BlindedFuluBlock:
b := blk.GetBlindedFuluBlock().Message
slot = b.Slot
vote = b.Body.Eth1Data.BlockHash
default:
return fmt.Errorf("block of type %T is unknown", blk.Block)
}
@@ -631,28 +587,20 @@ func validatorsVoteWithTheMajority(ec *e2etypes.EvaluationContext, conns ...*grp
}
if isFirstSlotInVotingPeriod {
ec.ExpectedEth1DataVote = vote
ec.Eth1DataMismatchCount = 0 // Reset for new voting period
return nil
}
if !bytes.Equal(vote, ec.ExpectedEth1DataVote) {
// Allow some tolerance for eth1data vote differences.
// Validators may have slightly different views of the eth1 chain
// as new blocks arrive during the voting period.
ec.Eth1DataMismatchCount++
// Allow up to 2 mismatches per voting period before failing.
if ec.Eth1DataMismatchCount > 2 {
for i := primitives.Slot(0); i < slot; i++ {
v, ok := ec.SeenVotes[i]
if ok {
fmt.Printf("vote at slot=%d = %#x\n", i, v)
} else {
fmt.Printf("did not see slot=%d\n", i)
}
for i := primitives.Slot(0); i < slot; i++ {
v, ok := ec.SeenVotes[i]
if ok {
fmt.Printf("vote at slot=%d = %#x\n", i, v)
} else {
fmt.Printf("did not see slot=%d\n", i)
}
return fmt.Errorf("incorrect eth1data vote for slot %d; expected: %#x vs voted: %#x (mismatch count: %d)",
slot, ec.ExpectedEth1DataVote, vote, ec.Eth1DataMismatchCount)
}
return fmt.Errorf("incorrect eth1data vote for slot %d; expected: %#x vs voted: %#x",
slot, ec.ExpectedEth1DataVote, vote)
}
}
return nil
@@ -696,12 +644,8 @@ func submitWithdrawal(ec *e2etypes.EvaluationContext, conns ...*grpc.ClientConn)
}
changes := make([]*structs.SignedBLSToExecutionChange, 0)
// Only send half the number of changes each time, to allow us to test
// at the fork boundary. When starting from Deneb+ at genesis, there's no
// fork boundary to test so we send all changes.
// at the fork boundary.
wantedChanges := numOfExits / 2
if e2etypes.GenesisFork() >= version.Deneb {
wantedChanges = numOfExits
}
for _, idx := range exitedIndices {
// Exit sending more change messages.
if len(changes) >= wantedChanges {

View File

@@ -26,11 +26,11 @@ import (
"google.golang.org/protobuf/types/known/emptypb"
)
var expectedParticipation = 0.98
var expectedParticipation = 0.99
var expectedMulticlientParticipation = 0.95
var expectedSyncParticipation = 0.95
var expectedSyncParticipation = 0.99
// ValidatorsAreActive ensures the expected amount of validators are active.
var ValidatorsAreActive = types.Evaluator{
@@ -62,7 +62,6 @@ var ValidatorSyncParticipation = types.Evaluator{
func validatorsAreActive(ec *types.EvaluationContext, conns ...*grpc.ClientConn) error {
conn := conns[0]
client := ethpb.NewBeaconChainClient(conn)
// Balances actually fluctuate but we just want to check initial balance.
validatorRequest := &ethpb.ListValidatorsRequest{
PageSize: int32(params.BeaconConfig().MinGenesisActiveValidatorCount),
@@ -73,26 +72,17 @@ func validatorsAreActive(ec *types.EvaluationContext, conns ...*grpc.ClientConn)
return errors.Wrap(err, "failed to get validators")
}
// Count should be MinGenesisActiveValidatorCount minus any validators that have exited.
// We determine actual exited count from the difference, as exits may be submitted but
// not yet processed, or affected by churn limits.
expectedCount := params.BeaconConfig().MinGenesisActiveValidatorCount
receivedCount := uint64(len(validators.ValidatorList))
maxExpected := params.BeaconConfig().MinGenesisActiveValidatorCount
minExpected := maxExpected - uint64(len(ec.ExitedVals))
if receivedCount > maxExpected {
return fmt.Errorf("validator count %d exceeds genesis count %d", receivedCount, maxExpected)
}
if receivedCount < minExpected {
return fmt.Errorf("validator count %d is less than expected minimum %d (genesis %d - %d submitted exits)",
receivedCount, minExpected, maxExpected, len(ec.ExitedVals))
if expectedCount != receivedCount {
return fmt.Errorf("expected validator count to be %d, received %d", expectedCount, receivedCount)
}
effBalanceLowCount := 0
exitEpochWrongCount := 0
withdrawEpochWrongCount := 0
for _, item := range validators.ValidatorList {
if _, exited := ec.ExitedVals[bytesutil.ToBytes48(item.Validator.PublicKey)]; exited {
if ec.ExitedVals[bytesutil.ToBytes48(item.Validator.PublicKey)] {
continue
}
if item.Validator.EffectiveBalance < params.BeaconConfig().MaxEffectiveBalance {
@@ -272,9 +262,9 @@ func validatorsSyncParticipation(_ *types.EvaluationContext, conns ...*grpc.Clie
// Skip fork slot.
continue
}
// Skip slots 1-2 at genesis - validators need time to ramp up after chain start
// due to doppelganger protection. This is a startup timing issue, not a fork transition issue.
if b.Block().Slot() < 3 {
// Skip slot 1 at genesis - validators need time to ramp up after chain start.
// This is a startup timing issue, not a fork transition issue.
if b.Block().Slot() == 1 {
continue
}
expectedParticipation := expectedSyncParticipation
@@ -310,34 +300,20 @@ func validatorsSyncParticipation(_ *types.EvaluationContext, conns ...*grpc.Clie
if b == nil || b.IsNil() {
return errors.New("nil block provided")
}
// Skip evaluation of fork transition slots as sync participation
// tends to drop briefly when transitioning between forks.
forkEpochs := []primitives.Epoch{
params.BeaconConfig().AltairForkEpoch,
params.BeaconConfig().BellatrixForkEpoch,
params.BeaconConfig().CapellaForkEpoch,
params.BeaconConfig().DenebForkEpoch,
params.BeaconConfig().ElectraForkEpoch,
params.BeaconConfig().FuluForkEpoch,
forkSlot, err := slots.EpochStart(params.BeaconConfig().AltairForkEpoch)
if err != nil {
return err
}
skipSlot := false
for _, forkEpoch := range forkEpochs {
// Skip fork epochs set to far future (not scheduled).
if forkEpoch == params.BeaconConfig().FarFutureEpoch {
continue
}
forkSlot, err := slots.EpochStart(forkEpoch)
if err != nil {
return err
}
// Skip the first two slots of each fork epoch.
if b.Block().Slot() == forkSlot || b.Block().Slot() == forkSlot+1 {
skipSlot = true
break
}
nexForkSlot, err := slots.EpochStart(params.BeaconConfig().BellatrixForkEpoch)
if err != nil {
return err
}
if skipSlot {
switch b.Block().Slot() {
case forkSlot, forkSlot + 1, nexForkSlot:
// Skip evaluation of the slot.
continue
default:
// no-op
}
syncAgg, err := b.Block().Body().SyncAggregate()
if err != nil {
@@ -382,14 +358,6 @@ func syncCompatibleBlockFromCtr(container *ethpb.BeaconBlockContainer) (interfac
if container.GetBlindedElectraBlock() != nil {
return blocks.NewSignedBeaconBlock(container.GetBlindedElectraBlock())
}
if container.GetFuluBlock() != nil {
return blocks.NewSignedBeaconBlock(container.GetFuluBlock())
}
if container.GetBlindedFuluBlock() != nil {
return blocks.NewSignedBeaconBlock(container.GetBlindedFuluBlock())
}
return nil, errors.New("no supported block type in container")
}

View File

@@ -10,7 +10,7 @@ import (
// Run mainnet e2e config with the current release validator against latest beacon node.
func TestEndToEnd_MainnetConfig_ValidatorAtCurrentRelease(t *testing.T) {
r := e2eMainnet(t, true, false, types.InitForkCfg(version.Bellatrix, version.Fulu, params.E2EMainnetTestConfig()))
r := e2eMainnet(t, true, false, types.InitForkCfg(version.Bellatrix, version.Electra, params.E2EMainnetTestConfig()))
r.run()
}

View File

@@ -8,38 +8,7 @@ import (
"github.com/OffchainLabs/prysm/v7/testing/endtoend/types"
)
// TestEndToEnd_MinimalConfig is the pre-submit e2e test from Electra to Fulu
// with compressed epochs. It runs 10 epochs with exit at epoch 4 (the earliest
// possible due to ShardCommitteePeriod=4), allowing all evaluators to complete:
// - Participation at epoch 2
// - Finalization at epoch 3
// - Fulu fork transition at epoch 2
// - BPO 1 at epoch 3 (15 blobs)
// - BPO 2 at epoch 4 (21 blobs)
// - Exit proposed at epoch 4
// - Exit confirmed at epoch 5
// - Withdrawal submitted at epoch 5
// - Withdrawal verified at epoch 8 (exit epoch 4 + 1 + MaxSeedLookahead + MinValidatorWithdrawabilityDelay + 1)
func TestEndToEnd_MinimalConfig(t *testing.T) {
cfg := params.E2ETestConfig()
cfg = types.InitForkCfg(version.Electra, version.Fulu, cfg)
// Set Fulu fork at epoch 2 for a quick fork transition test
cfg.FuluForkEpoch = 2
// Update BlobSchedule to use the new FuluForkEpoch for BPO testing
cfg.BlobSchedule = []params.BlobScheduleEntry{
{Epoch: cfg.DenebForkEpoch, MaxBlobsPerBlock: uint64(cfg.DeprecatedMaxBlobsPerBlock)},
{Epoch: cfg.ElectraForkEpoch, MaxBlobsPerBlock: uint64(cfg.DeprecatedMaxBlobsPerBlockElectra)},
// BPO (Blob Parameter Optimization) schedule for Fulu
{Epoch: cfg.FuluForkEpoch + 1, MaxBlobsPerBlock: 15},
{Epoch: cfg.FuluForkEpoch + 2, MaxBlobsPerBlock: 21},
}
cfg.InitializeForkSchedule()
r := e2eMinimal(t, cfg,
types.WithCheckpointSync(),
types.WithEpochs(10),
types.WithExitEpoch(4), // Minimum due to ShardCommitteePeriod=4
types.WithLargeBlobs(), // Use large blob transactions for BPO testing
)
r := e2eMinimal(t, types.InitForkCfg(version.Bellatrix, version.Electra, params.E2ETestConfig()), types.WithCheckpointSync())
r.run()
}

View File

@@ -1,17 +0,0 @@
package endtoend
import (
"testing"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/runtime/version"
"github.com/OffchainLabs/prysm/v7/testing/endtoend/types"
)
// TestEndToEnd_MinimalConfig_PostMerge is a post-submit test that runs the full
// e2e test from Bellatrix (post-merge) through all fork transitions to the latest fork.
// This test takes longer but provides comprehensive coverage of all forks.
func TestEndToEnd_MinimalConfig_PostMerge(t *testing.T) {
r := e2eMinimal(t, types.InitForkCfg(version.Bellatrix, version.Fulu, params.E2ETestConfig()), types.WithCheckpointSync())
r.run()
}

View File

@@ -59,15 +59,6 @@ func WithBuilder() E2EConfigOpt {
}
}
// WithLargeBlobs configures the transaction generator to use large blob
// transactions (6 blobs per tx) for testing BPO limits. Without this option,
// small blob transactions (1 blob per tx) are used by default.
func WithLargeBlobs() E2EConfigOpt {
return func(cfg *E2EConfig) {
cfg.UseLargeBlobs = true
}
}
func WithSSZOnly() E2EConfigOpt {
return func(cfg *E2EConfig) {
if err := os.Setenv(params.EnvNameOverrideAccept, api.OctetStreamMediaType); err != nil {
@@ -76,14 +67,6 @@ func WithSSZOnly() E2EConfigOpt {
}
}
// WithExitEpoch sets a custom epoch for voluntary exit submission.
// This affects ProposeVoluntaryExit, ValidatorsHaveExited, SubmitWithdrawal, and ValidatorsHaveWithdrawn evaluators.
func WithExitEpoch(e primitives.Epoch) E2EConfigOpt {
return func(cfg *E2EConfig) {
cfg.ExitEpoch = e
}
}
// E2EConfig defines the struct for all configurations needed for E2E testing.
type E2EConfig struct {
TestCheckpointSync bool
@@ -98,9 +81,7 @@ type E2EConfig struct {
UseValidatorCrossClient bool
UseBeaconRestApi bool
UseBuilder bool
UseLargeBlobs bool // Use large blob transactions (6 blobs per tx) for BPO testing
EpochsToRun uint64
ExitEpoch primitives.Epoch // Custom epoch for voluntary exit submission (0 means use default)
Seed int64
TracingSinkEndpoint string
Evaluators []Evaluator
@@ -114,9 +95,6 @@ type E2EConfig struct {
func GenesisFork() int {
cfg := params.BeaconConfig()
// Check from highest fork to lowest to find the genesis fork.
if cfg.FuluForkEpoch == 0 {
return version.Fulu
}
if cfg.ElectraForkEpoch == 0 {
return version.Electra
}
@@ -168,21 +146,16 @@ type DepositBalancer interface {
// EvaluationContext allows for additional data to be provided to evaluators that need extra state.
type EvaluationContext struct {
DepositBalancer
// ExitedVals maps validator pubkey to the epoch when their exit was submitted.
// The actual exit takes effect at: submission_epoch + 1 + MaxSeedLookahead
ExitedVals map[[48]byte]primitives.Epoch
ExitedVals map[[48]byte]bool
SeenVotes map[primitives.Slot][]byte
ExpectedEth1DataVote []byte
// Eth1DataMismatchCount tracks how many eth1data vote mismatches have been seen
// in the current voting period. Some tolerance is allowed for timing differences.
Eth1DataMismatchCount int
}
// NewEvaluationContext handles initializing internal datastructures (like maps) provided by the EvaluationContext.
func NewEvaluationContext(d DepositBalancer) *EvaluationContext {
return &EvaluationContext{
DepositBalancer: d,
ExitedVals: make(map[[48]byte]primitives.Epoch),
ExitedVals: make(map[[48]byte]bool),
SeenVotes: make(map[primitives.Slot][]byte),
}
}

View File

@@ -692,25 +692,14 @@ func (p *Builder) handleHeaderRequestElectra(w http.ResponseWriter) {
}
func (p *Builder) handleBlindedBlock(w http.ResponseWriter, req *http.Request) {
// Decode blinded block based on the current fork version.
// The beacon node sends JSON using api/server/structs types.
var err error
switch p.currVersion {
case version.Electra:
var sb structs.SignedBlindedBeaconBlockElectra
err = json.NewDecoder(req.Body).Decode(&sb)
case version.Deneb:
var sb structs.SignedBlindedBeaconBlockDeneb
err = json.NewDecoder(req.Body).Decode(&sb)
case version.Capella:
var sb structs.SignedBlindedBeaconBlockCapella
err = json.NewDecoder(req.Body).Decode(&sb)
default:
var sb structs.SignedBlindedBeaconBlockBellatrix
err = json.NewDecoder(req.Body).Decode(&sb)
// TODO update for fork specific
sb := &builderAPI.SignedBlindedBeaconBlockBellatrix{
SignedBlindedBeaconBlockBellatrix: &eth.SignedBlindedBeaconBlockBellatrix{},
}
err := json.NewDecoder(req.Body).Decode(sb)
if err != nil {
p.cfg.logger.WithError(err).WithField("version", version.String(p.currVersion)).Error("Could not decode blinded block")
p.cfg.logger.WithError(err).Error("Could not decode blinded block")
// TODO: Allow the method to unmarshal blinded blocks correctly
}
if p.currPayload == nil {
p.cfg.logger.Error("No payload is cached")

View File

@@ -10,6 +10,7 @@ go_library(
importpath = "github.com/OffchainLabs/prysm/v7/testing/spectest/utils",
visibility = ["//testing/spectest:__subpackages__"],
deps = [
"//config/features:go_default_library",
"//config/params:go_default_library",
"//io/file:go_default_library",
"//testing/require:go_default_library",

View File

@@ -6,12 +6,20 @@ import (
"fmt"
"testing"
"github.com/OffchainLabs/prysm/v7/config/features"
"github.com/OffchainLabs/prysm/v7/config/params"
)
// SetConfig sets the global params for spec tests depending on the option chosen.
// Provides reset function allowing to get back to the previous configuration at the end of a test.
func SetConfig(t testing.TB, config string) error {
params.SetupTestConfigCleanup(t)
resetFeatures := features.InitWithReset(&features.Flags{
LowValcountSweep: true,
})
t.Cleanup(resetFeatures)
switch config {
case "minimal":
params.OverrideBeaconConfig(params.MinimalSpecConfig().Copy())

View File

@@ -1,171 +0,0 @@
diff --git a/ecc/bls12-381/fp/BUILD.bazel b/ecc/bls12-381/fp/BUILD.bazel
index 4d57841..5b1dec4 100644
--- a/ecc/bls12-381/fp/BUILD.bazel
+++ b/ecc/bls12-381/fp/BUILD.bazel
@@ -7,15 +7,21 @@ go_library(
"arith.go",
"doc.go",
"element.go",
- "element_amd64.go",
- "element_amd64.s",
- "element_arm64.go",
- "element_arm64.s",
"element_exp.go",
"element_purego.go",
"vector.go",
"vector_purego.go",
- ],
+ ] + select({
+ "@io_bazel_rules_go//go/platform:amd64": [
+ "element_amd64.go",
+ "//field/asm/element_6w:element_6w_amd64"
+ ],
+ "@io_bazel_rules_go//go/platform:arm64": [
+ "element_arm64.go",
+ "//field/asm/element_6w:element_6w_arm64"
+ ],
+ "//conditions:default": [],
+ }),
importpath = "github.com/consensys/gnark-crypto/ecc/bls12-381/fp",
visibility = ["//visibility:public"],
deps = [
diff --git a/ecc/bls12-381/fr/BUILD.bazel b/ecc/bls12-381/fr/BUILD.bazel
index e24b29b..6beeb04 100644
--- a/ecc/bls12-381/fr/BUILD.bazel
+++ b/ecc/bls12-381/fr/BUILD.bazel
@@ -7,17 +7,24 @@ go_library(
"arith.go",
"doc.go",
"element.go",
- "element_amd64.go",
- "element_amd64.s",
- "element_arm64.go",
- "element_arm64.s",
"element_exp.go",
"element_purego.go",
"generator.go",
"vector.go",
- "vector_amd64.go",
"vector_purego.go",
- ],
+ ] + select({
+ "@io_bazel_rules_go//go/platform:amd64": [
+ "element_amd64.go",
+ "//field/asm/element_4w:element_4w_amd64",
+ "vector_amd64.go",
+ ],
+ "@io_bazel_rules_go//go/platform:arm64": [
+ "element_arm64.go",
+ "//field/asm/element_4w:element_4w_arm64"
+ ],
+ "//conditions:default": [],
+ }),
+
importpath = "github.com/consensys/gnark-crypto/ecc/bls12-381/fr",
visibility = ["//visibility:public"],
deps = [
diff --git a/field/asm/element_4w/BUILD.bazel b/field/asm/element_4w/BUILD.bazel
index ef0882d..975e6f9 100644
--- a/field/asm/element_4w/BUILD.bazel
+++ b/field/asm/element_4w/BUILD.bazel
@@ -16,3 +16,15 @@ alias(
actual = ":element_4w",
visibility = ["//visibility:public"],
)
+
+filegroup(
+ name = "element_4w_amd64",
+ srcs = ["element_4w_amd64.s"],
+ visibility = ["//visibility:public"],
+)
+
+filegroup(
+ name = "element_4w_arm64",
+ srcs = ["element_4w_arm64.s"],
+ visibility = ["//visibility:public"],
+)
diff --git a/field/asm/element_6w/BUILD.bazel b/field/asm/element_6w/BUILD.bazel
index fbbe81c..fd99a62 100644
--- a/field/asm/element_6w/BUILD.bazel
+++ b/field/asm/element_6w/BUILD.bazel
@@ -16,3 +16,15 @@ alias(
actual = ":element_6w",
visibility = ["//visibility:public"],
)
+
+filegroup(
+ name = "element_6w_amd64",
+ srcs = ["element_6w_amd64.s"],
+ visibility = ["//visibility:public"],
+)
+
+filegroup(
+ name = "element_6w_arm64",
+ srcs = ["element_6w_arm64.s"],
+ visibility = ["//visibility:public"],
+)
diff -urN gnark-patch-a/ecc/bn254/fp/BUILD.bazel gnark-patch-b/ecc/bn254/fp/BUILD.bazel
--- gnark-patch-a/ecc/bn254/fp/BUILD.bazel 2025-11-19 13:10:39
+++ gnark-patch-b/ecc/bn254/fp/BUILD.bazel 2025-11-19 13:08:50
@@ -7,16 +7,22 @@
"arith.go",
"doc.go",
"element.go",
- "element_amd64.go",
- "element_amd64.s",
- "element_arm64.go",
- "element_arm64.s",
"element_exp.go",
"element_purego.go",
"vector.go",
- "vector_amd64.go",
"vector_purego.go",
- ],
+ ] + select({
+ "@io_bazel_rules_go//go/platform:amd64": [
+ "element_amd64.go",
+ "//field/asm/element_4w:element_4w_amd64",
+ "vector_amd64.go",
+ ],
+ "@io_bazel_rules_go//go/platform:arm64": [
+ "element_arm64.go",
+ "//field/asm/element_4w:element_4w_arm64",
+ ],
+ "//conditions:default": [],
+ }),
importpath = "github.com/consensys/gnark-crypto/ecc/bn254/fp",
visibility = ["//visibility:public"],
deps = [
diff -urN gnark-patch-a/ecc/bn254/fr/BUILD.bazel gnark-patch-b/ecc/bn254/fr/BUILD.bazel
--- gnark-patch-a/ecc/bn254/fr/BUILD.bazel 2025-11-19 13:10:39
+++ gnark-patch-b/ecc/bn254/fr/BUILD.bazel 2025-11-19 13:08:55
@@ -7,17 +7,23 @@
"arith.go",
"doc.go",
"element.go",
- "element_amd64.go",
- "element_amd64.s",
- "element_arm64.go",
- "element_arm64.s",
"element_exp.go",
"element_purego.go",
"generator.go",
"vector.go",
- "vector_amd64.go",
"vector_purego.go",
- ],
+ ] + select({
+ "@io_bazel_rules_go//go/platform:amd64": [
+ "element_amd64.go",
+ "//field/asm/element_4w:element_4w_amd64",
+ "vector_amd64.go",
+ ],
+ "@io_bazel_rules_go//go/platform:arm64": [
+ "element_arm64.go",
+ "//field/asm/element_4w:element_4w_arm64",
+ ],
+ "//conditions:default": [],
+ }),
importpath = "github.com/consensys/gnark-crypto/ecc/bn254/fr",
visibility = ["//visibility:public"],
deps = [

View File

@@ -1,90 +0,0 @@
diff -urN a/BUILD.bazel b/BUILD.bazel
--- a/BUILD.bazel 1969-12-31 18:00:00.000000000 -0600
+++ b/BUILD.bazel 2025-01-05 12:00:00.000000000 -0600
@@ -0,0 +1,86 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "go_default_library",
+ srcs = [
+ "bindings.go",
+ "sha256_1_generic.go",
+ ] + select({
+ "@io_bazel_rules_go//go/platform:linux_amd64": [
+ "bindings_amd64.go",
+ "wrapper_linux_amd64.s",
+ ":hashtree_amd64_syso",
+ ],
+ "@io_bazel_rules_go//go/platform:windows_amd64": [
+ "bindings_amd64.go",
+ "wrapper_windows_amd64.s",
+ ":hashtree_amd64_syso",
+ ],
+ "@io_bazel_rules_go//go/platform:linux_arm64": [
+ "bindings_arm64.go",
+ "wrapper_arm64.s",
+ ":hashtree_arm64_syso",
+ ],
+ "@io_bazel_rules_go//go/platform:darwin_arm64": [
+ "bindings_arm64.go",
+ "wrapper_arm64.s",
+ ":hashtree_arm64_syso",
+ ],
+ "@io_bazel_rules_go//go/platform:darwin_amd64": [
+ "bindings_darwin_amd64.go",
+ ],
+ "//conditions:default": [],
+ }),
+ importpath = "github.com/OffchainLabs/hashtree",
+ visibility = ["//visibility:public"],
+ deps = ["@com_github_klauspost_cpuid_v2//:go_default_library"],
+)
+
+genrule(
+ name = "hashtree_arm64_syso",
+ srcs = [":hashtree_arm64"],
+ outs = ["hashtree_arm64.syso"],
+ cmd = "cp $(location :hashtree_arm64) $@",
+)
+
+genrule(
+ name = "hashtree_amd64_syso",
+ srcs = [":hashtree_amd64"],
+ outs = ["hashtree_amd64.syso"],
+ cmd = "cp $(location :hashtree_amd64) $@",
+)
+
+cc_library(
+ name = "hashtree_arm64",
+ srcs = [
+ "src/hashtree.c",
+ "src/sha256_generic.c",
+ "src/sha256_armv8_crypto.S",
+ "src/sha256_armv8_neon_x1.S",
+ "src/sha256_armv8_neon_x4.S",
+ ],
+ hdrs = ["src/hashtree.h"],
+ copts = ["-O3", "-Wall"],
+ linkstatic = True,
+ strip_include_prefix = "src",
+ visibility = ["//visibility:public"],
+)
+
+cc_library(
+ name = "hashtree_amd64",
+ srcs = [
+ "src/hashtree.c",
+ "src/sha256_generic.c",
+ "src/sha256_avx_x1.S",
+ "src/sha256_avx_x4.S",
+ "src/sha256_avx_x8.S",
+ "src/sha256_avx_x16.S",
+ "src/sha256_shani.S",
+ "src/sha256_sse_x1.S",
+ ],
+ hdrs = ["src/hashtree.h"],
+ copts = ["-O3", "-Wall", "-fno-integrated-as"],
+ linkstatic = True,
+ strip_include_prefix = "src",
+ visibility = ["//visibility:public"],
+)

View File

@@ -8,7 +8,7 @@ def _go_test_transition_impl(settings, attr):
if attr.eth_network == "minimal":
settings["//proto:network"] = "minimal"
settings["@io_bazel_rules_go//go/config:tags"] = ["minimal"] + settings["@io_bazel_rules_go//go/config:tags"]
settings["@io_bazel_rules_go//go/config:tags"] = ["minimal"] + settings["@io_bazel_rules_go//go/config:tags"]
elif attr.eth_network == "mainnet": # Default / optional
settings["//proto:network"] = "mainnet"
settings["@io_bazel_rules_go//go/config:tags"] = ["mainnet"] + settings["@io_bazel_rules_go//go/config:tags"]

View File

@@ -424,8 +424,7 @@ func debugStateTransition(
return st, errors.Wrap(err, "could not process block")
}
var valid bool
sigSet := set.Batch()
valid, err = sigSet.VerifyVerbosely()
valid, err = set.VerifyVerbosely()
if err != nil {
return st, errors.Wrap(err, "could not batch verify signature")
}