Compare commits

...

22 Commits

Author SHA1 Message Date
Kasey Kirkham
aee1349fbf ci fixes 2025-06-12 14:30:05 +02:00
Kasey Kirkham
e18e1a12de wait for clock in code paths that need to compute digests 2025-06-12 14:15:21 +02:00
Kasey Kirkham
46a883fdf0 fix test setup 2025-06-12 14:05:45 +02:00
Kasey Kirkham
1b01218eb9 derp 2025-06-12 14:00:39 +02:00
Kasey Kirkham
dfa945636f e2e fix 2025-06-12 13:49:38 +02:00
Kasey Kirkham
fd6c1d88c4 update digest->type handler for bpo 2025-06-12 13:38:31 +02:00
kasey
02f6b272df remove usages of params from proto packages (#15403)
* remove usages of params from proto packages

* make it harder to mess up the order of request limit args

* remove errant edit (Terence review)

* fix missed updates after sig change

---------

Co-authored-by: Kasey Kirkham <kasey@users.noreply.github.com>
2025-06-12 13:00:27 +02:00
Kasey Kirkham
398e88b52b implement bpo digest inc epoch + network/forks refactors 2025-06-12 12:46:14 +02:00
Manu NALEPA
43e0d7bfb1 Merge branch 'eip_7917' into fulu-devnet-2 2025-06-12 08:58:14 +02:00
Potuz
4323478a46 review 2025-06-11 18:06:22 +02:00
potuz
022f913374 Preston's review 2025-06-06 11:26:26 -03:00
potuz
6cc6c7e73d Increase deadling for processing blocks in spectests 2025-06-06 09:26:39 -03:00
terence tsao
a910e3cb17 Fix minimal tests 2025-06-06 09:20:26 -03:00
terence tsao
4d6457775b Remove deneb and electra entries from blob schedule
This was cherry picked from PR #15364
and edited to remove the minimal cases
2025-06-06 09:20:26 -03:00
potuz
66e2138aaa update spectests to 1.6.0-alpha.1 2025-06-06 09:20:26 -03:00
Potuz
3b98d4ac78 Marshal the state JSON 2025-06-06 09:20:26 -03:00
Potuz
6fca970bfb short circuit the proposer cache to use the state 2025-06-06 09:20:26 -03:00
Potuz
2c2ac4aa67 Add epoch transition code 2025-06-06 09:20:26 -03:00
potuz
4bee860907 Add the fields as shared 2025-06-06 09:20:26 -03:00
potuz
39bfe243fd Fix ToProto() and ToProtoUnsafe() 2025-06-06 09:20:26 -03:00
potuz
eb4e2d1b89 fix the hasher for the fulu state 2025-06-06 09:20:26 -03:00
potuz
9fa502fb0d Add the new Fulu state with the new field 2025-06-06 09:20:26 -03:00
154 changed files with 3338 additions and 1994 deletions

View File

@@ -253,16 +253,16 @@ filegroup(
url = "https://github.com/ethereum/EIPs/archive/5480440fe51742ed23342b68cf106cefd427e39d.tar.gz",
)
consensus_spec_version = "v1.6.0-alpha.0"
consensus_spec_version = "v1.6.0-alpha.1"
load("@prysm//tools:download_spectests.bzl", "consensus_spec_tests")
consensus_spec_tests(
name = "consensus_spec_tests",
flavors = {
"general": "sha256-W7oKvoM0nAkyitykRxAw6kmCvjYC01IqiNJy0AmCnMM=",
"minimal": "sha256-ig7/zxomjv6buBWMom4IxAJh3lFJ9+JnY44E7c8ZNP8=",
"mainnet": "sha256-mjx+MkXtPhCNv4c4knLYLIkvIdpF7WTjx/ElvGPQzSo=",
"general": "sha256-o4t9p3R+fQHF4KOykGmwlG3zDw5wUdVWprkzId8aIsk=",
"minimal": "sha256-sU7ToI8t3MR8x0vVjC8ERmAHZDWpEmnAC9FWIpHi5x4=",
"mainnet": "sha256-YKS4wngg0LgI9Upp4MYJ77aG+8+e/G4YeqEIlp06LZw=",
},
version = consensus_spec_version,
)
@@ -278,7 +278,7 @@ filegroup(
visibility = ["//visibility:public"],
)
""",
integrity = "sha256-u0RkIZIeGttb3sInR31mO64aBSwxALqO5SYIPlqEvPo=",
integrity = "sha256-Nv4TEuEJPQIM4E6T9J0FOITsmappmXZjGtlhe1HEXnU=",
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

@@ -16,7 +16,6 @@ go_library(
"//api/server/structs:go_default_library",
"//consensus-types/primitives:go_default_library",
"//encoding/bytesutil:go_default_library",
"//network/forks:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
"@com_github_pkg_errors//:go_default_library",

View File

@@ -9,7 +9,6 @@ import (
"net/url"
"path"
"regexp"
"sort"
"strconv"
"github.com/OffchainLabs/prysm/v6/api/client"
@@ -17,7 +16,6 @@ import (
"github.com/OffchainLabs/prysm/v6/api/server/structs"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v6/network/forks"
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/pkg/errors"
@@ -137,24 +135,6 @@ func (c *Client) GetFork(ctx context.Context, stateId StateOrBlockId) (*ethpb.Fo
return fr.ToConsensus()
}
// GetForkSchedule retrieve all forks, past present and future, of which this node is aware.
func (c *Client) GetForkSchedule(ctx context.Context) (forks.OrderedSchedule, error) {
body, err := c.Get(ctx, getForkSchedulePath)
if err != nil {
return nil, errors.Wrap(err, "error requesting fork schedule")
}
fsr := &forkScheduleResponse{}
err = json.Unmarshal(body, fsr)
if err != nil {
return nil, err
}
ofs, err := fsr.OrderedForkSchedule()
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("problem unmarshaling %s response", getForkSchedulePath))
}
return ofs, nil
}
// GetConfigSpec retrieve the current configs of the network used by the beacon node.
func (c *Client) GetConfigSpec(ctx context.Context) (*structs.GetSpecResponse, error) {
body, err := c.Get(ctx, getConfigSpecPath)
@@ -334,31 +314,3 @@ func (c *Client) GetBLStoExecutionChanges(ctx context.Context) (*structs.BLSToEx
}
return poolResponse, nil
}
type forkScheduleResponse struct {
Data []structs.Fork
}
func (fsr *forkScheduleResponse) OrderedForkSchedule() (forks.OrderedSchedule, error) {
ofs := make(forks.OrderedSchedule, 0)
for _, d := range fsr.Data {
epoch, err := strconv.ParseUint(d.Epoch, 10, 64)
if err != nil {
return nil, errors.Wrapf(err, "error parsing epoch %s", d.Epoch)
}
vSlice, err := hexutil.Decode(d.CurrentVersion)
if err != nil {
return nil, err
}
if len(vSlice) != 4 {
return nil, fmt.Errorf("got %d byte version, expected 4 bytes. version hex=%s", len(vSlice), d.CurrentVersion)
}
version := bytesutil.ToBytes4(vSlice)
ofs = append(ofs, forks.ForkScheduleEntry{
Version: version,
Epoch: primitives.Epoch(epoch),
})
}
sort.Sort(ofs)
return ofs, nil
}

View File

@@ -923,7 +923,14 @@ func BeaconStateFuluFromConsensus(st beaconState.BeaconState) (*BeaconStateFulu,
if err != nil {
return nil, err
}
srcLookahead, err := st.ProposerLookahead()
if err != nil {
return nil, err
}
lookahead := make([]string, len(srcLookahead))
for i, v := range srcLookahead {
lookahead[i] = fmt.Sprintf("%d", uint64(v))
}
return &BeaconStateFulu{
GenesisTime: fmt.Sprintf("%d", st.GenesisTime()),
GenesisValidatorsRoot: hexutil.Encode(st.GenesisValidatorsRoot()),
@@ -962,5 +969,6 @@ func BeaconStateFuluFromConsensus(st beaconState.BeaconState) (*BeaconStateFulu,
PendingDeposits: PendingDepositsFromConsensus(pbd),
PendingPartialWithdrawals: PendingPartialWithdrawalsFromConsensus(ppw),
PendingConsolidations: PendingConsolidationsFromConsensus(pc),
ProposerLookahead: lookahead,
}, nil
}

View File

@@ -219,4 +219,5 @@ type BeaconStateFulu struct {
PendingDeposits []*PendingDeposit `json:"pending_deposits"`
PendingPartialWithdrawals []*PendingPartialWithdrawal `json:"pending_partial_withdrawals"`
PendingConsolidations []*PendingConsolidation `json:"pending_consolidations"`
ProposerLookahead []string `json:"proposer_lookahead"`
}

View File

@@ -5,6 +5,7 @@ import (
"time"
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/helpers"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v6/monitoring/tracing/trace"
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
@@ -88,7 +89,7 @@ func (s *Service) OnAttestation(ctx context.Context, a ethpb.Att, disparity time
if err != nil {
return err
}
if err := attestation.IsValidAttestationIndices(ctx, indexedAtt); err != nil {
if err := attestation.IsValidAttestationIndices(ctx, indexedAtt, params.BeaconConfig().MaxValidatorsPerCommittee, params.BeaconConfig().MaxCommitteesPerSlot); err != nil {
return err
}

View File

@@ -41,7 +41,6 @@ go_library(
"//encoding/ssz:go_default_library",
"//math:go_default_library",
"//monitoring/tracing/trace:go_default_library",
"//network/forks:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/attestation:go_default_library",

View File

@@ -178,7 +178,7 @@ func VerifyAttestationNoVerifySignature(
}
}
return attestation.IsValidAttestationIndices(ctx, indexedAtt)
return attestation.IsValidAttestationIndices(ctx, indexedAtt, params.BeaconConfig().MaxValidatorsPerCommittee, params.BeaconConfig().MaxCommitteesPerSlot)
}
// ProcessAttestationNoVerifySignature processes the attestation without verifying the attestation signature. This
@@ -243,7 +243,7 @@ func VerifyIndexedAttestation(ctx context.Context, beaconState state.ReadOnlyBea
ctx, span := trace.StartSpan(ctx, "core.VerifyIndexedAttestation")
defer span.End()
if err := attestation.IsValidAttestationIndices(ctx, indexedAtt); err != nil {
if err := attestation.IsValidAttestationIndices(ctx, indexedAtt, params.BeaconConfig().MaxValidatorsPerCommittee, params.BeaconConfig().MaxCommitteesPerSlot); err != nil {
return err
}
domain, err := signing.Domain(

View File

@@ -11,7 +11,6 @@ import (
"github.com/OffchainLabs/prysm/v6/consensus-types/interfaces"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v6/crypto/bls"
"github.com/OffchainLabs/prysm/v6/network/forks"
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1/attestation"
"github.com/OffchainLabs/prysm/v6/time/slots"
@@ -98,7 +97,7 @@ func VerifyBlockHeaderSignature(beaconState state.BeaconState, header *ethpb.Sig
func VerifyBlockHeaderSignatureUsingCurrentFork(beaconState state.BeaconState, header *ethpb.SignedBeaconBlockHeader) error {
currentEpoch := slots.ToEpoch(header.Header.Slot)
fork, err := forks.Fork(currentEpoch)
fork, err := params.Fork(currentEpoch)
if err != nil {
return err
}
@@ -119,7 +118,7 @@ func VerifyBlockHeaderSignatureUsingCurrentFork(beaconState state.BeaconState, h
// via the respective epoch.
func VerifyBlockSignatureUsingCurrentFork(beaconState state.ReadOnlyBeaconState, blk interfaces.ReadOnlySignedBeaconBlock, blkRoot [32]byte) error {
currentEpoch := slots.ToEpoch(blk.Block().Slot())
fork, err := forks.Fork(currentEpoch)
fork, err := params.Fork(currentEpoch)
if err != nil {
return err
}
@@ -218,7 +217,7 @@ func createAttestationSignatureBatch(
if err != nil {
return nil, err
}
if err := attestation.IsValidAttestationIndices(ctx, ia); err != nil {
if err := attestation.IsValidAttestationIndices(ctx, ia, params.BeaconConfig().MaxValidatorsPerCommittee, params.BeaconConfig().MaxCommitteesPerSlot); err != nil {
return nil, err
}
indices := ia.GetAttestingIndices()

View File

@@ -2,23 +2,33 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = ["upgrade.go"],
srcs = [
"transition.go",
"upgrade.go",
],
importpath = "github.com/OffchainLabs/prysm/v6/beacon-chain/core/fulu",
visibility = ["//visibility:public"],
deps = [
"//beacon-chain/core/electra:go_default_library",
"//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/core/time:go_default_library",
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/state-native:go_default_library",
"//config/params:go_default_library",
"//monitoring/tracing/trace:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//time/slots:go_default_library",
"@com_github_pkg_errors//:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["upgrade_test.go"],
srcs = [
"transition_test.go",
"upgrade_test.go",
],
deps = [
":go_default_library",
"//beacon-chain/core/time:go_default_library",

View File

@@ -0,0 +1,47 @@
package fulu
import (
"context"
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/electra"
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/helpers"
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/monitoring/tracing/trace"
"github.com/OffchainLabs/prysm/v6/time/slots"
"github.com/pkg/errors"
)
func ProcessEpoch(ctx context.Context, state state.BeaconState) error {
if err := electra.ProcessEpoch(ctx, state); err != nil {
return errors.Wrap(err, "could not process epoch in fulu transition")
}
return processProposerLookahead(ctx, state)
}
func processProposerLookahead(ctx context.Context, state state.BeaconState) error {
_, span := trace.StartSpan(ctx, "fulu.processProposerLookahead")
defer span.End()
if state == nil || state.IsNil() {
return errors.New("nil state")
}
lookAhead, err := state.ProposerLookahead()
if err != nil {
return errors.Wrap(err, "could not get proposer lookahead")
}
lastEpochStart := len(lookAhead) - int(params.BeaconConfig().SlotsPerEpoch)
copy(lookAhead[:lastEpochStart], lookAhead[params.BeaconConfig().SlotsPerEpoch:])
lastEpoch := slots.ToEpoch(state.Slot()) + params.BeaconConfig().MinSeedLookahead + 1
indices, err := helpers.ActiveValidatorIndices(ctx, state, lastEpoch)
if err != nil {
return err
}
lastEpochProposers, err := helpers.PrecomputeProposerIndices(state, indices, lastEpoch)
if err != nil {
return errors.Wrap(err, "could not precompute proposer indices")
}
copy(lookAhead[lastEpochStart:], lastEpochProposers)
return state.SetProposerLookahead(lookAhead)
}

View File

@@ -0,0 +1,28 @@
package fulu_test
import (
"context"
"testing"
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/fulu"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/testing/require"
"github.com/OffchainLabs/prysm/v6/testing/util"
)
func TestProcessEpoch_CanProcessFulu(t *testing.T) {
st, _ := util.DeterministicGenesisStateElectra(t, params.BeaconConfig().MaxValidatorsPerCommittee)
require.NoError(t, st.SetSlot(10*params.BeaconConfig().SlotsPerEpoch))
st, err := fulu.UpgradeToFulu(context.Background(), st)
require.NoError(t, err)
preLookahead, err := st.ProposerLookahead()
require.NoError(t, err)
err = fulu.ProcessEpoch(context.Background(), st)
require.NoError(t, err)
postLookahead, err := st.ProposerLookahead()
require.NoError(t, err)
require.NotEqual(t, preLookahead[0], postLookahead[0])
for i, v := range preLookahead[params.BeaconConfig().SlotsPerEpoch:] {
require.Equal(t, v, postLookahead[i])
}
}

View File

@@ -1,18 +1,22 @@
package fulu
import (
"context"
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/helpers"
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/time"
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
state_native "github.com/OffchainLabs/prysm/v6/beacon-chain/state/state-native"
"github.com/OffchainLabs/prysm/v6/config/params"
enginev1 "github.com/OffchainLabs/prysm/v6/proto/engine/v1"
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v6/time/slots"
"github.com/pkg/errors"
)
// UpgradeToFulu updates inputs a generic state to return the version Fulu state.
// https://github.com/ethereum/consensus-specs/blob/v1.5.0-beta.5/specs/fulu/fork.md#upgrading-the-state
func UpgradeToFulu(beaconState state.BeaconState) (state.BeaconState, error) {
func UpgradeToFulu(ctx context.Context, beaconState state.BeaconState) (state.BeaconState, error) {
currentSyncCommittee, err := beaconState.CurrentSyncCommittee()
if err != nil {
return nil, err
@@ -101,8 +105,12 @@ func UpgradeToFulu(beaconState state.BeaconState) (state.BeaconState, error) {
if err != nil {
return nil, err
}
proposerLookahead, err := helpers.InitializeProposerLookahead(ctx, beaconState, slots.ToEpoch(beaconState.Slot()))
if err != nil {
return nil, err
}
s := &ethpb.BeaconStateElectra{
s := &ethpb.BeaconStateFulu{
GenesisTime: beaconState.GenesisTime(),
GenesisValidatorsRoot: beaconState.GenesisValidatorsRoot(),
Slot: beaconState.Slot(),
@@ -163,6 +171,7 @@ func UpgradeToFulu(beaconState state.BeaconState) (state.BeaconState, error) {
PendingDeposits: pendingDeposits,
PendingPartialWithdrawals: pendingPartialWithdrawals,
PendingConsolidations: pendingConsolidations,
ProposerLookahead: proposerLookahead,
}
// Need to cast the beaconState to use in helper functions

View File

@@ -25,7 +25,7 @@ func TestUpgradeToFulu(t *testing.T) {
require.NoError(t, st.SetBalances(bals))
preForkState := st.Copy()
mSt, err := fulu.UpgradeToFulu(st)
mSt, err := fulu.UpgradeToFulu(t.Context(), st)
require.NoError(t, err)
require.Equal(t, preForkState.GenesisTime(), mSt.GenesisTime())

View File

@@ -555,21 +555,31 @@ func UpdateProposerIndicesInCache(ctx context.Context, state state.ReadOnlyBeaco
if err != nil {
return err
}
// Skip cache update if the key already exists
_, ok := proposerIndicesCache.ProposerIndices(epoch, [32]byte(root))
if ok {
return nil
}
indices, err := ActiveValidatorIndices(ctx, state, epoch)
if err != nil {
return err
}
proposerIndices, err := PrecomputeProposerIndices(state, indices, epoch)
if err != nil {
return err
}
if len(proposerIndices) != int(params.BeaconConfig().SlotsPerEpoch) {
return errors.New("invalid proposer length returned from state")
var proposerIndices []primitives.ValidatorIndex
// use the state if post fulu (EIP-7917)
if state.Version() >= version.Fulu {
lookAhead, err := state.ProposerLookahead()
if err != nil {
return errors.Wrap(err, "could not get proposer lookahead")
}
proposerIndices = lookAhead[:params.BeaconConfig().SlotsPerEpoch]
} else {
// Skip cache update if the key already exists
_, ok := proposerIndicesCache.ProposerIndices(epoch, [32]byte(root))
if ok {
return nil
}
indices, err := ActiveValidatorIndices(ctx, state, epoch)
if err != nil {
return err
}
proposerIndices, err = PrecomputeProposerIndices(state, indices, epoch)
if err != nil {
return err
}
if len(proposerIndices) != int(params.BeaconConfig().SlotsPerEpoch) {
return errors.New("invalid proposer length returned from state")
}
}
// This is here to deal with tests only
var indicesArray [fieldparams.SlotsPerEpoch]primitives.ValidatorIndex
@@ -656,6 +666,25 @@ func ComputeCommittee(
return shuffledList[start:end], nil
}
// InitializeProposerLookahead computes the list of the proposer indices for the next cou of epochs.
func InitializeProposerLookahead(ctx context.Context, state state.ReadOnlyBeaconState, epoch primitives.Epoch) ([]uint64, error) {
lookAhead := make([]uint64, 0, uint64(params.BeaconConfig().MinSeedLookahead+1)*uint64(params.BeaconConfig().SlotsPerEpoch))
indices, err := ActiveValidatorIndices(ctx, state, epoch)
if err != nil {
return nil, errors.Wrap(err, "could not get active indices")
}
for i := range params.BeaconConfig().MinSeedLookahead + 1 {
proposerIndices, err := PrecomputeProposerIndices(state, indices, epoch+i)
if err != nil {
return nil, errors.Wrap(err, "could not compute proposer indices")
}
for _, proposerIndex := range proposerIndices {
lookAhead = append(lookAhead, uint64(proposerIndex))
}
}
return lookAhead, nil
}
// PrecomputeProposerIndices computes proposer indices of the current epoch and returns a list of proposer indices,
// the index of the list represents the slot number.
func PrecomputeProposerIndices(state state.ReadOnlyBeaconState, activeIndices []primitives.ValidatorIndex, e primitives.Epoch) ([]primitives.ValidatorIndex, error) {

View File

@@ -299,9 +299,29 @@ func ProposerIndexAtSlotFromCheckpoint(c *forkchoicetypes.Checkpoint, slot primi
return proposerIndices[slot%params.BeaconConfig().SlotsPerEpoch], nil
}
func beaconProposerIndexAtSlotFulu(state state.ReadOnlyBeaconState, slot primitives.Slot) (primitives.ValidatorIndex, error) {
e := slots.ToEpoch(slot)
stateEpoch := slots.ToEpoch(state.Slot())
if e < stateEpoch || e > stateEpoch+1 {
return 0, errors.Errorf("slot %d is not in the current epoch %d or the next epoch", slot, stateEpoch)
}
lookAhead, err := state.ProposerLookahead()
if err != nil {
return 0, errors.Wrap(err, "could not get proposer lookahead")
}
if e == stateEpoch {
return lookAhead[slot%params.BeaconConfig().SlotsPerEpoch], nil
}
// The caller is requesting the proposer for the next epoch
return lookAhead[slot%params.BeaconConfig().SlotsPerEpoch+params.BeaconConfig().SlotsPerEpoch], nil
}
// BeaconProposerIndexAtSlot returns proposer index at the given slot from the
// point of view of the given state as head state
func BeaconProposerIndexAtSlot(ctx context.Context, state state.ReadOnlyBeaconState, slot primitives.Slot) (primitives.ValidatorIndex, error) {
if state.Version() >= version.Fulu {
return beaconProposerIndexAtSlotFulu(state, slot)
}
e := slots.ToEpoch(slot)
// The cache uses the state root of the previous epoch - minimum_seed_lookahead last slot as key. (e.g. Starting epoch 1, slot 32, the key would be block root at slot 31)
// For simplicity, the node will skip caching of genesis epoch.

View File

@@ -1171,3 +1171,29 @@ func TestValidatorMaxEffectiveBalance(t *testing.T) {
// Sanity check that MinActivationBalance equals (pre-electra) MaxEffectiveBalance
assert.Equal(t, params.BeaconConfig().MinActivationBalance, params.BeaconConfig().MaxEffectiveBalance)
}
func TestBeaconProposerIndexAtSlotFulu(t *testing.T) {
lookahead := make([]uint64, 64)
lookahead[0] = 15
lookahead[1] = 16
lookahead[34] = 42
pbState := ethpb.BeaconStateFulu{
Slot: 100,
ProposerLookahead: lookahead,
}
st, err := state_native.InitializeFromProtoFulu(&pbState)
require.NoError(t, err)
idx, err := helpers.BeaconProposerIndexAtSlot(t.Context(), st, 96)
require.NoError(t, err)
require.Equal(t, primitives.ValidatorIndex(15), idx)
idx, err = helpers.BeaconProposerIndexAtSlot(t.Context(), st, 97)
require.NoError(t, err)
require.Equal(t, primitives.ValidatorIndex(16), idx)
idx, err = helpers.BeaconProposerIndexAtSlot(t.Context(), st, 130)
require.NoError(t, err)
require.Equal(t, primitives.ValidatorIndex(42), idx)
_, err = helpers.BeaconProposerIndexAtSlot(t.Context(), st, 95)
require.ErrorContains(t, "slot 95 is not in the current epoch 3 or the next epoch", err)
_, err = helpers.BeaconProposerIndexAtSlot(t.Context(), st, 160)
require.ErrorContains(t, "slot 160 is not in the current epoch 3 or the next epoch", err)
}

View File

@@ -44,7 +44,7 @@ func TestValidatorsCustodyRequirement(t *testing.T) {
validatorsIndex[primitives.ValidatorIndex(i)] = true
}
beaconState, err := state_native.InitializeFromProtoFulu(&ethpb.BeaconStateElectra{Validators: validators})
beaconState, err := state_native.InitializeFromProtoFulu(&ethpb.BeaconStateFulu{Validators: validators})
require.NoError(t, err)
actual, err := peerdas.ValidatorsCustodyRequirement(beaconState, validatorsIndex)

View File

@@ -4,7 +4,6 @@ go_library(
name = "go_default_library",
srcs = [
"domain.go",
"signature.go",
"signing_root.go",
],
importpath = "github.com/OffchainLabs/prysm/v6/beacon-chain/core/signing",
@@ -25,7 +24,6 @@ go_test(
name = "go_default_test",
srcs = [
"domain_test.go",
"signature_test.go",
"signing_root_test.go",
],
embed = [":go_default_library"],

View File

@@ -1,34 +0,0 @@
package signing
import (
"github.com/OffchainLabs/prysm/v6/config/params"
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/pkg/errors"
)
var ErrNilRegistration = errors.New("nil signed registration")
// VerifyRegistrationSignature verifies the signature of a validator's registration.
func VerifyRegistrationSignature(
sr *ethpb.SignedValidatorRegistrationV1,
) error {
if sr == nil || sr.Message == nil {
return ErrNilRegistration
}
d := params.BeaconConfig().DomainApplicationBuilder
// Per spec, we want the fork version and genesis validator to be nil.
// Which is genesis value and zero by default.
sd, err := ComputeDomain(
d,
nil, /* fork version */
nil /* genesis val root */)
if err != nil {
return err
}
if err := VerifySigningRoot(sr.Message, sr.Message.Pubkey, sr.Signature, sd); err != nil {
return ErrSigFailedToVerify
}
return nil
}

View File

@@ -1,42 +0,0 @@
package signing_test
import (
"testing"
"time"
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/signing"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/crypto/bls"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v6/testing/require"
)
func TestVerifyRegistrationSignature(t *testing.T) {
sk, err := bls.RandKey()
require.NoError(t, err)
reg := &ethpb.ValidatorRegistrationV1{
FeeRecipient: bytesutil.PadTo([]byte("fee"), 20),
GasLimit: 123456,
Timestamp: uint64(time.Now().Unix()),
Pubkey: sk.PublicKey().Marshal(),
}
d := params.BeaconConfig().DomainApplicationBuilder
domain, err := signing.ComputeDomain(d, nil, nil)
require.NoError(t, err)
sr, err := signing.ComputeSigningRoot(reg, domain)
require.NoError(t, err)
sk.Sign(sr[:]).Marshal()
sReg := &ethpb.SignedValidatorRegistrationV1{
Message: reg,
Signature: sk.Sign(sr[:]).Marshal(),
}
require.NoError(t, signing.VerifyRegistrationSignature(sReg))
sReg.Signature = []byte("bad")
require.ErrorIs(t, signing.VerifyRegistrationSignature(sReg), signing.ErrSigFailedToVerify)
sReg.Message = nil
require.ErrorIs(t, signing.VerifyRegistrationSignature(sReg), signing.ErrNilRegistration)
}

View File

@@ -303,7 +303,11 @@ func ProcessSlotsCore(ctx context.Context, span trace.Span, state state.BeaconSt
func ProcessEpoch(ctx context.Context, state state.BeaconState) (state.BeaconState, error) {
var err error
if time.CanProcessEpoch(state) {
if state.Version() >= version.Electra {
if state.Version() >= version.Fulu {
if err = fulu.ProcessEpoch(ctx, state); err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("could not process %s epoch", version.String(state.Version())))
}
} else if state.Version() >= version.Electra {
if err = electra.ProcessEpoch(ctx, state); err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("could not process %s epoch", version.String(state.Version())))
}
@@ -377,7 +381,7 @@ func UpgradeState(ctx context.Context, state state.BeaconState) (state.BeaconSta
}
if time.CanUpgradeToFulu(slot) {
state, err = fulu.UpgradeToFulu(state)
state, err = fulu.UpgradeToFulu(ctx, state)
if err != nil {
tracing.AnnotateError(span, err)
return nil, err

View File

@@ -518,7 +518,7 @@ func (s *Store) unmarshalState(_ context.Context, enc []byte, validatorEntries [
switch {
case hasFuluKey(enc):
protoState := &ethpb.BeaconStateElectra{}
protoState := &ethpb.BeaconStateFulu{}
if err := protoState.UnmarshalSSZ(enc[len(fuluKey):]); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal encoding for Fulu")
}
@@ -690,7 +690,7 @@ func marshalState(ctx context.Context, st state.ReadOnlyBeaconState) ([]byte, er
}
return snappy.Encode(nil, append(ElectraKey, rawObj...)), nil
case version.Fulu:
rState, ok := st.ToProtoUnsafe().(*ethpb.BeaconStateElectra)
rState, ok := st.ToProtoUnsafe().(*ethpb.BeaconStateFulu)
if !ok {
return nil, errors.New("non valid inner state")
}

View File

@@ -71,7 +71,6 @@ go_library(
"//monitoring/tracing:go_default_library",
"//monitoring/tracing/trace:go_default_library",
"//network:go_default_library",
"//network/forks:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/metadata:go_default_library",
"//runtime:go_default_library",
@@ -168,7 +167,6 @@ go_test(
"//crypto/hash:go_default_library",
"//encoding/bytesutil:go_default_library",
"//network:go_default_library",
"//network/forks:go_default_library",
"//proto/eth/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/metadata:go_default_library",

View File

@@ -15,7 +15,6 @@ import (
"github.com/OffchainLabs/prysm/v6/crypto/hash"
"github.com/OffchainLabs/prysm/v6/monitoring/tracing"
"github.com/OffchainLabs/prysm/v6/monitoring/tracing/trace"
"github.com/OffchainLabs/prysm/v6/network/forks"
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v6/time/slots"
"github.com/pkg/errors"
@@ -279,14 +278,8 @@ func (s *Service) BroadcastLightClientOptimisticUpdate(ctx context.Context, upda
return errors.New("attempted to broadcast nil light client optimistic update")
}
forkDigest, err := forks.ForkDigestFromEpoch(slots.ToEpoch(update.AttestedHeader().Beacon().Slot), s.genesisValidatorsRoot)
if err != nil {
err := errors.Wrap(err, "could not retrieve fork digest")
tracing.AnnotateError(span, err)
return err
}
if err := s.broadcastObject(ctx, update, lcOptimisticToTopic(forkDigest)); err != nil {
digest := params.ForkDigest(slots.ToEpoch(update.AttestedHeader().Beacon().Slot))
if err := s.broadcastObject(ctx, update, lcOptimisticToTopic(digest)); err != nil {
log.WithError(err).Debug("Failed to broadcast light client optimistic update")
err := errors.Wrap(err, "could not publish message")
tracing.AnnotateError(span, err)
@@ -305,13 +298,7 @@ func (s *Service) BroadcastLightClientFinalityUpdate(ctx context.Context, update
return errors.New("attempted to broadcast nil light client finality update")
}
forkDigest, err := forks.ForkDigestFromEpoch(slots.ToEpoch(update.AttestedHeader().Beacon().Slot), s.genesisValidatorsRoot)
if err != nil {
err := errors.Wrap(err, "could not retrieve fork digest")
tracing.AnnotateError(span, err)
return err
}
forkDigest := params.ForkDigest(slots.ToEpoch(update.AttestedHeader().Beacon().Slot))
if err := s.broadcastObject(ctx, update, lcFinalityToTopic(forkDigest)); err != nil {
log.WithError(err).Debug("Failed to broadcast light client finality update")
err := errors.Wrap(err, "could not publish message")

View File

@@ -16,12 +16,13 @@ import (
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/peers"
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/peers/scorers"
p2ptest "github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/testing"
"github.com/OffchainLabs/prysm/v6/beacon-chain/startup"
"github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/flags"
fieldparams "github.com/OffchainLabs/prysm/v6/config/fieldparams"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/consensus-types/interfaces"
"github.com/OffchainLabs/prysm/v6/consensus-types/wrapper"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v6/network/forks"
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
testpb "github.com/OffchainLabs/prysm/v6/proto/testing"
"github.com/OffchainLabs/prysm/v6/runtime/version"
@@ -61,6 +62,7 @@ func TestService_Broadcast(t *testing.T) {
topic := "/eth2/%x/testing"
// Set a test gossip mapping for testpb.TestSimpleMessage.
GossipTypeMapping[reflect.TypeOf(msg)] = topic
p.clock = startup.NewClock(p.genesisTime, bytesutil.ToBytes32(p.genesisValidatorsRoot))
digest, err := p.currentForkDigest()
require.NoError(t, err)
topic = fmt.Sprintf(topic, digest)
@@ -550,9 +552,7 @@ func TestService_BroadcastLightClientOptimisticUpdate(t *testing.T) {
require.NoError(t, err)
GossipTypeMapping[reflect.TypeOf(msg)] = LightClientOptimisticUpdateTopicFormat
digest, err := forks.ForkDigestFromEpoch(slots.ToEpoch(msg.AttestedHeader().Beacon().Slot), p.genesisValidatorsRoot)
require.NoError(t, err)
topic := fmt.Sprintf(LightClientOptimisticUpdateTopicFormat, digest)
topic := fmt.Sprintf(LightClientOptimisticUpdateTopicFormat, params.ForkDigest(slots.ToEpoch(msg.AttestedHeader().Beacon().Slot)))
// External peer subscribes to the topic.
topic += p.Encoding().ProtocolSuffix()
@@ -617,9 +617,7 @@ func TestService_BroadcastLightClientFinalityUpdate(t *testing.T) {
require.NoError(t, err)
GossipTypeMapping[reflect.TypeOf(msg)] = LightClientFinalityUpdateTopicFormat
digest, err := forks.ForkDigestFromEpoch(slots.ToEpoch(msg.AttestedHeader().Beacon().Slot), p.genesisValidatorsRoot)
require.NoError(t, err)
topic := fmt.Sprintf(LightClientFinalityUpdateTopicFormat, digest)
topic := fmt.Sprintf(LightClientFinalityUpdateTopicFormat, params.ForkDigest(slots.ToEpoch(msg.AttestedHeader().Beacon().Slot)))
// External peer subscribes to the topic.
topic += p.Encoding().ProtocolSuffix()

View File

@@ -2,6 +2,7 @@ package p2p
import (
"bytes"
"context"
"crypto/ecdsa"
"net"
"sync"
@@ -503,7 +504,11 @@ func (s *Service) createLocalNode(
localNode.SetFallbackIP(ipAddr)
localNode.SetFallbackUDP(udpPort)
localNode, err = addForkEntry(localNode, s.genesisTime, s.genesisValidatorsRoot)
clock, err := s.cfg.ClockWaiter.WaitForClock(context.Background())
if err != nil {
return nil, errors.Wrap(err, "timeout waiting for startup clock")
}
localNode, err = addForkEntry(localNode, clock.CurrentEpoch())
if err != nil {
return nil, errors.Wrap(err, "could not add eth2 fork version entry to enr")
}

View File

@@ -3,13 +3,10 @@ package p2p
import (
"bytes"
"fmt"
"time"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/network/forks"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
pb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
prysmTime "github.com/OffchainLabs/prysm/v6/time"
"github.com/OffchainLabs/prysm/v6/time/slots"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/enr"
"github.com/pkg/errors"
@@ -22,10 +19,11 @@ var eth2ENRKey = params.BeaconNetworkConfig().ETH2Key
// ForkDigest returns the current fork digest of
// the node according to the local clock.
func (s *Service) currentForkDigest() ([4]byte, error) {
if !s.isInitialized() {
if !s.isInitialized() || s.clock == nil {
return [4]byte{}, errors.New("state is not initialized")
}
return forks.CreateForkDigest(s.genesisTime, s.genesisValidatorsRoot)
return params.ForkDigest(s.clock.CurrentEpoch()), nil
}
// Compares fork ENRs between an incoming peer's record and our node's
@@ -79,24 +77,9 @@ func (s *Service) compareForkENR(record *enr.Record) error {
// which takes into account the current fork version from the current
// epoch to create a fork digest, the next fork version,
// and the next fork epoch.
func addForkEntry(
node *enode.LocalNode,
genesisTime time.Time,
genesisValidatorsRoot []byte,
) (*enode.LocalNode, error) {
digest, err := forks.CreateForkDigest(genesisTime, genesisValidatorsRoot)
if err != nil {
return nil, err
}
currentSlot := slots.Since(genesisTime)
currentEpoch := slots.ToEpoch(currentSlot)
if prysmTime.Now().Before(genesisTime) {
currentEpoch = 0
}
nextForkVersion, nextForkEpoch, err := forks.NextForkData(currentEpoch)
if err != nil {
return nil, err
}
func addForkEntry(node *enode.LocalNode, current primitives.Epoch) (*enode.LocalNode, error) {
digest := params.ForkDigest(current)
nextForkVersion, nextForkEpoch := params.NextForkData(current)
enrForkID := &pb.ENRForkID{
CurrentForkDigest: digest[:],
NextForkVersion: nextForkVersion[:],

View File

@@ -11,11 +11,11 @@ import (
mock "github.com/OffchainLabs/prysm/v6/beacon-chain/blockchain/testing"
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/signing"
"github.com/OffchainLabs/prysm/v6/beacon-chain/startup"
fieldparams "github.com/OffchainLabs/prysm/v6/config/fieldparams"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v6/network/forks"
pb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v6/testing/assert"
"github.com/OffchainLabs/prysm/v6/testing/require"
@@ -231,10 +231,8 @@ func TestDiscv5_AddRetrieveForkEntryENR(t *testing.T) {
nextForkVersion := []byte{0, 0, 0, 1}
params.OverrideBeaconConfig(c)
genesisTime := time.Now()
genesisValidatorsRoot := make([]byte, 32)
digest, err := forks.CreateForkDigest(genesisTime, make([]byte, 32))
require.NoError(t, err)
clock := startup.NewClock(time.Now(), [32]byte{})
digest := params.ForkDigest(clock.CurrentEpoch())
enrForkID := &pb.ENRForkID{
CurrentForkDigest: digest[:],
NextForkVersion: nextForkVersion,
@@ -256,7 +254,7 @@ func TestDiscv5_AddRetrieveForkEntryENR(t *testing.T) {
localNode := enode.NewLocalNode(db, pkey)
localNode.Set(entry)
want, err := signing.ComputeForkDigest([]byte{0, 0, 0, 0}, genesisValidatorsRoot)
want, err := signing.ComputeForkDigest([]byte{0, 0, 0, 0}, clock.GenesisValidatorsRootSlice())
require.NoError(t, err)
resp, err := forkEntry(localNode.Node().Record())
@@ -283,7 +281,8 @@ func TestAddForkEntry_Genesis(t *testing.T) {
params.OverrideBeaconConfig(bCfg)
localNode := enode.NewLocalNode(db, pkey)
localNode, err = addForkEntry(localNode, time.Now().Add(10*time.Second), bytesutil.PadTo([]byte{'A', 'B', 'C', 'D'}, 32))
clock := startup.NewClock(time.Now(), bCfg.GenesisValidatorsRoot)
localNode, err = addForkEntry(localNode, clock.CurrentEpoch())
require.NoError(t, err)
forkEntry, err := forkEntry(localNode.Node().Record())
require.NoError(t, err)

View File

@@ -25,7 +25,10 @@ func (s *Service) forkWatcher() {
// this over the epoch, which might be slightly wasteful
// but is fine nonetheless.
if s.dv5Listener != nil { // make sure it's not a local network
_, err := addForkEntry(s.dv5Listener.LocalNode(), s.genesisTime, s.genesisValidatorsRoot)
if s.clock == nil {
continue
}
_, err := addForkEntry(s.dv5Listener.LocalNode(), s.clock.CurrentEpoch())
if err != nil {
log.WithError(err).Error("Could not add fork entry")
}

View File

@@ -7,7 +7,6 @@ import (
"github.com/OffchainLabs/prysm/v6/crypto/hash"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v6/math"
"github.com/OffchainLabs/prysm/v6/network/forks"
pubsubpb "github.com/libp2p/go-libp2p-pubsub/pb"
)
@@ -39,7 +38,7 @@ func MsgID(genesisValidatorsRoot []byte, pmsg *pubsubpb.Message) string {
copy(msg, "invalid")
return bytesutil.UnsafeCastToString(msg)
}
_, fEpoch, err := forks.RetrieveForkDataFromDigest(digest, genesisValidatorsRoot)
_, fEpoch, err := params.ForkDataFromDigest(digest)
if err != nil {
// Impossible condition that should
// never be hit.

View File

@@ -7,10 +7,10 @@ import (
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/signing"
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p"
"github.com/OffchainLabs/prysm/v6/beacon-chain/startup"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/crypto/hash"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v6/network/forks"
"github.com/OffchainLabs/prysm/v6/testing/assert"
"github.com/golang/snappy"
pubsubpb "github.com/libp2p/go-libp2p-pubsub/pb"
@@ -18,22 +18,22 @@ import (
func TestMsgID_HashesCorrectly(t *testing.T) {
params.SetupTestConfigCleanup(t)
genesisValidatorsRoot := bytesutil.PadTo([]byte{'A'}, 32)
d, err := forks.CreateForkDigest(time.Now(), genesisValidatorsRoot)
assert.NoError(t, err)
clock := startup.NewClock(time.Now(), bytesutil.ToBytes32([]byte{'A'}))
valRoot := clock.GenesisValidatorsRoot()
d := params.ForkDigest(clock.CurrentEpoch())
tpc := fmt.Sprintf(p2p.BlockSubnetTopicFormat, d)
invalidSnappy := [32]byte{'J', 'U', 'N', 'K'}
pMsg := &pubsubpb.Message{Data: invalidSnappy[:], Topic: &tpc}
hashedData := hash.Hash(append(params.BeaconConfig().MessageDomainInvalidSnappy[:], pMsg.Data...))
msgID := string(hashedData[:20])
assert.Equal(t, msgID, p2p.MsgID(genesisValidatorsRoot, pMsg), "Got incorrect msg id")
assert.Equal(t, msgID, p2p.MsgID(valRoot[:], pMsg), "Got incorrect msg id")
validObj := [32]byte{'v', 'a', 'l', 'i', 'd'}
enc := snappy.Encode(nil, validObj[:])
nMsg := &pubsubpb.Message{Data: enc, Topic: &tpc}
hashedData = hash.Hash(append(params.BeaconConfig().MessageDomainValidSnappy[:], validObj[:]...))
msgID = string(hashedData[:20])
assert.Equal(t, msgID, p2p.MsgID(genesisValidatorsRoot, nMsg), "Got incorrect msg id")
assert.Equal(t, msgID, p2p.MsgID(valRoot[:], nMsg), "Got incorrect msg id")
}
func TestMessageIDFunction_HashesCorrectlyAltair(t *testing.T) {

View File

@@ -6,7 +6,6 @@ import (
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/encoder"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/network/forks"
pubsub "github.com/libp2p/go-libp2p-pubsub"
pubsubpb "github.com/libp2p/go-libp2p-pubsub/pb"
"github.com/libp2p/go-libp2p/core/peer"
@@ -53,36 +52,12 @@ func (s *Service) CanSubscribe(topic string) bool {
log.WithError(err).Error("Could not determine fork digest")
return false
}
altairForkDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().AltairForkEpoch, s.genesisValidatorsRoot)
if err != nil {
log.WithError(err).Error("Could not determine altair fork digest")
return false
}
bellatrixForkDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().BellatrixForkEpoch, s.genesisValidatorsRoot)
if err != nil {
log.WithError(err).Error("Could not determine Bellatrix fork digest")
return false
}
capellaForkDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().CapellaForkEpoch, s.genesisValidatorsRoot)
if err != nil {
log.WithError(err).Error("Could not determine Capella fork digest")
return false
}
denebForkDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().DenebForkEpoch, s.genesisValidatorsRoot)
if err != nil {
log.WithError(err).Error("Could not determine Deneb fork digest")
return false
}
electraForkDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().ElectraForkEpoch, s.genesisValidatorsRoot)
if err != nil {
log.WithError(err).Error("Could not determine Electra fork digest")
return false
}
fuluForkDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().FuluForkEpoch, s.genesisValidatorsRoot)
if err != nil {
log.WithError(err).Error("Could not determine Fulu fork digest")
return false
}
altairForkDigest := params.ForkDigest(params.BeaconConfig().AltairForkEpoch)
bellatrixForkDigest := params.ForkDigest(params.BeaconConfig().BellatrixForkEpoch)
capellaForkDigest := params.ForkDigest(params.BeaconConfig().CapellaForkEpoch)
denebForkDigest := params.ForkDigest(params.BeaconConfig().DenebForkEpoch)
electraForkDigest := params.ForkDigest(params.BeaconConfig().ElectraForkEpoch)
fuluForkDigest := params.ForkDigest(params.BeaconConfig().FuluForkEpoch)
switch parts[2] {
case fmt.Sprintf("%x", phase0ForkDigest):
case fmt.Sprintf("%x", altairForkDigest):

View File

@@ -11,8 +11,6 @@ import (
"github.com/OffchainLabs/prysm/v6/beacon-chain/startup"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v6/network/forks"
"github.com/OffchainLabs/prysm/v6/testing/assert"
"github.com/OffchainLabs/prysm/v6/testing/require"
prysmTime "github.com/OffchainLabs/prysm/v6/time"
pubsubpb "github.com/libp2p/go-libp2p-pubsub/pb"
@@ -23,10 +21,8 @@ func TestService_CanSubscribe(t *testing.T) {
params.SetupTestConfigCleanup(t)
currentFork := [4]byte{0x01, 0x02, 0x03, 0x04}
validProtocolSuffix := "/" + encoder.ProtocolSuffixSSZSnappy
genesisTime := time.Now()
var valRoot [32]byte
digest, err := forks.CreateForkDigest(genesisTime, valRoot[:])
assert.NoError(t, err)
clock := startup.NewClock(time.Now(), [32]byte{})
digest := params.ForkDigest(clock.CurrentEpoch())
type test struct {
name string
topic string
@@ -108,11 +104,12 @@ func TestService_CanSubscribe(t *testing.T) {
}
tests = append(tests, tt)
}
valRoot := clock.GenesisValidatorsRoot()
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := &Service{
genesisValidatorsRoot: valRoot[:],
genesisTime: genesisTime,
genesisTime: clock.GenesisTime(),
}
if got := s.CanSubscribe(tt.topic); got != tt.want {
t.Errorf("CanSubscribe(%s) = %v, want %v", tt.topic, got, tt.want)
@@ -220,10 +217,8 @@ func TestGossipTopicMapping_scanfcheck_GossipTopicFormattingSanityCheck(t *testi
func TestService_FilterIncomingSubscriptions(t *testing.T) {
params.SetupTestConfigCleanup(t)
validProtocolSuffix := "/" + encoder.ProtocolSuffixSSZSnappy
genesisTime := time.Now()
var valRoot [32]byte
digest, err := forks.CreateForkDigest(genesisTime, valRoot[:])
assert.NoError(t, err)
clock := startup.NewClock(time.Now(), [32]byte{})
digest := params.ForkDigest(clock.CurrentEpoch())
type args struct {
id peer.ID
subs []*pubsubpb.RPC_SubOpts
@@ -320,11 +315,12 @@ func TestService_FilterIncomingSubscriptions(t *testing.T) {
},
},
}
valRoot := clock.GenesisValidatorsRoot()
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := &Service{
genesisValidatorsRoot: valRoot[:],
genesisTime: genesisTime,
genesisTime: clock.GenesisTime(),
}
got, err := s.FilterIncomingSubscriptions(tt.args.id, tt.args.subs)
if (err != nil) != tt.wantErr {

View File

@@ -14,6 +14,7 @@ import (
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/peers"
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/peers/scorers"
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/types"
"github.com/OffchainLabs/prysm/v6/beacon-chain/startup"
"github.com/OffchainLabs/prysm/v6/config/features"
"github.com/OffchainLabs/prysm/v6/config/params"
leakybucket "github.com/OffchainLabs/prysm/v6/container/leaky-bucket"
@@ -82,6 +83,7 @@ type Service struct {
genesisTime time.Time
genesisValidatorsRoot []byte
activeValidatorCount uint64
clock *startup.Clock
}
// NewService initializes a new p2p service compatible with shared.Service interface. No

View File

@@ -13,7 +13,6 @@ import (
"github.com/OffchainLabs/prysm/v6/beacon-chain/startup"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v6/network/forks"
"github.com/OffchainLabs/prysm/v6/testing/assert"
"github.com/OffchainLabs/prysm/v6/testing/require"
prysmTime "github.com/OffchainLabs/prysm/v6/time"
@@ -346,14 +345,12 @@ func TestService_JoinLeaveTopic(t *testing.T) {
func initializeStateWithForkDigest(_ context.Context, t *testing.T, gs startup.ClockSetter) [4]byte {
gt := prysmTime.Now()
gvr := bytesutil.ToBytes32(bytesutil.PadTo([]byte("genesis validators root"), 32))
require.NoError(t, gs.SetClock(startup.NewClock(gt, gvr)))
fd, err := forks.CreateForkDigest(gt, gvr[:])
require.NoError(t, err)
clock := startup.NewClock(gt, gvr)
require.NoError(t, gs.SetClock(clock))
time.Sleep(50 * time.Millisecond) // wait for pubsub filter to initialize.
return fd
return params.ForkDigest(clock.CurrentEpoch())
}
// TODO: Uncomment when out of devnet

View File

@@ -9,7 +9,6 @@ go_library(
"//api/server/structs:go_default_library",
"//config/params:go_default_library",
"//monitoring/tracing/trace:go_default_library",
"//network/forks:go_default_library",
"//network/httputil:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
],
@@ -24,7 +23,6 @@ go_test(
"//config/params:go_default_library",
"//consensus-types/primitives:go_default_library",
"//encoding/bytesutil:go_default_library",
"//network/forks:go_default_library",
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",

View File

@@ -10,7 +10,6 @@ import (
"github.com/OffchainLabs/prysm/v6/api/server/structs"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/monitoring/tracing/trace"
"github.com/OffchainLabs/prysm/v6/network/forks"
"github.com/OffchainLabs/prysm/v6/network/httputil"
"github.com/ethereum/go-ethereum/common/hexutil"
)
@@ -33,34 +32,25 @@ func GetForkSchedule(w http.ResponseWriter, r *http.Request) {
_, span := trace.StartSpan(r.Context(), "config.GetForkSchedule")
defer span.End()
schedule := params.BeaconConfig().ForkVersionSchedule
schedule := params.SortedForkSchedule()
data := make([]*structs.Fork, 0, len(schedule))
if len(schedule) == 0 {
httputil.WriteJson(w, &structs.GetForkScheduleResponse{
Data: make([]*structs.Fork, 0),
Data: data,
})
return
}
versions := forks.SortedForkVersions(schedule)
chainForks := make([]*structs.Fork, len(schedule))
var previous, current []byte
for i, v := range versions {
if i == 0 {
previous = params.BeaconConfig().GenesisForkVersion
} else {
previous = current
}
copyV := v
current = copyV[:]
chainForks[i] = &structs.Fork{
PreviousVersion: hexutil.Encode(previous),
CurrentVersion: hexutil.Encode(current),
Epoch: fmt.Sprintf("%d", schedule[v]),
}
previous := schedule[0]
for _, entry := range schedule {
data = append(data, &structs.Fork{
PreviousVersion: hexutil.Encode(previous.ForkVersion[:]),
CurrentVersion: hexutil.Encode(entry.ForkVersion[:]),
Epoch: fmt.Sprintf("%d", entry.Epoch),
})
previous = entry
}
httputil.WriteJson(w, &structs.GetForkScheduleResponse{
Data: chainForks,
Data: data,
})
}

View File

@@ -11,9 +11,6 @@ import (
"github.com/OffchainLabs/prysm/v6/api/server/structs"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v6/network/forks"
"github.com/OffchainLabs/prysm/v6/testing/assert"
"github.com/OffchainLabs/prysm/v6/testing/require"
"github.com/ethereum/go-ethereum/common"
@@ -586,43 +583,34 @@ func TestGetSpec(t *testing.T) {
func TestForkSchedule_Ok(t *testing.T) {
t.Run("ok", func(t *testing.T) {
genesisForkVersion := []byte("Genesis")
firstForkVersion, firstForkEpoch := []byte("Firs"), primitives.Epoch(100)
secondForkVersion, secondForkEpoch := []byte("Seco"), primitives.Epoch(200)
thirdForkVersion, thirdForkEpoch := []byte("Thir"), primitives.Epoch(300)
params.SetupTestConfigCleanup(t)
config := params.BeaconConfig().Copy()
config.GenesisForkVersion = genesisForkVersion
// Create fork schedule adding keys in non-sorted order.
schedule := make(map[[4]byte]primitives.Epoch, 3)
schedule[bytesutil.ToBytes4(secondForkVersion)] = secondForkEpoch
schedule[bytesutil.ToBytes4(firstForkVersion)] = firstForkEpoch
schedule[bytesutil.ToBytes4(thirdForkVersion)] = thirdForkEpoch
config.ForkVersionSchedule = schedule
params.OverrideBeaconConfig(config)
config.InitializeForkSchedule()
request := httptest.NewRequest(http.MethodGet, "http://example.com/eth/v1/config/fork_schedule", nil)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
genesisStr, firstStr, secondStr := hexutil.Encode(config.GenesisForkVersion), hexutil.Encode(config.AltairForkVersion), hexutil.Encode(config.BellatrixForkVersion)
GetForkSchedule(writer, request)
require.Equal(t, http.StatusOK, writer.Code)
resp := &structs.GetForkScheduleResponse{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
require.Equal(t, 3, len(resp.Data))
schedule := params.SortedForkSchedule()
require.Equal(t, len(schedule), len(resp.Data))
fork := resp.Data[0]
assert.DeepEqual(t, hexutil.Encode(genesisForkVersion), fork.PreviousVersion)
assert.DeepEqual(t, hexutil.Encode(firstForkVersion), fork.CurrentVersion)
assert.Equal(t, fmt.Sprintf("%d", firstForkEpoch), fork.Epoch)
assert.Equal(t, genesisStr, fork.PreviousVersion)
assert.Equal(t, genesisStr, fork.CurrentVersion)
assert.Equal(t, fmt.Sprintf("%d", config.GenesisEpoch), fork.Epoch)
fork = resp.Data[1]
assert.DeepEqual(t, hexutil.Encode(firstForkVersion), fork.PreviousVersion)
assert.DeepEqual(t, hexutil.Encode(secondForkVersion), fork.CurrentVersion)
assert.Equal(t, fmt.Sprintf("%d", secondForkEpoch), fork.Epoch)
assert.Equal(t, genesisStr, fork.PreviousVersion)
assert.Equal(t, firstStr, fork.CurrentVersion)
assert.Equal(t, fmt.Sprintf("%d", config.AltairForkEpoch), fork.Epoch)
fork = resp.Data[2]
assert.DeepEqual(t, hexutil.Encode(secondForkVersion), fork.PreviousVersion)
assert.DeepEqual(t, hexutil.Encode(thirdForkVersion), fork.CurrentVersion)
assert.Equal(t, fmt.Sprintf("%d", thirdForkEpoch), fork.Epoch)
assert.Equal(t, firstStr, fork.PreviousVersion)
assert.Equal(t, secondStr, fork.CurrentVersion)
assert.Equal(t, fmt.Sprintf("%d", config.BellatrixForkEpoch), fork.Epoch)
})
t.Run("correct number of forks", func(t *testing.T) {
request := httptest.NewRequest(http.MethodGet, "http://example.com/eth/v1/config/fork_schedule", nil)
@@ -633,7 +621,7 @@ func TestForkSchedule_Ok(t *testing.T) {
require.Equal(t, http.StatusOK, writer.Code)
resp := &structs.GetForkScheduleResponse{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
os := forks.NewOrderedSchedule(params.BeaconConfig())
assert.Equal(t, os.Len(), len(resp.Data))
os := params.SortedForkSchedule()
assert.Equal(t, len(os), len(resp.Data))
})
}

View File

@@ -35,6 +35,7 @@ go_test(
"//beacon-chain/forkchoice/doubly-linked-tree:go_default_library",
"//beacon-chain/forkchoice/types:go_default_library",
"//beacon-chain/rpc/testutil:go_default_library",
"//config/params:go_default_library",
"//encoding/bytesutil:go_default_library",
"//runtime/version:go_default_library",
"//testing/assert:go_default_library",

View File

@@ -15,6 +15,7 @@ import (
doublylinkedtree "github.com/OffchainLabs/prysm/v6/beacon-chain/forkchoice/doubly-linked-tree"
forkchoicetypes "github.com/OffchainLabs/prysm/v6/beacon-chain/forkchoice/types"
"github.com/OffchainLabs/prysm/v6/beacon-chain/rpc/testutil"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v6/runtime/version"
"github.com/OffchainLabs/prysm/v6/testing/assert"
@@ -219,9 +220,10 @@ func TestGetBeaconStateV2(t *testing.T) {
resp := &structs.GetBeaconStateV2Response{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
assert.Equal(t, version.String(version.Fulu), resp.Version)
st := &structs.BeaconStateElectra{}
st := &structs.BeaconStateFulu{}
require.NoError(t, json.Unmarshal(resp.Data, st))
assert.Equal(t, "123", st.Slot)
assert.Equal(t, int(params.BeaconConfig().MinSeedLookahead+1)*int(params.BeaconConfig().SlotsPerEpoch), len(st.ProposerLookahead))
})
t.Run("execution optimistic", func(t *testing.T) {
parentRoot := [32]byte{'a'}

View File

@@ -20,7 +20,6 @@ go_library(
"//config/params:go_default_library",
"//encoding/bytesutil:go_default_library",
"//monitoring/tracing/trace:go_default_library",
"//network/forks:go_default_library",
"//network/httputil:go_default_library",
"//runtime/version:go_default_library",
"//time/slots:go_default_library",

View File

@@ -11,7 +11,6 @@ import (
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v6/monitoring/tracing/trace"
"github.com/OffchainLabs/prysm/v6/network/forks"
"github.com/OffchainLabs/prysm/v6/network/httputil"
"github.com/OffchainLabs/prysm/v6/runtime/version"
"github.com/OffchainLabs/prysm/v6/time/slots"
@@ -115,7 +114,7 @@ func (s *Server) GetLightClientUpdatesByRange(w http.ResponseWriter, req *http.R
updateSlot := update.AttestedHeader().Beacon().Slot
updateEpoch := slots.ToEpoch(updateSlot)
updateFork, err := forks.Fork(updateEpoch)
updateFork, err := params.Fork(updateEpoch)
if err != nil {
httputil.HandleError(w, "Could not get fork Version: "+err.Error(), http.StatusInternalServerError)
return

View File

@@ -88,7 +88,6 @@ go_library(
"//math:go_default_library",
"//monitoring/tracing:go_default_library",
"//monitoring/tracing/trace:go_default_library",
"//network/forks:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/eth/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",

View File

@@ -19,7 +19,6 @@ import (
"github.com/OffchainLabs/prysm/v6/encoding/ssz"
"github.com/OffchainLabs/prysm/v6/monitoring/tracing"
"github.com/OffchainLabs/prysm/v6/monitoring/tracing/trace"
"github.com/OffchainLabs/prysm/v6/network/forks"
enginev1 "github.com/OffchainLabs/prysm/v6/proto/engine/v1"
"github.com/OffchainLabs/prysm/v6/runtime/version"
"github.com/OffchainLabs/prysm/v6/time/slots"
@@ -220,7 +219,7 @@ func (vs *Server) getPayloadHeaderFromBuilder(
if signedBid == nil || signedBid.IsNil() {
return nil, errors.New("builder returned nil bid")
}
fork, err := forks.Fork(slots.ToEpoch(slot))
fork, err := params.Fork(slots.ToEpoch(slot))
if err != nil {
return nil, errors.Wrap(err, "unable to get fork information")
}

View File

@@ -29,7 +29,6 @@ import (
"github.com/OffchainLabs/prysm/v6/beacon-chain/sync"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v6/network/forks"
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v6/runtime/version"
"google.golang.org/grpc/codes"
@@ -156,7 +155,7 @@ func (vs *Server) ValidatorIndex(ctx context.Context, req *ethpb.ValidatorIndexR
//
// DomainData fetches the current domain version information from the beacon state.
func (vs *Server) DomainData(ctx context.Context, request *ethpb.DomainRequest) (*ethpb.DomainResponse, error) {
fork, err := forks.Fork(request.Epoch)
fork, err := params.Fork(request.Epoch)
if err != nil {
return nil, err
}

View File

@@ -35,12 +35,21 @@ func (g *Clock) GenesisValidatorsRoot() [32]byte {
return g.vr
}
// GenesisValidatorsRoot returns the genesis state validator root as a slice for convenience.
func (g *Clock) GenesisValidatorsRootSlice() []byte {
return g.vr[:]
}
// CurrentSlot returns the current slot relative to the time.Time value that Clock embeds.
func (g *Clock) CurrentSlot() types.Slot {
now := g.now()
return slots.Duration(g.t, now)
}
func (g *Clock) CurrentEpoch() types.Epoch {
return slots.ToEpoch(g.CurrentSlot())
}
// SlotStart computes the time the given slot begins.
func (g *Clock) SlotStart(slot types.Slot) time.Time {
return slots.BeginsAt(slot, g.t)

View File

@@ -61,6 +61,7 @@ type ReadOnlyBeaconState interface {
ReadOnlySyncCommittee
ReadOnlyDeposits
ReadOnlyConsolidations
ReadOnlyProposerLookahead
ToProtoUnsafe() interface{}
ToProto() interface{}
GenesisTime() uint64
@@ -95,6 +96,7 @@ type WriteOnlyBeaconState interface {
WriteOnlyConsolidations
WriteOnlyWithdrawals
WriteOnlyDeposits
WriteOnlyProposerLookahead
SetGenesisTime(val uint64) error
SetGenesisValidatorsRoot(val []byte) error
SetSlot(val primitives.Slot) error
@@ -239,6 +241,10 @@ type ReadOnlyConsolidations interface {
NumPendingConsolidations() (uint64, error)
}
type ReadOnlyProposerLookahead interface {
ProposerLookahead() ([]primitives.ValidatorIndex, error)
}
// WriteOnlyBlockRoots defines a struct which only has write access to block roots methods.
type WriteOnlyBlockRoots interface {
SetBlockRoots(val [][]byte) error
@@ -340,3 +346,7 @@ type WriteOnlyDeposits interface {
SetPendingDeposits(val []*ethpb.PendingDeposit) error
SetDepositBalanceToConsume(primitives.Gwei) error
}
type WriteOnlyProposerLookahead interface {
SetProposerLookahead([]primitives.ValidatorIndex) error
}

View File

@@ -17,6 +17,7 @@ go_library(
"getters_misc.go",
"getters_participation.go",
"getters_payload_header.go",
"getters_proposer_lookahead.go",
"getters_randao.go",
"getters_state.go",
"getters_sync_committee.go",
@@ -37,6 +38,7 @@ go_library(
"setters_misc.go",
"setters_participation.go",
"setters_payload_header.go",
"setters_proposer_lookahead.go",
"setters_randao.go",
"setters_state.go",
"setters_sync_committee.go",
@@ -97,6 +99,7 @@ go_test(
"getters_deposits_test.go",
"getters_exit_test.go",
"getters_participation_test.go",
"getters_setters_lookahead_test.go",
"getters_test.go",
"getters_validator_test.go",
"getters_withdrawal_test.go",

View File

@@ -3,7 +3,7 @@
Note: Whenever only the name of a file is provided, it's assumed to be in the `/beacon-chain/state/state-native` package.
- Add a `BeaconState[Version]FieldCount` configuration item to `/config/params/config.go` and set it in `/config/params/mainnet_config.go`.
- Add the field to the `BeaconState` struct in `beacon_state_mainnet.go` and `beacon_state_minimal.go`. Update the marshaling code too.
- Add the field to the `BeaconState` struct in `beacon_state.go`. Update the marshaling structs in the same file too.
- Add the field's metadata to `/beacon-chain/state/state-native/types/types.go`.
- Add a getter and a setter for the field, either to existing `getter_XXX.go`/`setter_XXX.go` files or create new ones if the field doesn't fit anywhere.
Add the new getter and setter to `/beacon-chain/state/interfaces.go`.
@@ -19,6 +19,6 @@ between states.
- Add the following functions: `InitializeFromProto[Version]()`, `InitializeFromProtoUnsafe[Version]()`.
- Update the following functions: `Copy()`, `initializeMerkleLayers()`, `RecordStateMetrics()` (applies only to multi-value slice fields), `rootSelector()`,
`finalizerCleanup()` (applies only to multi-value slice fields).
- If the field is a slice, add it to the field map in `types.go`.
- If the field is a slice, add it to the field map in `types.go`. This only applies to large slices that need to be rehashed only in part. In particular, this mostly applies for arrays of objects, and not for arrays of basic SSZ types as these are not hashed by taking the root of each element.
- If the field is a slice, update the `fieldConverters()` function in `/beacon-chain/state/fieldtrie/field_trie_helpers.go`. The exact implementation will vary
depending on a few factors (is the field similar to an existing one, is it a multi-value slice etc.)
depending on a few factors (is the field similar to an existing one, is it a multi-value slice etc). This applies only for the slices as mentioned in the previous comment.

View File

@@ -70,6 +70,7 @@ type BeaconState struct {
pendingDeposits []*ethpb.PendingDeposit // pending_deposits: List[PendingDeposit, PENDING_DEPOSITS_LIMIT]
pendingPartialWithdrawals []*ethpb.PendingPartialWithdrawal // pending_partial_withdrawals: List[PartialWithdrawal, PENDING_PARTIAL_WITHDRAWALS_LIMIT]
pendingConsolidations []*ethpb.PendingConsolidation // pending_consolidations: List[PendingConsolidation, PENDING_CONSOLIDATIONS_LIMIT]
proposerLookahead []primitives.ValidatorIndex // proposer_look_ahead: List[uint64, (MIN_LOOKAHEAD + 1)*SLOTS_PER_EPOCH]
id uint64
lock sync.RWMutex
@@ -125,6 +126,7 @@ type beaconStateMarshalable struct {
PendingDeposits []*ethpb.PendingDeposit `json:"pending_deposits" yaml:"pending_deposits"`
PendingPartialWithdrawals []*ethpb.PendingPartialWithdrawal `json:"pending_partial_withdrawals" yaml:"pending_partial_withdrawals"`
PendingConsolidations []*ethpb.PendingConsolidation `json:"pending_consolidations" yaml:"pending_consolidations"`
ProposerLookahead []primitives.ValidatorIndex `json:"proposer_look_ahead" yaml:"proposer_look_ahead"`
}
func (b *BeaconState) MarshalJSON() ([]byte, error) {
@@ -194,6 +196,7 @@ func (b *BeaconState) MarshalJSON() ([]byte, error) {
PendingDeposits: b.pendingDeposits,
PendingPartialWithdrawals: b.pendingPartialWithdrawals,
PendingConsolidations: b.pendingConsolidations,
ProposerLookahead: b.proposerLookahead,
}
return json.Marshal(marshalable)
}

View File

@@ -0,0 +1,19 @@
package state_native
import (
"slices"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v6/runtime/version"
)
// ProposerLookahead is a non-mutating call to the beacon state which returns a slice of
// validator indices that hold the proposers in the next few slots.
func (b *BeaconState) ProposerLookahead() ([]primitives.ValidatorIndex, error) {
if b.version < version.Fulu {
return nil, errNotSupported("ProposerLookahead", b.version)
}
b.lock.RLock()
defer b.lock.RUnlock()
return slices.Clone(b.proposerLookahead), nil
}

View File

@@ -0,0 +1,44 @@
package state_native_test
import (
"testing"
state_native "github.com/OffchainLabs/prysm/v6/beacon-chain/state/state-native"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v6/testing/require"
)
func TestProposerLookahead(t *testing.T) {
t.Run("Fulu expected values", func(t *testing.T) {
lookahead := make([]uint64, int(params.BeaconConfig().MinSeedLookahead+1)*int(params.BeaconConfig().SlotsPerEpoch))
want := make([]primitives.ValidatorIndex, int(params.BeaconConfig().MinSeedLookahead+1)*int(params.BeaconConfig().SlotsPerEpoch))
st, err := state_native.InitializeFromProtoFulu(&ethpb.BeaconStateFulu{
ProposerLookahead: lookahead,
})
require.NoError(t, err)
got, err := st.ProposerLookahead()
require.NoError(t, err)
require.Equal(t, len(want), len(got))
for i, w := range want {
require.Equal(t, w, got[i], "index %d", i)
}
})
t.Run("Fulu error on invalid size", func(t *testing.T) {
lookahead := make([]primitives.ValidatorIndex, int(params.BeaconConfig().MinSeedLookahead+1)*int(params.BeaconConfig().SlotsPerEpoch)+1)
st, err := state_native.InitializeFromProtoFulu(&ethpb.BeaconStateFulu{})
require.NoError(t, err)
require.ErrorContains(t, "invalid size for proposer lookahead", st.SetProposerLookahead(lookahead))
})
t.Run("earlier than electra returns error", func(t *testing.T) {
st, err := state_native.InitializeFromProtoDeneb(&ethpb.BeaconStateDeneb{})
require.NoError(t, err)
_, err = st.ProposerLookahead()
require.ErrorContains(t, "is not supported", err)
lookahead := make([]primitives.ValidatorIndex, int(params.BeaconConfig().MinSeedLookahead+1)*int(params.BeaconConfig().SlotsPerEpoch))
require.ErrorContains(t, "is not supported", st.SetProposerLookahead(lookahead))
})
}

View File

@@ -182,7 +182,7 @@ func (b *BeaconState) ToProtoUnsafe() interface{} {
NextWithdrawalValidatorIndex: b.nextWithdrawalValidatorIndex,
HistoricalSummaries: b.historicalSummaries,
}
case version.Electra, version.Fulu:
case version.Electra:
return &ethpb.BeaconStateElectra{
GenesisTime: b.genesisTime,
GenesisValidatorsRoot: gvrCopy[:],
@@ -222,6 +222,51 @@ func (b *BeaconState) ToProtoUnsafe() interface{} {
PendingPartialWithdrawals: b.pendingPartialWithdrawals,
PendingConsolidations: b.pendingConsolidations,
}
case version.Fulu:
lookahead := make([]uint64, len(b.proposerLookahead))
for i, v := range b.proposerLookahead {
lookahead[i] = uint64(v)
}
return &ethpb.BeaconStateFulu{
GenesisTime: b.genesisTime,
GenesisValidatorsRoot: gvrCopy[:],
Slot: b.slot,
Fork: b.fork,
LatestBlockHeader: b.latestBlockHeader,
BlockRoots: br,
StateRoots: sr,
HistoricalRoots: b.historicalRoots.Slice(),
Eth1Data: b.eth1Data,
Eth1DataVotes: b.eth1DataVotes,
Eth1DepositIndex: b.eth1DepositIndex,
Validators: vals,
Balances: bals,
RandaoMixes: rm,
Slashings: b.slashings,
PreviousEpochParticipation: b.previousEpochParticipation,
CurrentEpochParticipation: b.currentEpochParticipation,
JustificationBits: b.justificationBits,
PreviousJustifiedCheckpoint: b.previousJustifiedCheckpoint,
CurrentJustifiedCheckpoint: b.currentJustifiedCheckpoint,
FinalizedCheckpoint: b.finalizedCheckpoint,
InactivityScores: inactivityScores,
CurrentSyncCommittee: b.currentSyncCommittee,
NextSyncCommittee: b.nextSyncCommittee,
LatestExecutionPayloadHeader: b.latestExecutionPayloadHeaderDeneb,
NextWithdrawalIndex: b.nextWithdrawalIndex,
NextWithdrawalValidatorIndex: b.nextWithdrawalValidatorIndex,
HistoricalSummaries: b.historicalSummaries,
DepositRequestsStartIndex: b.depositRequestsStartIndex,
DepositBalanceToConsume: b.depositBalanceToConsume,
ExitBalanceToConsume: b.exitBalanceToConsume,
EarliestExitEpoch: b.earliestExitEpoch,
ConsolidationBalanceToConsume: b.consolidationBalanceToConsume,
EarliestConsolidationEpoch: b.earliestConsolidationEpoch,
PendingDeposits: b.pendingDeposits,
PendingPartialWithdrawals: b.pendingPartialWithdrawals,
PendingConsolidations: b.pendingConsolidations,
ProposerLookahead: lookahead,
}
default:
return nil
}
@@ -388,7 +433,7 @@ func (b *BeaconState) ToProto() interface{} {
NextWithdrawalValidatorIndex: b.nextWithdrawalValidatorIndex,
HistoricalSummaries: b.historicalSummariesVal(),
}
case version.Electra, version.Fulu:
case version.Electra:
return &ethpb.BeaconStateElectra{
GenesisTime: b.genesisTime,
GenesisValidatorsRoot: gvrCopy[:],
@@ -428,6 +473,51 @@ func (b *BeaconState) ToProto() interface{} {
PendingPartialWithdrawals: b.pendingPartialWithdrawalsVal(),
PendingConsolidations: b.pendingConsolidationsVal(),
}
case version.Fulu:
lookahead := make([]uint64, len(b.proposerLookahead))
for i, v := range b.proposerLookahead {
lookahead[i] = uint64(v)
}
return &ethpb.BeaconStateFulu{
GenesisTime: b.genesisTime,
GenesisValidatorsRoot: gvrCopy[:],
Slot: b.slot,
Fork: b.forkVal(),
LatestBlockHeader: b.latestBlockHeaderVal(),
BlockRoots: br,
StateRoots: sr,
HistoricalRoots: b.historicalRoots.Slice(),
Eth1Data: b.eth1DataVal(),
Eth1DataVotes: b.eth1DataVotesVal(),
Eth1DepositIndex: b.eth1DepositIndex,
Validators: b.validatorsVal(),
Balances: b.balancesVal(),
RandaoMixes: rm,
Slashings: b.slashingsVal(),
PreviousEpochParticipation: b.previousEpochParticipationVal(),
CurrentEpochParticipation: b.currentEpochParticipationVal(),
JustificationBits: b.justificationBitsVal(),
PreviousJustifiedCheckpoint: b.previousJustifiedCheckpointVal(),
CurrentJustifiedCheckpoint: b.currentJustifiedCheckpointVal(),
FinalizedCheckpoint: b.finalizedCheckpointVal(),
InactivityScores: b.inactivityScoresVal(),
CurrentSyncCommittee: b.currentSyncCommitteeVal(),
NextSyncCommittee: b.nextSyncCommitteeVal(),
LatestExecutionPayloadHeader: b.latestExecutionPayloadHeaderDeneb.Copy(),
NextWithdrawalIndex: b.nextWithdrawalIndex,
NextWithdrawalValidatorIndex: b.nextWithdrawalValidatorIndex,
HistoricalSummaries: b.historicalSummariesVal(),
DepositRequestsStartIndex: b.depositRequestsStartIndex,
DepositBalanceToConsume: b.depositBalanceToConsume,
ExitBalanceToConsume: b.exitBalanceToConsume,
EarliestExitEpoch: b.earliestExitEpoch,
ConsolidationBalanceToConsume: b.consolidationBalanceToConsume,
EarliestConsolidationEpoch: b.earliestConsolidationEpoch,
PendingDeposits: b.pendingDepositsVal(),
PendingPartialWithdrawals: b.pendingPartialWithdrawalsVal(),
PendingConsolidations: b.pendingConsolidationsVal(),
ProposerLookahead: lookahead,
}
default:
return nil
}
@@ -554,4 +644,12 @@ func ProtobufBeaconStateElectra(s interface{}) (*ethpb.BeaconStateElectra, error
return pbState, nil
}
var ProtobufBeaconStateFulu = ProtobufBeaconStateElectra
// ProtobufBeaconStateFulu transforms an input into beacon state Fulu in the form of protobuf.
// Error is returned if the input is not type protobuf beacon state.
func ProtobufBeaconStateFulu(s interface{}) (*ethpb.BeaconStateFulu, error) {
pbState, ok := s.(*ethpb.BeaconStateFulu)
if !ok {
return nil, errors.New("input is not type pb.BeaconStateFulu")
}
return pbState, nil
}

View File

@@ -320,5 +320,13 @@ func ComputeFieldRootsWithHasher(ctx context.Context, state *BeaconState) ([][]b
fieldRoots[types.PendingConsolidations.RealPosition()] = pcRoot[:]
}
if state.version >= version.Fulu {
// Proposer lookahead root.
proposerLookaheadRoot, err := stateutil.ProposerLookaheadRoot(state.proposerLookahead)
if err != nil {
return nil, errors.Wrap(err, "could not compute proposer lookahead merkleization")
}
fieldRoots[types.ProposerLookahead.RealPosition()] = proposerLookaheadRoot[:]
}
return fieldRoots, nil
}

View File

@@ -0,0 +1,30 @@
package state_native
import (
"errors"
"github.com/OffchainLabs/prysm/v6/beacon-chain/state/state-native/types"
"github.com/OffchainLabs/prysm/v6/beacon-chain/state/stateutil"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v6/runtime/version"
)
// SetProposerLookahead is a mutating call to the beacon state which sets the proposer lookahead
func (b *BeaconState) SetProposerLookahead(lookahead []primitives.ValidatorIndex) error {
if b.version < version.Fulu {
return errNotSupported("SetProposerLookahead", b.version)
}
if len(lookahead) != int((params.BeaconConfig().MinSeedLookahead+1))*int(params.BeaconConfig().SlotsPerEpoch) {
return errors.New("invalid size for proposer lookahead")
}
b.lock.Lock()
defer b.lock.Unlock()
b.sharedFieldReferences[types.ProposerLookahead].MinusRef()
b.sharedFieldReferences[types.ProposerLookahead] = stateutil.NewRef(1)
b.proposerLookahead = lookahead
b.markFieldAsDirty(types.ProposerLookahead)
return nil
}

View File

@@ -14,6 +14,7 @@ import (
"github.com/OffchainLabs/prysm/v6/config/features"
fieldparams "github.com/OffchainLabs/prysm/v6/config/fieldparams"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
mvslice "github.com/OffchainLabs/prysm/v6/container/multi-value-slice"
"github.com/OffchainLabs/prysm/v6/container/slice"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
@@ -108,7 +109,10 @@ var (
types.PendingConsolidations,
)
fuluFields = electraFields
fuluFields = append(
electraFields,
types.ProposerLookahead,
)
)
const (
@@ -118,14 +122,14 @@ const (
capellaSharedFieldRefCount = 13
denebSharedFieldRefCount = 13
electraSharedFieldRefCount = 16
fuluSharedFieldRefCount = 16
fuluSharedFieldRefCount = 17
experimentalStatePhase0SharedFieldRefCount = 5
experimentalStateAltairSharedFieldRefCount = 5
experimentalStateBellatrixSharedFieldRefCount = 6
experimentalStateCapellaSharedFieldRefCount = 7
experimentalStateDenebSharedFieldRefCount = 7
experimentalStateElectraSharedFieldRefCount = 10
experimentalStateFuluSharedFieldRefCount = 10
experimentalStateFuluSharedFieldRefCount = 11
)
// InitializeFromProtoPhase0 the beacon state from a protobuf representation.
@@ -159,8 +163,8 @@ func InitializeFromProtoElectra(st *ethpb.BeaconStateElectra) (state.BeaconState
}
// InitializeFromProtoFulu the beacon state from a protobuf representation.
func InitializeFromProtoFulu(st *ethpb.BeaconStateElectra) (state.BeaconState, error) {
return InitializeFromProtoUnsafeFulu(proto.Clone(st).(*ethpb.BeaconStateElectra))
func InitializeFromProtoFulu(st *ethpb.BeaconStateFulu) (state.BeaconState, error) {
return InitializeFromProtoUnsafeFulu(proto.Clone(st).(*ethpb.BeaconStateFulu))
}
// InitializeFromProtoUnsafePhase0 directly uses the beacon state protobuf fields
@@ -842,7 +846,7 @@ func InitializeFromProtoUnsafeElectra(st *ethpb.BeaconStateElectra) (state.Beaco
// InitializeFromProtoUnsafeFulu directly uses the beacon state protobuf fields
// and sets them as fields of the BeaconState type.
func InitializeFromProtoUnsafeFulu(st *ethpb.BeaconStateElectra) (state.BeaconState, error) {
func InitializeFromProtoUnsafeFulu(st *ethpb.BeaconStateFulu) (state.BeaconState, error) {
if st == nil {
return nil, errors.New("received nil state")
}
@@ -852,6 +856,10 @@ func InitializeFromProtoUnsafeFulu(st *ethpb.BeaconStateElectra) (state.BeaconSt
hRoots[i] = bytesutil.ToBytes32(r)
}
proposerLookahead := make([]primitives.ValidatorIndex, len(st.ProposerLookahead))
for i, v := range st.ProposerLookahead {
proposerLookahead[i] = primitives.ValidatorIndex(v)
}
fieldCount := params.BeaconConfig().BeaconStateFuluFieldCount
b := &BeaconState{
version: version.Fulu,
@@ -886,6 +894,7 @@ func InitializeFromProtoUnsafeFulu(st *ethpb.BeaconStateElectra) (state.BeaconSt
pendingDeposits: st.PendingDeposits,
pendingPartialWithdrawals: st.PendingPartialWithdrawals,
pendingConsolidations: st.PendingConsolidations,
proposerLookahead: proposerLookahead,
dirtyFields: make(map[types.FieldIndex]bool, fieldCount),
dirtyIndices: make(map[types.FieldIndex][]uint64, fieldCount),
@@ -950,6 +959,7 @@ func InitializeFromProtoUnsafeFulu(st *ethpb.BeaconStateElectra) (state.BeaconSt
b.sharedFieldReferences[types.PendingDeposits] = stateutil.NewRef(1)
b.sharedFieldReferences[types.PendingPartialWithdrawals] = stateutil.NewRef(1)
b.sharedFieldReferences[types.PendingConsolidations] = stateutil.NewRef(1)
b.sharedFieldReferences[types.ProposerLookahead] = stateutil.NewRef(1) // New in Fulu.
if !features.Get().EnableExperimentalState {
b.sharedFieldReferences[types.BlockRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[types.StateRoots] = stateutil.NewRef(1)
@@ -1015,6 +1025,7 @@ func (b *BeaconState) Copy() state.BeaconState {
currentEpochAttestations: b.currentEpochAttestations,
eth1DataVotes: b.eth1DataVotes,
slashings: b.slashings,
proposerLookahead: b.proposerLookahead,
// Large arrays, increases over time.
balances: b.balances,
@@ -1441,6 +1452,8 @@ func (b *BeaconState) rootSelector(ctx context.Context, field types.FieldIndex)
return stateutil.PendingPartialWithdrawalsRoot(b.pendingPartialWithdrawals)
case types.PendingConsolidations:
return stateutil.PendingConsolidationsRoot(b.pendingConsolidations)
case types.ProposerLookahead:
return stateutil.ProposerLookaheadRoot(b.proposerLookahead)
}
return [32]byte{}, errors.New("invalid field index provided")
}

View File

@@ -112,6 +112,8 @@ func (f FieldIndex) String() string {
return "pendingPartialWithdrawals"
case PendingConsolidations:
return "pendingConsolidations"
case ProposerLookahead:
return "proposerLookahead"
default:
return fmt.Sprintf("unknown field index number: %d", f)
}
@@ -195,6 +197,8 @@ func (f FieldIndex) RealPosition() int {
return 35
case PendingConsolidations:
return 36
case ProposerLookahead:
return 37
default:
return -1
}
@@ -259,6 +263,7 @@ const (
PendingDeposits // Electra: EIP-7251
PendingPartialWithdrawals // Electra: EIP-7251
PendingConsolidations // Electra: EIP-7251
ProposerLookahead // Fulu: EIP-7917
)
// Enumerator keeps track of the number of states created since the node's start.

View File

@@ -15,6 +15,7 @@ go_library(
"pending_consolidations_root.go",
"pending_deposits_root.go",
"pending_partial_withdrawals_root.go",
"proposer_lookahead_root.go",
"reference.go",
"sync_committee.root.go",
"trie_helpers.go",
@@ -49,6 +50,7 @@ go_test(
"benchmark_test.go",
"field_root_test.go",
"field_root_validator_test.go",
"proposer_lookahead_root_test.go",
"reference_bench_test.go",
"state_root_test.go",
"trie_helpers_test.go",

View File

@@ -0,0 +1,18 @@
package stateutil
import (
"encoding/binary"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v6/encoding/ssz"
)
// ProposerLookaheadRoot computes the hash tree root of the proposer lookahead
func ProposerLookaheadRoot(lookahead []primitives.ValidatorIndex) ([32]byte, error) {
chunks := make([][32]byte, (len(lookahead)*8+31)/32)
for i, idx := range lookahead {
j := i / 4
binary.LittleEndian.PutUint64(chunks[j][(i%4)*8:], uint64(idx))
}
return ssz.MerkleizeVector(chunks, uint64(len(chunks))), nil
}

View File

@@ -0,0 +1,17 @@
package stateutil_test
import (
"testing"
"github.com/OffchainLabs/prysm/v6/beacon-chain/state/stateutil"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v6/testing/require"
)
func TestProposerLookaheadRoot(t *testing.T) {
lookahead := make([]primitives.ValidatorIndex, 64)
root, err := stateutil.ProposerLookaheadRoot(lookahead)
require.NoError(t, err)
expected := [32]byte{83, 109, 152, 131, 127, 45, 209, 101, 165, 93, 94, 234, 233, 20, 133, 149, 68, 114, 213, 111, 36, 109, 242, 86, 191, 60, 174, 25, 53, 42, 18, 60}
require.Equal(t, expected, root)
}

View File

@@ -128,7 +128,6 @@ go_library(
"//math:go_default_library",
"//monitoring/tracing:go_default_library",
"//monitoring/tracing/trace:go_default_library",
"//network/forks:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/attestation:go_default_library",
"//proto/prysm/v1alpha1/metadata:go_default_library",
@@ -267,7 +266,6 @@ go_test(
"//crypto/rand:go_default_library",
"//encoding/bytesutil:go_default_library",
"//encoding/ssz/equality:go_default_library",
"//network/forks:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/attestation:go_default_library",

View File

@@ -35,7 +35,6 @@ go_library(
"//consensus-types/primitives:go_default_library",
"//crypto/bls:go_default_library",
"//encoding/bytesutil:go_default_library",
"//network/forks:go_default_library",
"//proto/dbval:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//runtime:go_default_library",
@@ -80,7 +79,6 @@ go_test(
"//consensus-types/primitives:go_default_library",
"//crypto/bls:go_default_library",
"//encoding/bytesutil:go_default_library",
"//network/forks:go_default_library",
"//proto/dbval:go_default_library",
"//runtime/interop:go_default_library",
"//testing/require:go_default_library",

View File

@@ -9,7 +9,6 @@ import (
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v6/crypto/bls"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v6/network/forks"
"github.com/OffchainLabs/prysm/v6/runtime/version"
"github.com/OffchainLabs/prysm/v6/time/slots"
"github.com/pkg/errors"
@@ -107,8 +106,7 @@ func (vr verifier) blockSignatureBatch(b blocks.ROBlock) (*bls.SignatureBatch, e
}
func newBackfillVerifier(vr []byte, keys [][fieldparams.BLSPubkeyLength]byte) (*verifier, error) {
dc, err := newDomainCache(vr, params.BeaconConfig().DomainBeaconProposer,
forks.NewOrderedSchedule(params.BeaconConfig()))
dc, err := newDomainCache(vr, params.BeaconConfig().DomainBeaconProposer)
if err != nil {
return nil, err
}
@@ -122,33 +120,31 @@ func newBackfillVerifier(vr []byte, keys [][fieldparams.BLSPubkeyLength]byte) (*
// domainCache provides a fast signing domain lookup by epoch.
type domainCache struct {
fsched forks.OrderedSchedule
forkDomains map[[4]byte][]byte
dType [bls.DomainByteLength]byte
}
func newDomainCache(vRoot []byte, dType [bls.DomainByteLength]byte, fsched forks.OrderedSchedule) (*domainCache, error) {
func newDomainCache(vRoot []byte, dType [bls.DomainByteLength]byte) (*domainCache, error) {
dc := &domainCache{
fsched: fsched,
forkDomains: make(map[[4]byte][]byte),
dType: dType,
}
for _, entry := range fsched {
d, err := signing.ComputeDomain(dc.dType, entry.Version[:], vRoot)
for _, entry := range params.SortedForkSchedule() {
d, err := signing.ComputeDomain(dc.dType, entry.ForkVersion[:], vRoot)
if err != nil {
return nil, errors.Wrapf(err, "failed to pre-compute signing domain for fork version=%#x", entry.Version)
return nil, errors.Wrapf(err, "failed to pre-compute signing domain for fork version=%#x", entry.ForkVersion)
}
dc.forkDomains[entry.Version] = d
dc.forkDomains[entry.ForkVersion] = d
}
return dc, nil
}
func (dc *domainCache) forEpoch(e primitives.Epoch) ([]byte, error) {
fork, err := dc.fsched.VersionForEpoch(e)
fork, err := params.Fork(e)
if err != nil {
return nil, err
}
d, ok := dc.forkDomains[fork]
d, ok := dc.forkDomains[[4]byte(fork.CurrentVersion)]
if !ok {
return nil, errors.Wrapf(errUnknownDomain, "fork version=%#x, epoch=%d", fork, e)
}

View File

@@ -12,7 +12,6 @@ import (
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v6/crypto/bls"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v6/network/forks"
"github.com/OffchainLabs/prysm/v6/runtime/interop"
"github.com/OffchainLabs/prysm/v6/testing/require"
"github.com/OffchainLabs/prysm/v6/testing/util"
@@ -30,18 +29,17 @@ func TestDomainCache(t *testing.T) {
}
vRoot, err := hexutil.Decode("0x0011223344556677889900112233445566778899001122334455667788990011")
require.NoError(t, err)
dType := cfg.DomainBeaconProposer
require.NoError(t, err)
require.Equal(t, 32, len(vRoot))
fsched := forks.NewOrderedSchedule(cfg)
dc, err := newDomainCache(vRoot, dType, fsched)
dc, err := newDomainCache(vRoot, dType)
require.NoError(t, err)
require.Equal(t, len(fsched), len(dc.forkDomains))
for i := range fsched {
e := fsched[i].Epoch
ad, err := dc.forEpoch(e)
schedule := params.SortedForkSchedule()
require.Equal(t, len(schedule), len(dc.forkDomains))
for _, entry := range schedule {
ad, err := dc.forEpoch(entry.Epoch)
require.NoError(t, err)
ed, err := signing.ComputeDomain(dType, fsched[i].Version[:], vRoot)
ed, err := signing.ComputeDomain(dType, entry.ForkVersion[:], vRoot)
require.NoError(t, err)
require.DeepEqual(t, ed, ad)
}

View File

@@ -22,7 +22,6 @@ import (
types "github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
leakybucket "github.com/OffchainLabs/prysm/v6/container/leaky-bucket"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v6/network/forks"
enginev1 "github.com/OffchainLabs/prysm/v6/proto/engine/v1"
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v6/testing/require"
@@ -157,11 +156,7 @@ func (r *expectedBlobChunk) requireExpected(t *testing.T, s *Service, stream net
c, err := readContextFromStream(stream)
require.NoError(t, err)
valRoot := s.cfg.chain.GenesisValidatorsRoot()
ctxBytes, err := forks.ForkDigestFromEpoch(slots.ToEpoch(r.sidecar.Slot()), valRoot[:])
require.NoError(t, err)
require.Equal(t, ctxBytes, bytesutil.ToBytes4(c))
require.Equal(t, params.ForkDigest(slots.ToEpoch(r.sidecar.Slot())), bytesutil.ToBytes4(c))
sc := &ethpb.BlobSidecar{}
require.NoError(t, encoding.DecodeWithMaxLength(stream, sc))
@@ -281,7 +276,7 @@ func repositionFutureEpochs(cfg *params.BeaconChainConfig) {
func defaultMockChain(t *testing.T, currentSlot uint64) (*mock.ChainService, *startup.Clock) {
de := params.BeaconConfig().DenebForkEpoch
df, err := forks.Fork(de)
df, err := params.Fork(de)
require.NoError(t, err)
denebBuffer := params.BeaconConfig().MinEpochsForBlobsSidecarsRequest + 1000
ce := de + denebBuffer

View File

@@ -46,7 +46,6 @@ go_test(
"//consensus-types/blocks/testing:go_default_library",
"//consensus-types/primitives:go_default_library",
"//encoding/ssz/detect:go_default_library",
"//network/forks:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//runtime/version:go_default_library",
"//testing/require:go_default_library",

View File

@@ -13,7 +13,6 @@ import (
"github.com/OffchainLabs/prysm/v6/consensus-types/blocks"
blocktest "github.com/OffchainLabs/prysm/v6/consensus-types/blocks/testing"
"github.com/OffchainLabs/prysm/v6/encoding/ssz/detect"
"github.com/OffchainLabs/prysm/v6/network/forks"
"github.com/OffchainLabs/prysm/v6/testing/require"
"github.com/OffchainLabs/prysm/v6/testing/util"
"github.com/OffchainLabs/prysm/v6/time/slots"
@@ -23,6 +22,7 @@ import (
func TestDownloadFinalizedData(t *testing.T) {
ctx := context.Background()
cfg := params.MainnetConfig()
cfg.InitializeForkSchedule()
// avoid the altair zone because genesis tests are easier to set up
epoch := cfg.AltairForkEpoch - 1
@@ -31,7 +31,7 @@ func TestDownloadFinalizedData(t *testing.T) {
require.NoError(t, err)
st, err := util.NewBeaconState()
require.NoError(t, err)
fork, err := forks.ForkForEpochFromConfig(cfg, epoch)
fork := params.ForkFromConfig(cfg, epoch)
require.NoError(t, err)
require.NoError(t, st.SetFork(fork))
require.NoError(t, st.SetSlot(slot))

View File

@@ -17,7 +17,6 @@ import (
blocktest "github.com/OffchainLabs/prysm/v6/consensus-types/blocks/testing"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v6/encoding/ssz/detect"
"github.com/OffchainLabs/prysm/v6/network/forks"
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v6/runtime/version"
"github.com/OffchainLabs/prysm/v6/testing/require"
@@ -84,7 +83,7 @@ func TestDownloadWeakSubjectivityCheckpoint(t *testing.T) {
require.NoError(t, err)
wst, err := util.NewBeaconState()
require.NoError(t, err)
fork, err := forkForEpoch(cfg, epoch)
fork, err := params.Fork(epoch)
require.NoError(t, err)
require.NoError(t, wst.SetFork(fork))
@@ -183,7 +182,7 @@ func TestDownloadBackwardsCompatibleCombined(t *testing.T) {
require.NoError(t, err)
wst, err := util.NewBeaconState()
require.NoError(t, err)
fork, err := forkForEpoch(cfg, cfg.GenesisEpoch)
fork, err := params.Fork(cfg.GenesisEpoch)
require.NoError(t, err)
require.NoError(t, wst.SetFork(fork))
@@ -280,33 +279,11 @@ func TestGetWeakSubjectivityEpochFromHead(t *testing.T) {
require.Equal(t, expectedEpoch, actualEpoch)
}
func forkForEpoch(cfg *params.BeaconChainConfig, epoch primitives.Epoch) (*ethpb.Fork, error) {
os := forks.NewOrderedSchedule(cfg)
currentVersion, err := os.VersionForEpoch(epoch)
if err != nil {
return nil, err
}
prevVersion, err := os.Previous(currentVersion)
if err != nil {
if !errors.Is(err, forks.ErrNoPreviousVersion) {
return nil, err
}
// use same version for both in the case of genesis
prevVersion = currentVersion
}
forkEpoch := cfg.ForkVersionSchedule[currentVersion]
return &ethpb.Fork{
PreviousVersion: prevVersion[:],
CurrentVersion: currentVersion[:],
Epoch: forkEpoch,
}, nil
}
func defaultTestHeadState(t *testing.T, cfg *params.BeaconChainConfig) (state.BeaconState, primitives.Epoch) {
st, err := util.NewBeaconStateAltair()
require.NoError(t, err)
fork, err := forkForEpoch(cfg, cfg.AltairForkEpoch)
fork, err := params.Fork(cfg.AltairForkEpoch)
require.NoError(t, err)
require.NoError(t, st.SetFork(fork))

View File

@@ -3,7 +3,6 @@ package sync
import (
"io"
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/signing"
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/libp2p/go-libp2p/core/network"
@@ -87,12 +86,8 @@ type ContextByteVersions map[[4]byte]int
// and the runtime/version identifier for the corresponding fork.
func ContextByteVersionsForValRoot(valRoot [32]byte) (ContextByteVersions, error) {
m := make(ContextByteVersions)
for fv, v := range params.ConfigForkVersions(params.BeaconConfig()) {
digest, err := signing.ComputeForkDigest(fv[:], valRoot[:])
if err != nil {
return nil, errors.Wrapf(err, "unable to compute fork digest for fork version %#x", fv)
}
m[digest] = v
for _, entry := range params.SortedNetworkScheduleEntries() {
m[entry.ForkDigest] = entry.VersionEnum
}
return m, nil
}

View File

@@ -6,7 +6,6 @@ import (
"strings"
"github.com/OffchainLabs/prysm/v6/beacon-chain/blockchain"
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/signing"
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p"
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/types"
"github.com/OffchainLabs/prysm/v6/beacon-chain/startup"
@@ -112,22 +111,14 @@ func extractDataTypeFromTypeMap[T any](typeMap map[[4]byte]func() (T, error), di
if len(digest) != forkDigestLength {
return zero, errors.Errorf("invalid digest returned, wanted a length of %d but received %d", forkDigestLength, len(digest))
}
vRoot := tor.GenesisValidatorsRoot()
for k, f := range typeMap {
rDigest, err := signing.ComputeForkDigest(k[:], vRoot[:])
if err != nil {
return zero, err
}
if rDigest == bytesutil.ToBytes4(digest) {
return f()
}
forkVersion, _, err := params.ForkDataFromDigest([4]byte(digest))
if err != nil {
return zero, errors.Wrapf(ErrNoValidDigest, "could not extract %T data type, saw digest=%#x", zero, digest)
}
return zero, errors.Wrapf(
ErrNoValidDigest,
"could not extract %T data type, saw digest=%#x, genesis=%v, vr=%#x",
zero,
digest,
tor.GenesisTime(),
tor.GenesisValidatorsRoot(),
)
f, ok := typeMap[forkVersion]
if ok {
return f()
}
return zero, errors.Wrapf(ErrNoValidDigest, "could not extract %T data type, saw digest=%#x", zero, digest)
}

View File

@@ -4,7 +4,6 @@ import (
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v6/network/forks"
"github.com/OffchainLabs/prysm/v6/time/slots"
"github.com/libp2p/go-libp2p/core/protocol"
"github.com/pkg/errors"
@@ -42,54 +41,41 @@ func (s *Service) forkWatcher() {
// registerForUpcomingFork registers appropriate gossip and RPC topic if there is a fork in the next epoch.
func (s *Service) registerForUpcomingFork(currentEpoch primitives.Epoch) error {
// Get the genesis validators root.
genesisValidatorsRoot := s.cfg.clock.GenesisValidatorsRoot()
// Check if there is a fork in the next epoch.
isForkNextEpoch, err := forks.IsForkNextEpoch(s.cfg.clock.GenesisTime(), genesisValidatorsRoot[:])
if err != nil {
return errors.Wrap(err, "Could not retrieve next fork epoch")
}
isForkNextEpoch := params.IsForkNextEpoch(currentEpoch)
// Exit early if there is no fork in the next epoch.
if !isForkNextEpoch {
return nil
}
beforeForkEpoch := currentEpoch
forkEpoch := beforeForkEpoch + 1
// Get the fork afterForkDigest for the next epoch.
afterForkDigest, err := forks.ForkDigestFromEpoch(forkEpoch, genesisValidatorsRoot[:])
if err != nil {
return errors.Wrap(err, "could not retrieve fork digest")
}
nextForkEpoch := currentEpoch + 1
nextForkDigest := params.ForkDigest(nextForkEpoch)
// Exit early if the topics for the next epoch are already registered.
// It likely to be the case for all slots of the epoch that are not the first one.
if s.subHandler.digestExists(afterForkDigest) {
if s.subHandler.digestExists(nextForkDigest) {
return nil
}
// Register the subscribers (gossipsub) for the next epoch.
s.registerSubscribers(forkEpoch, afterForkDigest)
s.registerSubscribers(nextForkEpoch, nextForkDigest)
// Get the handlers for the current and next fork.
beforeForkHandlerByTopic, err := s.rpcHandlerByTopicFromEpoch(beforeForkEpoch)
currentHandler, err := s.rpcHandlerByTopicFromEpoch(currentEpoch)
if err != nil {
return errors.Wrap(err, "RPC handler by topic from before fork epoch")
}
forkHandlerByTopic, err := s.rpcHandlerByTopicFromEpoch(forkEpoch)
nextHandler, err := s.rpcHandlerByTopicFromEpoch(nextForkEpoch)
if err != nil {
return errors.Wrap(err, "RPC handler by topic from fork epoch")
}
// Compute newly added topics.
newRPCHandlerByTopic := addedRPCHandlerByTopic(beforeForkHandlerByTopic, forkHandlerByTopic)
newHandlersByTopic := addedRPCHandlerByTopic(currentHandler, nextHandler)
// Register the new RPC handlers.
for topic, handler := range newRPCHandlerByTopic {
for topic, handler := range newHandlersByTopic {
s.registerRPC(topic, handler)
}
@@ -98,11 +84,8 @@ func (s *Service) registerForUpcomingFork(currentEpoch primitives.Epoch) error {
// deregisterFromPastFork deregisters appropriate gossip and RPC topic if there is a fork in the current epoch.
func (s *Service) deregisterFromPastFork(currentEpoch primitives.Epoch) error {
// Extract the genesis validators root.
genesisValidatorsRoot := s.cfg.clock.GenesisValidatorsRoot()
// Get the fork.
currentFork, err := forks.Fork(currentEpoch)
currentFork, err := params.Fork(currentEpoch)
if err != nil {
return errors.Wrap(err, "genesis validators root")
}
@@ -123,10 +106,7 @@ func (s *Service) deregisterFromPastFork(currentEpoch primitives.Epoch) error {
// Look at the previous fork's digest.
beforeForkEpoch := currentFork.Epoch - 1
beforeForkDigest, err := forks.ForkDigestFromEpoch(beforeForkEpoch, genesisValidatorsRoot[:])
if err != nil {
return errors.Wrap(err, "fork digest from epoch")
}
beforeForkDigest := params.ForkDigest(beforeForkEpoch)
// Exit early if there are no topics with that particular digest.
if !s.subHandler.digestExists(beforeForkDigest) {

View File

@@ -14,7 +14,6 @@ import (
mockSync "github.com/OffchainLabs/prysm/v6/beacon-chain/sync/initial-sync/testing"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v6/network/forks"
"github.com/OffchainLabs/prysm/v6/runtime/version"
"github.com/OffchainLabs/prysm/v6/testing/assert"
)
@@ -93,9 +92,7 @@ func TestService_CheckForNextEpochFork(t *testing.T) {
currEpoch: 4,
wantErr: false,
postSvcCheck: func(t *testing.T, s *Service) {
genRoot := s.cfg.clock.GenesisValidatorsRoot()
digest, err := forks.ForkDigestFromEpoch(5, genRoot[:])
assert.NoError(t, err)
digest := params.ForkDigest(5)
assert.Equal(t, true, s.subHandler.digestExists(digest))
rpcMap := make(map[string]bool)
for _, p := range s.cfg.p2p.Host().Mux().Protocols() {
@@ -138,9 +135,7 @@ func TestService_CheckForNextEpochFork(t *testing.T) {
currEpoch: 4,
wantErr: false,
postSvcCheck: func(t *testing.T, s *Service) {
genRoot := s.cfg.clock.GenesisValidatorsRoot()
digest, err := forks.ForkDigestFromEpoch(5, genRoot[:])
assert.NoError(t, err)
digest := params.ForkDigest(5)
assert.Equal(t, true, s.subHandler.digestExists(digest))
rpcMap := make(map[string]bool)
for _, p := range s.cfg.p2p.Host().Mux().Protocols() {
@@ -181,9 +176,7 @@ func TestService_CheckForNextEpochFork(t *testing.T) {
currEpoch: 4,
wantErr: false,
postSvcCheck: func(t *testing.T, s *Service) {
genRoot := s.cfg.clock.GenesisValidatorsRoot()
digest, err := forks.ForkDigestFromEpoch(5, genRoot[:])
assert.NoError(t, err)
digest := params.ForkDigest(5)
assert.Equal(t, true, s.subHandler.digestExists(digest))
rpcMap := make(map[string]bool)
for _, p := range s.cfg.p2p.Host().Mux().Protocols() {
@@ -226,9 +219,7 @@ func TestService_CheckForNextEpochFork(t *testing.T) {
currEpoch: 4,
wantErr: false,
postSvcCheck: func(t *testing.T, s *Service) {
genRoot := s.cfg.clock.GenesisValidatorsRoot()
digest, err := forks.ForkDigestFromEpoch(5, genRoot[:])
assert.NoError(t, err)
digest := params.ForkDigest(5)
assert.Equal(t, true, s.subHandler.digestExists(digest))
rpcMap := make(map[string]bool)
for _, p := range s.cfg.p2p.Host().Mux().Protocols() {
@@ -271,9 +262,7 @@ func TestService_CheckForNextEpochFork(t *testing.T) {
currEpoch: 4,
wantErr: false,
postSvcCheck: func(t *testing.T, s *Service) {
genRoot := s.cfg.clock.GenesisValidatorsRoot()
digest, err := forks.ForkDigestFromEpoch(5, genRoot[:])
assert.NoError(t, err)
digest := params.ForkDigest(5)
assert.Equal(t, true, s.subHandler.digestExists(digest))
rpcMap := make(map[string]bool)
for _, p := range s.cfg.p2p.Host().Mux().Protocols() {
@@ -392,14 +381,12 @@ func TestService_CheckForPreviousEpochFork(t *testing.T) {
r.registerRPC(topic, handler)
}
genRoot := r.cfg.clock.GenesisValidatorsRoot()
digest, err := forks.ForkDigestFromEpoch(0, genRoot[:])
digest := params.ForkDigest(0)
assert.NoError(t, err)
r.registerSubscribers(0, digest)
assert.Equal(t, true, r.subHandler.digestExists(digest))
digest, err = forks.ForkDigestFromEpoch(3, genRoot[:])
assert.NoError(t, err)
digest = params.ForkDigest(3)
r.registerSubscribers(3, digest)
assert.Equal(t, true, r.subHandler.digestExists(digest))
@@ -408,12 +395,9 @@ func TestService_CheckForPreviousEpochFork(t *testing.T) {
currEpoch: 4,
wantErr: false,
postSvcCheck: func(t *testing.T, s *Service) {
genRoot := s.cfg.clock.GenesisValidatorsRoot()
digest, err := forks.ForkDigestFromEpoch(0, genRoot[:])
assert.NoError(t, err)
digest := params.ForkDigest(0)
assert.Equal(t, false, s.subHandler.digestExists(digest))
digest, err = forks.ForkDigestFromEpoch(3, genRoot[:])
assert.NoError(t, err)
digest = params.ForkDigest(3)
assert.Equal(t, true, s.subHandler.digestExists(digest))
ptcls := s.cfg.p2p.Host().Mux().Protocols()
@@ -460,14 +444,11 @@ func TestService_CheckForPreviousEpochFork(t *testing.T) {
chainStarted: abool.New(),
subHandler: newSubTopicHandler(),
}
genRoot := r.cfg.clock.GenesisValidatorsRoot()
digest, err := forks.ForkDigestFromEpoch(1, genRoot[:])
assert.NoError(t, err)
digest := params.ForkDigest(1)
r.registerSubscribers(1, digest)
assert.Equal(t, true, r.subHandler.digestExists(digest))
digest, err = forks.ForkDigestFromEpoch(3, genRoot[:])
assert.NoError(t, err)
digest = params.ForkDigest(3)
r.registerSubscribers(3, digest)
assert.Equal(t, true, r.subHandler.digestExists(digest))
@@ -476,12 +457,9 @@ func TestService_CheckForPreviousEpochFork(t *testing.T) {
currEpoch: 4,
wantErr: false,
postSvcCheck: func(t *testing.T, s *Service) {
genRoot := s.cfg.clock.GenesisValidatorsRoot()
digest, err := forks.ForkDigestFromEpoch(1, genRoot[:])
assert.NoError(t, err)
digest := params.ForkDigest(1)
assert.Equal(t, false, s.subHandler.digestExists(digest))
digest, err = forks.ForkDigestFromEpoch(3, genRoot[:])
assert.NoError(t, err)
digest = params.ForkDigest(3)
assert.Equal(t, true, s.subHandler.digestExists(digest))
},
},

View File

@@ -8,9 +8,7 @@ import (
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/consensus-types/blocks"
"github.com/OffchainLabs/prysm/v6/consensus-types/interfaces"
"github.com/OffchainLabs/prysm/v6/network/forks"
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v6/runtime/version"
"github.com/OffchainLabs/prysm/v6/time/slots"
libp2pcore "github.com/libp2p/go-libp2p/core"
"github.com/pkg/errors"
@@ -30,57 +28,9 @@ func WriteBlockChunk(stream libp2pcore.Stream, tor blockchain.TemporalOracle, en
if _, err := stream.Write([]byte{responseCodeSuccess}); err != nil {
return err
}
var obtainedCtx []byte
valRoot := tor.GenesisValidatorsRoot()
switch blk.Version() {
case version.Phase0:
digest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().GenesisEpoch, valRoot[:])
if err != nil {
return err
}
obtainedCtx = digest[:]
case version.Altair:
digest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().AltairForkEpoch, valRoot[:])
if err != nil {
return err
}
obtainedCtx = digest[:]
case version.Bellatrix:
digest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().BellatrixForkEpoch, valRoot[:])
if err != nil {
return err
}
obtainedCtx = digest[:]
case version.Capella:
digest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().CapellaForkEpoch, valRoot[:])
if err != nil {
return err
}
obtainedCtx = digest[:]
case version.Deneb:
digest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().DenebForkEpoch, valRoot[:])
if err != nil {
return err
}
obtainedCtx = digest[:]
case version.Electra:
digest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().ElectraForkEpoch, valRoot[:])
if err != nil {
return err
}
obtainedCtx = digest[:]
case version.Fulu:
digest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().FuluForkEpoch, valRoot[:])
if err != nil {
return err
}
obtainedCtx = digest[:]
default:
return errors.Wrapf(ErrUnrecognizedVersion, "block version %d is not recognized", blk.Version())
}
if err := writeContextToStream(obtainedCtx, stream); err != nil {
digest := params.ForkDigest(slots.ToEpoch(blk.Block().Slot()))
if err := writeContextToStream(digest[:], stream); err != nil {
return err
}
_, err := encoding.EncodeWithMaxLength(stream, blk)
@@ -150,16 +100,11 @@ func WriteBlobSidecarChunk(stream libp2pcore.Stream, tor blockchain.TemporalOrac
if _, err := stream.Write([]byte{responseCodeSuccess}); err != nil {
return err
}
valRoot := tor.GenesisValidatorsRoot()
ctxBytes, err := forks.ForkDigestFromEpoch(slots.ToEpoch(sidecar.Slot()), valRoot[:])
if err != nil {
return err
}
ctxBytes := params.ForkDigest(slots.ToEpoch(sidecar.Slot()))
if err := writeContextToStream(ctxBytes[:], stream); err != nil {
return err
}
_, err = encoding.EncodeWithMaxLength(stream, sidecar)
_, err := encoding.EncodeWithMaxLength(stream, sidecar)
return err
}
@@ -168,18 +113,12 @@ func WriteLightClientBootstrapChunk(stream libp2pcore.Stream, tor blockchain.Tem
return err
}
valRoot := tor.GenesisValidatorsRoot()
digest, err := forks.ForkDigestFromEpoch(slots.ToEpoch(bootstrap.Header().Beacon().Slot), valRoot[:])
if err != nil {
digest := params.ForkDigest(slots.ToEpoch(bootstrap.Header().Beacon().Slot))
if err := writeContextToStream(digest[:], stream); err != nil {
return err
}
obtainedCtx := digest[:]
if err = writeContextToStream(obtainedCtx, stream); err != nil {
return err
}
_, err = encoding.EncodeWithMaxLength(stream, bootstrap)
_, err := encoding.EncodeWithMaxLength(stream, bootstrap)
return err
}
@@ -188,17 +127,11 @@ func WriteLightClientUpdateChunk(stream libp2pcore.Stream, tor blockchain.Tempor
return err
}
valRoot := tor.GenesisValidatorsRoot()
digest, err := forks.ForkDigestFromEpoch(slots.ToEpoch(update.AttestedHeader().Beacon().Slot), valRoot[:])
if err != nil {
digest := params.ForkDigest(slots.ToEpoch(update.AttestedHeader().Beacon().Slot))
if err := writeContextToStream(digest[:], stream); err != nil {
return err
}
obtainedCtx := digest[:]
if err = writeContextToStream(obtainedCtx, stream); err != nil {
return err
}
_, err = encoding.EncodeWithMaxLength(stream, update)
_, err := encoding.EncodeWithMaxLength(stream, update)
return err
}
@@ -207,17 +140,12 @@ func WriteLightClientOptimisticUpdateChunk(stream libp2pcore.Stream, tor blockch
return err
}
valRoot := tor.GenesisValidatorsRoot()
digest, err := forks.ForkDigestFromEpoch(slots.ToEpoch(update.AttestedHeader().Beacon().Slot), valRoot[:])
if err != nil {
return err
}
obtainedCtx := digest[:]
digest := params.ForkDigest(slots.ToEpoch(update.AttestedHeader().Beacon().Slot))
if err = writeContextToStream(obtainedCtx, stream); err != nil {
if err := writeContextToStream(digest[:], stream); err != nil {
return err
}
_, err = encoding.EncodeWithMaxLength(stream, update)
_, err := encoding.EncodeWithMaxLength(stream, update)
return err
}
@@ -226,17 +154,12 @@ func WriteLightClientFinalityUpdateChunk(stream libp2pcore.Stream, tor blockchai
return err
}
valRoot := tor.GenesisValidatorsRoot()
digest, err := forks.ForkDigestFromEpoch(slots.ToEpoch(update.AttestedHeader().Beacon().Slot), valRoot[:])
if err != nil {
return err
}
obtainedCtx := digest[:]
digest := params.ForkDigest(slots.ToEpoch(update.AttestedHeader().Beacon().Slot))
if err = writeContextToStream(obtainedCtx, stream); err != nil {
if err := writeContextToStream(digest[:], stream); err != nil {
return err
}
_, err = encoding.EncodeWithMaxLength(stream, update)
_, err := encoding.EncodeWithMaxLength(stream, update)
return err
}
@@ -246,15 +169,10 @@ func WriteDataColumnSidecarChunk(stream libp2pcore.Stream, tor blockchain.Tempor
if _, err := stream.Write([]byte{responseCodeSuccess}); err != nil {
return err
}
valRoot := tor.GenesisValidatorsRoot()
ctxBytes, err := forks.ForkDigestFromEpoch(slots.ToEpoch(sidecar.SignedBlockHeader.Header.Slot), valRoot[:])
if err != nil {
return err
}
ctxBytes := params.ForkDigestFromEpoch(slots.ToEpoch(sidecar.SignedBlockHeader.Header.Slot))
if err := writeContextToStream(ctxBytes[:], stream); err != nil {
return err
}
_, err = encoding.EncodeWithMaxLength(stream, sidecar)
_, err := encoding.EncodeWithMaxLength(stream, sidecar)
return err
}

View File

@@ -17,7 +17,6 @@ import (
"github.com/OffchainLabs/prysm/v6/config/features"
"github.com/OffchainLabs/prysm/v6/config/params"
leakybucket "github.com/OffchainLabs/prysm/v6/container/leaky-bucket"
"github.com/OffchainLabs/prysm/v6/network/forks"
pb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v6/runtime/version"
"github.com/OffchainLabs/prysm/v6/testing/require"
@@ -63,17 +62,11 @@ func TestRPC_LightClientBootstrap(t *testing.T) {
topic := string(pcl)
r.rateLimiter.limiterMap[topic] = leakybucket.NewCollector(10000, 10000, time.Second, false)
altairDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().AltairForkEpoch, chainService.ValidatorsRoot[:])
require.NoError(t, err)
bellatrixDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().BellatrixForkEpoch, chainService.ValidatorsRoot[:])
require.NoError(t, err)
capellaDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().CapellaForkEpoch, chainService.ValidatorsRoot[:])
require.NoError(t, err)
denebDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().DenebForkEpoch, chainService.ValidatorsRoot[:])
require.NoError(t, err)
electraDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().ElectraForkEpoch, chainService.ValidatorsRoot[:])
require.NoError(t, err)
altairDigest := params.ForkDigest(params.BeaconConfig().AltairForkEpoch)
bellatrixDigest := params.ForkDigest(params.BeaconConfig().BellatrixForkEpoch)
capellaDigest := params.ForkDigest(params.BeaconConfig().CapellaForkEpoch)
denebDigest := params.ForkDigest(params.BeaconConfig().DenebForkEpoch)
electraDigest := params.ForkDigest(params.BeaconConfig().ElectraForkEpoch)
for i := 1; i <= 5; i++ {
t.Run(version.String(i), func(t *testing.T) {
l := util.NewTestLightClient(t, i)
@@ -185,16 +178,11 @@ func TestRPC_LightClientOptimisticUpdate(t *testing.T) {
topic := string(pcl)
r.rateLimiter.limiterMap[topic] = leakybucket.NewCollector(10000, 10000, time.Second, false)
altairDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().AltairForkEpoch, chainService.ValidatorsRoot[:])
require.NoError(t, err)
bellatrixDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().BellatrixForkEpoch, chainService.ValidatorsRoot[:])
require.NoError(t, err)
capellaDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().CapellaForkEpoch, chainService.ValidatorsRoot[:])
require.NoError(t, err)
denebDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().DenebForkEpoch, chainService.ValidatorsRoot[:])
require.NoError(t, err)
electraDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().ElectraForkEpoch, chainService.ValidatorsRoot[:])
require.NoError(t, err)
altairDigest := params.ForkDigest(params.BeaconConfig().AltairForkEpoch)
bellatrixDigest := params.ForkDigest(params.BeaconConfig().BellatrixForkEpoch)
capellaDigest := params.ForkDigest(params.BeaconConfig().CapellaForkEpoch)
denebDigest := params.ForkDigest(params.BeaconConfig().DenebForkEpoch)
electraDigest := params.ForkDigest(params.BeaconConfig().ElectraForkEpoch)
for i := 1; i <= 5; i++ {
t.Run(version.String(i), func(t *testing.T) {
@@ -305,16 +293,11 @@ func TestRPC_LightClientFinalityUpdate(t *testing.T) {
topic := string(pcl)
r.rateLimiter.limiterMap[topic] = leakybucket.NewCollector(10000, 10000, time.Second, false)
altairDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().AltairForkEpoch, chainService.ValidatorsRoot[:])
require.NoError(t, err)
bellatrixDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().BellatrixForkEpoch, chainService.ValidatorsRoot[:])
require.NoError(t, err)
capellaDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().CapellaForkEpoch, chainService.ValidatorsRoot[:])
require.NoError(t, err)
denebDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().DenebForkEpoch, chainService.ValidatorsRoot[:])
require.NoError(t, err)
electraDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().ElectraForkEpoch, chainService.ValidatorsRoot[:])
require.NoError(t, err)
altairDigest := params.ForkDigest(params.BeaconConfig().AltairForkEpoch)
bellatrixDigest := params.ForkDigest(params.BeaconConfig().BellatrixForkEpoch)
capellaDigest := params.ForkDigest(params.BeaconConfig().CapellaForkEpoch)
denebDigest := params.ForkDigest(params.BeaconConfig().DenebForkEpoch)
electraDigest := params.ForkDigest(params.BeaconConfig().ElectraForkEpoch)
for i := 1; i <= 5; i++ {
t.Run(version.String(i), func(t *testing.T) {
@@ -425,16 +408,11 @@ func TestRPC_LightClientUpdatesByRange(t *testing.T) {
topic := string(pcl)
r.rateLimiter.limiterMap[topic] = leakybucket.NewCollector(10000, 10000, time.Second, false)
altairDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().AltairForkEpoch, chainService.ValidatorsRoot[:])
require.NoError(t, err)
bellatrixDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().BellatrixForkEpoch, chainService.ValidatorsRoot[:])
require.NoError(t, err)
capellaDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().CapellaForkEpoch, chainService.ValidatorsRoot[:])
require.NoError(t, err)
denebDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().DenebForkEpoch, chainService.ValidatorsRoot[:])
require.NoError(t, err)
electraDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().ElectraForkEpoch, chainService.ValidatorsRoot[:])
require.NoError(t, err)
altairDigest := params.ForkDigest(params.BeaconConfig().AltairForkEpoch)
bellatrixDigest := params.ForkDigest(params.BeaconConfig().BellatrixForkEpoch)
capellaDigest := params.ForkDigest(params.BeaconConfig().CapellaForkEpoch)
denebDigest := params.ForkDigest(params.BeaconConfig().DenebForkEpoch)
electraDigest := params.ForkDigest(params.BeaconConfig().ElectraForkEpoch)
for i := 1; i <= 5; i++ {
t.Run(version.String(i), func(t *testing.T) {

View File

@@ -5,8 +5,8 @@ import (
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p"
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/types"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/consensus-types/wrapper"
"github.com/OffchainLabs/prysm/v6/network/forks"
pb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1/metadata"
"github.com/OffchainLabs/prysm/v6/runtime/version"
@@ -168,17 +168,9 @@ func (s *Service) sendMetaDataRequest(ctx context.Context, peerID peer.ID) (meta
return nil, errors.New(errMsg)
}
// Get the genesis validators root.
valRoot := s.cfg.clock.GenesisValidatorsRoot()
// Get the fork digest from the current epoch and the genesis validators root.
rpcCtx, err := forks.ForkDigestFromEpoch(currentEpoch, valRoot[:])
if err != nil {
return nil, errors.Wrap(err, "fork digest from epoch")
}
digest := params.ForkDigestFromEpoch(currentEpoch)
// Instantiate zero value of the metadata.
msg, err := extractDataTypeFromTypeMap(types.MetaDataMap, rpcCtx[:], s.cfg.clock)
msg, err := extractDataTypeFromTypeMap(types.MetaDataMap, digest[:], s.cfg.clock)
if err != nil {
return nil, errors.Wrap(err, "extract data type from type map")
}

View File

@@ -15,15 +15,14 @@ import (
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/peerdas"
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p"
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/peers"
"github.com/OffchainLabs/prysm/v6/beacon-chain/startup"
"github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/flags"
"github.com/OffchainLabs/prysm/v6/config/features"
fieldparams "github.com/OffchainLabs/prysm/v6/config/fieldparams"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v6/container/slice"
"github.com/OffchainLabs/prysm/v6/monitoring/tracing"
"github.com/OffchainLabs/prysm/v6/monitoring/tracing/trace"
"github.com/OffchainLabs/prysm/v6/network/forks"
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v6/runtime/messagehandler"
"github.com/OffchainLabs/prysm/v6/time/slots"
@@ -206,8 +205,7 @@ func (s *Service) registerSubscribers(epoch primitives.Epoch, digest [4]byte) {
// subscribe to a given topic with a given validator and subscription handler.
// The base protobuf message is used to initialize new messages for decoding.
func (s *Service) subscribe(topic string, validator wrappedVal, handle subHandler, digest [4]byte) *pubsub.Subscription {
genRoot := s.cfg.clock.GenesisValidatorsRoot()
_, e, err := forks.RetrieveForkDataFromDigest(digest, genRoot[:])
_, e, err := params.ForkDataFromDigest(digest)
if err != nil {
// Impossible condition as it would mean digest does not exist.
panic(err) // lint:nopanic -- Impossible condition.
@@ -441,10 +439,8 @@ func (s *Service) searchForPeers(
func (s *Service) subscribeToSubnets(
topicFormat string,
digest [4]byte,
genesisValidatorsRoot [fieldparams.RootLength]byte,
genesisTime time.Time,
clock *startup.Clock,
subscriptions map[uint64]*pubsub.Subscription,
currentSlot primitives.Slot,
validate wrappedVal,
handle subHandler,
getSubnetsToSubscribe func(currentSlot primitives.Slot) []uint64,
@@ -455,7 +451,7 @@ func (s *Service) subscribeToSubnets(
}
// Check the validity of the digest.
valid, err := isDigestValid(digest, genesisTime, genesisValidatorsRoot)
valid, err := isDigestValid(digest, clock)
if err != nil {
log.Error(err)
return true
@@ -482,7 +478,7 @@ func (s *Service) subscribeToSubnets(
}
// Retrieve the subnets we want to subscribe to.
subnetsToSubscribeIndex := getSubnetsToSubscribe(currentSlot)
subnetsToSubscribeIndex := getSubnetsToSubscribe(clock.CurrentSlot())
// Remove subscriptions that are no longer wanted.
s.pruneSubscriptions(subscriptions, subnetsToSubscribeIndex, topicFormat, digest)
@@ -517,11 +513,8 @@ func (s *Service) subscribeWithParameters(
// Initialize the subscriptions map.
subscriptions := make(map[uint64]*pubsub.Subscription)
// Retrieve the genesis validators root.
genesisValidatorsRoot := s.cfg.clock.GenesisValidatorsRoot()
// Retrieve the epoch of the fork corresponding to the digest.
_, epoch, err := forks.RetrieveForkDataFromDigest(digest, genesisValidatorsRoot[:])
_, epoch, err := params.ForkDataFromDigest(digest)
if err != nil {
panic(err) // lint:nopanic -- Impossible condition.
}
@@ -540,7 +533,9 @@ func (s *Service) subscribeWithParameters(
secondsPerSlotDuration := time.Duration(secondsPerSlot) * time.Second
currentSlot := s.cfg.clock.CurrentSlot()
s.subscribeToSubnets(topicFormat, digest, genesisValidatorsRoot, genesisTime, subscriptions, currentSlot, validate, handle, getSubnetsToSubscribe)
// Subscribe to subnets.
s.subscribeToSubnets(topicFormat, digest, s.cfg.clock, subscriptions, validate, handle, getSubnetsToSubscribe)
logCtx, cancel := context.WithCancel(s.ctx)
@@ -563,7 +558,7 @@ func (s *Service) subscribeWithParameters(
for {
select {
case currentSlot := <-slotTicker.C():
isDigestValid := s.subscribeToSubnets(topicFormat, digest, genesisValidatorsRoot, genesisTime, subscriptions, currentSlot, validate, handle, getSubnetsToSubscribe)
isDigestValid := s.subscribeToSubnets(topicFormat, digest, s.cfg.clock, subscriptions, validate, handle, getSubnetsToSubscribe)
// Stop the ticker if the digest is not valid. Likely to happen after a hard fork.
if !isDigestValid {
@@ -722,27 +717,19 @@ func (*Service) addDigestAndIndexToTopic(topic string, digest [4]byte, idx uint6
}
func (s *Service) currentForkDigest() ([4]byte, error) {
genRoot := s.cfg.clock.GenesisValidatorsRoot()
return forks.CreateForkDigest(s.cfg.clock.GenesisTime(), genRoot[:])
return params.ForkDigest(s.cfg.clock.CurrentEpoch()), nil
}
// Checks if the provided digest matches up with the current supposed digest.
func isDigestValid(digest [4]byte, genesis time.Time, genValRoot [32]byte) (bool, error) {
retDigest, err := forks.CreateForkDigest(genesis, genValRoot[:])
if err != nil {
return false, err
}
isNextEpoch, err := forks.IsForkNextEpoch(genesis, genValRoot[:])
if err != nil {
return false, err
}
func isDigestValid(digest [4]byte, clock *startup.Clock) (bool, error) {
currentEpoch := clock.CurrentEpoch()
// In the event there is a fork the next epoch,
// we skip the check, as we subscribe subnets an
// epoch in advance.
if isNextEpoch {
if params.IsForkNextEpoch(currentEpoch) {
return true, nil
}
return retDigest == digest, nil
return params.ForkDigest(currentEpoch) == digest, nil
}
func computeSubnetsToFindPeersIndex(

View File

@@ -26,7 +26,6 @@ import (
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v6/network/forks"
pb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v6/runtime/version"
"github.com/OffchainLabs/prysm/v6/testing/assert"
@@ -319,8 +318,8 @@ func Test_wrapAndReportValidation(t *testing.T) {
Genesis: time.Now(),
ValidatorsRoot: [32]byte{0x01},
}
fd, err := forks.CreateForkDigest(mChain.GenesisTime(), mChain.ValidatorsRoot[:])
assert.NoError(t, err)
clock := startup.NewClock(mChain.Genesis, mChain.ValidatorsRoot)
fd := params.ForkDigest(clock.CurrentEpoch())
mockTopic := fmt.Sprintf(p2p.BlockSubnetTopicFormat, fd) + encoder.SszNetworkEncoder{}.ProtocolSuffix()
type args struct {
topic string
@@ -610,17 +609,18 @@ func TestSubscribeWithSyncSubnets_DynamicSwitchFork(t *testing.T) {
}
func TestIsDigestValid(t *testing.T) {
clock := startup.NewClock(time.Now().Add(-100*time.Second), [32]byte{'A'})
genRoot := [32]byte{'A'}
digest, err := signing.ComputeForkDigest(params.BeaconConfig().GenesisForkVersion, genRoot[:])
assert.NoError(t, err)
valid, err := isDigestValid(digest, time.Now().Add(-100*time.Second), genRoot)
valid, err := isDigestValid(digest, clock)
assert.NoError(t, err)
assert.Equal(t, true, valid)
// Compute future fork digest that will be invalid currently.
digest, err = signing.ComputeForkDigest(params.BeaconConfig().AltairForkVersion, genRoot[:])
assert.NoError(t, err)
valid, err = isDigestValid(digest, time.Now().Add(-100*time.Second), genRoot)
valid, err = isDigestValid(digest, clock)
assert.NoError(t, err)
assert.Equal(t, false, valid)
}

View File

@@ -7,7 +7,8 @@ import (
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p"
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/encoder"
"github.com/OffchainLabs/prysm/v6/network/forks"
"github.com/OffchainLabs/prysm/v6/beacon-chain/startup"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/testing/assert"
pubsub "github.com/libp2p/go-libp2p-pubsub"
)
@@ -18,8 +19,8 @@ func TestSubTopicHandler_CRUD(t *testing.T) {
assert.Equal(t, false, h.topicExists("junk"))
assert.Equal(t, false, h.digestExists([4]byte{}))
digest, err := forks.CreateForkDigest(time.Now(), make([]byte, 32))
assert.NoError(t, err)
clock := startup.NewClock(time.Now(), [32]byte{})
digest := params.ForkDigest(clock.CurrentEpoch())
enc := encoder.SszNetworkEncoder{}
// Valid topic added in.

View File

@@ -22,7 +22,6 @@ import (
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v6/network/forks"
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v6/testing/assert"
"github.com/OffchainLabs/prysm/v6/testing/require"
@@ -224,8 +223,7 @@ func TestService_ValidateSyncCommitteeMessage(t *testing.T) {
gt := time.Now().Add(-time.Second * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Duration(slots.PrevSlot(hState.Slot())))
vr := [32]byte{'A'}
clock := startup.NewClock(gt, vr)
digest, err := forks.CreateForkDigest(gt, vr[:])
assert.NoError(t, err)
digest := params.ForkDigest(slots.ToEpoch(clock.CurrentSlot()))
actualTopic := fmt.Sprintf(defaultTopic, digest, 5)
return s, actualTopic, clock
@@ -270,8 +268,8 @@ func TestService_ValidateSyncCommitteeMessage(t *testing.T) {
gt := time.Now().Add(-time.Second * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Duration(slots.PrevSlot(hState.Slot())))
vr := [32]byte{'A'}
digest, err := forks.CreateForkDigest(gt, vr[:])
assert.NoError(t, err)
clock := startup.NewClock(gt, vr)
digest := params.ForkDigest(clock.CurrentEpoch())
actualTopic := fmt.Sprintf(defaultTopic, digest, 5)
return s, actualTopic, startup.NewClock(gt, vr)
@@ -324,8 +322,8 @@ func TestService_ValidateSyncCommitteeMessage(t *testing.T) {
// Set Topic and Subnet
gt := time.Now().Add(-time.Second * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Duration(slots.PrevSlot(hState.Slot())))
vr := [32]byte{'A'}
digest, err := forks.CreateForkDigest(gt, vr[:])
assert.NoError(t, err)
clock := startup.NewClock(gt, vr)
digest := params.ForkDigest(slots.ToEpoch(clock.CurrentSlot()))
actualTopic := fmt.Sprintf(defaultTopic, digest, 5)
return s, actualTopic, startup.NewClock(gt, vr)
@@ -382,8 +380,8 @@ func TestService_ValidateSyncCommitteeMessage(t *testing.T) {
// Set Topic and Subnet
gt := time.Now().Add(-time.Second * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Duration(slots.PrevSlot(hState.Slot())))
vr := [32]byte{'A'}
digest, err := forks.CreateForkDigest(gt, vr[:])
assert.NoError(t, err)
clock := startup.NewClock(gt, vr)
digest := params.ForkDigest(slots.ToEpoch(clock.CurrentSlot()))
actualTopic := fmt.Sprintf(defaultTopic, digest, 1)
return s, actualTopic, startup.NewClock(gt, vr)

View File

@@ -35,7 +35,6 @@ go_library(
"//consensus-types/primitives:go_default_library",
"//crypto/bls:go_default_library",
"//encoding/bytesutil:go_default_library",
"//network/forks:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//runtime/logging:go_default_library",
"//time/slots:go_default_library",

View File

@@ -13,7 +13,6 @@ import (
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v6/crypto/bls"
"github.com/OffchainLabs/prysm/v6/network/forks"
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v6/time/slots"
lru "github.com/hashicorp/golang-lru"
@@ -63,7 +62,7 @@ func (d signatureData) logFields() logrus.Fields {
func newSigCache(vr []byte, size int, gf forkLookup) *sigCache {
if gf == nil {
gf = forks.Fork
gf = params.Fork
}
return &sigCache{Cache: lruwrpr.New(size), valRoot: vr, getFork: gf}
}

View File

@@ -10,9 +10,9 @@ import (
"github.com/OffchainLabs/prysm/v6/beacon-chain/startup"
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
fieldparams "github.com/OffchainLabs/prysm/v6/config/fieldparams"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/consensus-types/blocks"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v6/network/forks"
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
)
@@ -108,7 +108,7 @@ func NewInitializerWaiter(cw startup.ClockWaiter, fc Forkchoicer, sr StateByRoot
o(iw)
}
if iw.getFork == nil {
iw.getFork = forks.Fork
iw.getFork = params.Fork
}
return iw
}

View File

@@ -0,0 +1,2 @@
### Ignored
- remove usages of params from the proto package so that the params package can access proto types.

View File

@@ -0,0 +1,3 @@
### Added
- Implement EIP-7917: Stable proposer lookahead.

3
changelog/tt_fugu_.md Normal file
View File

@@ -0,0 +1,3 @@
### Removed
- Deneb and electra entries from blob schedule.

View File

@@ -20,6 +20,7 @@ go_library(
"//beacon-chain/p2p:go_default_library",
"//beacon-chain/p2p/encoder:go_default_library",
"//beacon-chain/p2p/types:go_default_library",
"//beacon-chain/startup:go_default_library",
"//beacon-chain/sync:go_default_library",
"//cmd:go_default_library",
"//config/params:go_default_library",
@@ -31,7 +32,6 @@ go_library(
"//monitoring/tracing:go_default_library",
"//monitoring/tracing/trace:go_default_library",
"//network:go_default_library",
"//network/forks:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/metadata:go_default_library",
"//runtime/version:go_default_library",

View File

@@ -9,13 +9,13 @@ import (
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p"
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/encoder"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/consensus-types/wrapper"
ecdsaprysm "github.com/OffchainLabs/prysm/v6/crypto/ecdsa"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v6/monitoring/tracing"
"github.com/OffchainLabs/prysm/v6/monitoring/tracing/trace"
"github.com/OffchainLabs/prysm/v6/network"
"github.com/OffchainLabs/prysm/v6/network/forks"
pb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1/metadata"
"github.com/OffchainLabs/prysm/v6/runtime/version"
@@ -178,7 +178,7 @@ func (c *client) initializeMockChainService(ctx context.Context) (*mockChain, er
return nil, err
}
currEpoch := slots.ToEpoch(slots.SinceGenesis(genesisResp.GenesisTime.AsTime()))
currFork, err := forks.Fork(currEpoch)
currFork, err := params.Fork(currEpoch)
if err != nil {
return nil, err
}

View File

@@ -4,8 +4,10 @@ import (
"context"
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p"
"github.com/OffchainLabs/prysm/v6/beacon-chain/startup"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v6/network/forks"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
pb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v6/time/slots"
libp2pcore "github.com/libp2p/go-libp2p/core"
@@ -50,11 +52,9 @@ func (c *client) statusRPCHandler(ctx context.Context, _ interface{}, stream lib
if err != nil {
return err
}
digest, err := forks.CreateForkDigest(resp.GenesisTime.AsTime(), resp.GenesisValidatorsRoot)
if err != nil {
return err
}
kindOfFork, err := forks.Fork(slots.ToEpoch(chainHead.HeadSlot))
clock := startup.NewClock(resp.GenesisTime.AsTime(), bytesutil.ToBytes32(resp.GenesisValidatorsRoot))
digest := params.ForkDigest(slots.ToEpoch(clock.CurrentSlot()))
kindOfFork, err := params.Fork(slots.ToEpoch(chainHead.HeadSlot))
if err != nil {
return err
}

View File

@@ -7,6 +7,8 @@ go_library(
"config_utils_develop.go", # keep
"config_utils_prod.go",
"configset.go",
"errors.go",
"fork.go",
"init.go",
"interop.go",
"io_config.go",
@@ -28,8 +30,11 @@ go_library(
deps = [
"//config/fieldparams:go_default_library",
"//consensus-types/primitives:go_default_library",
"//crypto/hash:go_default_library",
"//encoding/bytesutil:go_default_library",
"//math:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//runtime/version:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_ethereum_go_ethereum//params:go_default_library",
@@ -47,6 +52,8 @@ go_test(
"checktags_test.go",
"config_test.go",
"configset_test.go",
"export_test.go",
"fork_test.go",
"loader_test.go",
"mainnet_config_export_test.go",
"mainnet_config_test.go",
@@ -73,6 +80,7 @@ go_test(
"//consensus-types/primitives:go_default_library",
"//encoding/bytesutil:go_default_library",
"//io/file:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",

View File

@@ -2,15 +2,23 @@
package params
import (
"encoding/binary"
"fmt"
"math"
"slices"
"sort"
"time"
log "github.com/sirupsen/logrus"
fieldparams "github.com/OffchainLabs/prysm/v6/config/fieldparams"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v6/crypto/hash"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
enginev1 "github.com/OffchainLabs/prysm/v6/proto/engine/v1"
"github.com/OffchainLabs/prysm/v6/runtime/version"
"github.com/ethereum/go-ethereum/common"
"github.com/pkg/errors"
)
// BeaconChainConfig contains constant configs for node to participate in beacon chain.
@@ -313,18 +321,224 @@ type BeaconChainConfig struct {
// DeprecatedMaxBlobsPerBlockFulu defines the max blobs that could exist in a block post Fulu hard fork.
// Deprecated: This field is no longer supported. Avoid using it.
DeprecatedMaxBlobsPerBlockFulu int `yaml:"MAX_BLOBS_PER_BLOCK_FULU" spec:"true"`
forkSchedule *NetworkSchedule
bpoSchedule *NetworkSchedule
networkSchedule *NetworkSchedule
}
type BlobScheduleEntry struct {
Epoch primitives.Epoch `yaml:"EPOCH"`
func (b *BeaconChainConfig) ExecutionRequestLimits() enginev1.ExecutionRequestLimits {
return enginev1.ExecutionRequestLimits{
Deposits: b.MaxDepositRequestsPerPayload,
Withdrawals: b.MaxWithdrawalsPerPayload,
Consolidations: b.MaxConsolidationsRequestsPerPayload,
}
}
type NetworkScheduleEntry struct {
ForkVersion [fieldparams.VersionLength]byte
ForkDigest [4]byte
MaxBlobsPerBlock uint64 `yaml:"MAX_BLOBS_PER_BLOCK"`
Epoch primitives.Epoch `yaml:"EPOCH"`
VersionEnum int
isFork bool
}
func (ns NetworkScheduleEntry) Copy() NetworkScheduleEntry {
return NetworkScheduleEntry{
ForkVersion: ns.ForkVersion,
ForkDigest: ns.ForkDigest,
MaxBlobsPerBlock: ns.MaxBlobsPerBlock,
Epoch: ns.Epoch,
isFork: ns.isFork,
}
}
type BlobScheduleEntry NetworkScheduleEntry
// TODO: this needs to be able to return an error
// InitializeForkSchedule initializes the schedules forks baked into the config.
func (b *BeaconChainConfig) InitializeForkSchedule() {
// Reset Fork Version Schedule.
b.ForkVersionSchedule = configForkSchedule(b)
b.ForkVersionNames = configForkNames(b)
b.forkSchedule = initForkSchedule(b)
b.bpoSchedule = initBPOSchedule(b)
combined := b.forkSchedule.merge(b.bpoSchedule)
if err := combined.prepare(b); err != nil {
log.WithError(err).Error("failed to prepare network schedule", "error", err)
}
b.networkSchedule = combined
}
type NetworkSchedule struct {
entries []NetworkScheduleEntry
byEpoch map[primitives.Epoch]*NetworkScheduleEntry
byVersion map[[4]byte]*NetworkScheduleEntry
byDigest map[[4]byte]*NetworkScheduleEntry
}
func newNetworkSchedule(entries []NetworkScheduleEntry) *NetworkSchedule {
return &NetworkSchedule{
entries: entries,
byEpoch: make(map[primitives.Epoch]*NetworkScheduleEntry),
byVersion: make(map[[4]byte]*NetworkScheduleEntry),
byDigest: make(map[[4]byte]*NetworkScheduleEntry),
}
}
func (ns *NetworkSchedule) nextEpochIdx(epoch primitives.Epoch) int {
return sort.Search(len(ns.entries), func(i int) bool {
return ns.entries[i].Epoch > epoch
})
}
func (ns *NetworkSchedule) Next(epoch primitives.Epoch) NetworkScheduleEntry {
nextIdx := ns.nextEpochIdx(epoch)
if nextIdx < len(ns.entries) && ns.entries[nextIdx].Epoch != BeaconConfig().FarFutureEpoch {
return ns.entries[nextIdx]
}
return ns.LastEntry()
}
func (ns *NetworkSchedule) LastEntry() NetworkScheduleEntry {
for i := len(ns.entries) - 1; i >= 0; i-- {
if ns.entries[i].Epoch != BeaconConfig().FarFutureEpoch {
return ns.entries[i]
}
}
return ns.entries[0]
}
// LastFork is the last full fork (this is used by e2e testing)
func (ns *NetworkSchedule) LastFork() NetworkScheduleEntry {
for i := len(ns.entries) - 1; i >= 0; i-- {
if ns.entries[i].isFork && ns.entries[i].Epoch != BeaconConfig().FarFutureEpoch {
return ns.entries[i]
}
}
return ns.entries[0]
}
func (ns *NetworkSchedule) ForEpoch(epoch primitives.Epoch) NetworkScheduleEntry {
nextIdx := ns.nextEpochIdx(epoch)
if nextIdx > 0 {
return ns.entries[nextIdx-1]
}
return ns.entries[0]
}
func (ns *NetworkSchedule) activatedAt(epoch primitives.Epoch) (*NetworkScheduleEntry, bool) {
entry, ok := ns.byEpoch[epoch]
return entry, ok
}
func (ns *NetworkSchedule) merge(other *NetworkSchedule) *NetworkSchedule {
merged := make([]NetworkScheduleEntry, 0, len(ns.entries)+len(other.entries))
merged = append(merged, ns.entries...)
merged = append(merged, other.entries...)
sort.Slice(merged, func(i, j int) bool {
if merged[i].Epoch == merged[j].Epoch {
return merged[i].isFork
}
return merged[i].Epoch < merged[j].Epoch
})
return newNetworkSchedule(merged)
}
func (ns *NetworkSchedule) index(e NetworkScheduleEntry) {
if _, ok := ns.byEpoch[e.Epoch]; !ok {
ns.byDigest[e.ForkDigest] = &e
}
if _, ok := ns.byVersion[e.ForkVersion]; !ok {
ns.byVersion[e.ForkVersion] = &e
}
if _, ok := ns.byEpoch[e.Epoch]; !ok {
ns.byEpoch[e.Epoch] = &e
}
}
func (ns *NetworkSchedule) prepare(b *BeaconChainConfig) error {
if len(ns.entries) == 0 {
return errors.New("cannot compute digests for an empty network schedule")
}
if !ns.entries[0].isFork {
return errors.New("cannot compute digests for a network schedule without a fork entry")
}
lastFork, err := entryWithForkDigest(ns.entries[0], b)
if err != nil {
return err
}
// TODO: I don't think I need this copy thing but I'm paranoid and tired, remove it later
ns.entries[0] = lastFork.Copy()
ns.index(ns.entries[0])
lastBlobs := lastFork.MaxBlobsPerBlock
for i := 1; i < len(ns.entries); i++ {
entry := ns.entries[i]
if entry.isFork {
lastFork = entry
} else {
entry.ForkVersion = lastFork.ForkVersion
entry.VersionEnum = lastFork.VersionEnum
}
if entry.MaxBlobsPerBlock > 0 {
lastBlobs = entry.MaxBlobsPerBlock
} else {
entry.MaxBlobsPerBlock = lastBlobs
}
entry, err = entryWithForkDigest(entry, b)
if err != nil {
return err
}
ns.entries[i] = entry
ns.index(entry)
}
return nil
}
func entryWithForkDigest(entry NetworkScheduleEntry, b *BeaconChainConfig) (NetworkScheduleEntry, error) {
root, err := computeForkDataRoot(entry.ForkVersion, b.GenesisValidatorsRoot)
if err != nil {
return entry, err
}
entry.ForkDigest = bytesutil.ToBytes4(root[:])
if entry.Epoch < b.FuluForkEpoch {
return entry, nil
}
if entry.MaxBlobsPerBlock > math.MaxUint32 {
return entry, fmt.Errorf("max blobs per block exceeds maximum uint32 value")
}
hb := make([]byte, 16)
binary.LittleEndian.PutUint64(hb[0:8], uint64(entry.Epoch))
binary.LittleEndian.PutUint64(hb[8:], uint64(entry.MaxBlobsPerBlock))
bpoHash := hash.Hash(hb)
entry.ForkDigest[0] = entry.ForkDigest[0] ^ bpoHash[0]
entry.ForkDigest[1] = entry.ForkDigest[1] ^ bpoHash[1]
entry.ForkDigest[2] = entry.ForkDigest[2] ^ bpoHash[2]
entry.ForkDigest[3] = entry.ForkDigest[3] ^ bpoHash[3]
return entry, nil
}
func initForkSchedule(b *BeaconChainConfig) *NetworkSchedule {
return newNetworkSchedule([]NetworkScheduleEntry{
{Epoch: b.GenesisEpoch, isFork: true, ForkVersion: [4]byte(b.GenesisForkVersion), VersionEnum: version.Phase0},
{Epoch: b.AltairForkEpoch, isFork: true, ForkVersion: [4]byte(b.AltairForkVersion), VersionEnum: version.Altair},
{Epoch: b.BellatrixForkEpoch, isFork: true, ForkVersion: [4]byte(b.BellatrixForkVersion), VersionEnum: version.Bellatrix},
{Epoch: b.CapellaForkEpoch, isFork: true, ForkVersion: [4]byte(b.CapellaForkVersion), VersionEnum: version.Capella},
{Epoch: b.DenebForkEpoch, isFork: true, ForkVersion: [4]byte(b.DenebForkVersion), MaxBlobsPerBlock: uint64(b.DeprecatedMaxBlobsPerBlock), VersionEnum: version.Deneb},
{Epoch: b.ElectraForkEpoch, isFork: true, ForkVersion: [4]byte(b.ElectraForkVersion), MaxBlobsPerBlock: uint64(b.DeprecatedMaxBlobsPerBlockElectra), VersionEnum: version.Electra},
{Epoch: b.FuluForkEpoch, isFork: true, ForkVersion: [4]byte(b.FuluForkVersion), VersionEnum: version.Fulu},
})
}
func initBPOSchedule(b *BeaconChainConfig) *NetworkSchedule {
sort.Slice(b.BlobSchedule, func(i, j int) bool {
return b.BlobSchedule[i].Epoch < b.BlobSchedule[j].Epoch
})
entries := make([]NetworkScheduleEntry, len(b.BlobSchedule))
for i := range b.BlobSchedule {
entries[i] = NetworkScheduleEntry(b.BlobSchedule[i])
}
return newNetworkSchedule(entries)
}
func configForkSchedule(b *BeaconChainConfig) map[[fieldparams.VersionLength]byte]primitives.Epoch {

View File

@@ -22,6 +22,7 @@ func BeaconConfig() *BeaconChainConfig {
// OverrideBeaconConfig(c). Any subsequent calls to params.BeaconConfig() will
// return this new configuration.
func OverrideBeaconConfig(c *BeaconChainConfig) {
c.InitializeForkSchedule()
cfgrw.Lock()
defer cfgrw.Unlock()
configs.active = c

View File

@@ -16,6 +16,7 @@ func BeaconConfig() *BeaconChainConfig {
// OverrideBeaconConfig(c). Any subsequent calls to params.BeaconConfig() will
// return this new configuration.
func OverrideBeaconConfig(c *BeaconChainConfig) {
c.InitializeForkSchedule()
configs.active = c
}

View File

@@ -1,4 +1,4 @@
package forks
package params
import "github.com/pkg/errors"

View File

@@ -0,0 +1,3 @@
package params
var ComputeForkDataRoot = computeForkDataRoot

95
config/params/fork.go Normal file
View File

@@ -0,0 +1,95 @@
package params
import (
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/pkg/errors"
)
// IsForkNextEpoch checks if an allotted fork is in the following epoch.
func IsForkNextEpoch(currentEpoch primitives.Epoch) bool {
entry, ok := BeaconConfig().networkSchedule.activatedAt(currentEpoch + 1)
return ok && entry.isFork
}
// ForkDigestFromEpoch retrieves the fork digest from the current schedule determined
// by the provided epoch.
func ForkDigestFromEpoch(epoch primitives.Epoch) [4]byte {
return BeaconConfig().networkSchedule.ForEpoch(epoch).ForkDigest
}
// CreateForkDigest creates a fork digest from a genesis time and genesis
// validators root, utilizing the current slot to determine
// the active fork version in the node.
func ForkDigest(epoch primitives.Epoch) [4]byte {
return BeaconConfig().networkSchedule.ForEpoch(epoch).ForkDigest
}
func computeForkDataRoot(version [4]byte, root [32]byte) ([32]byte, error) {
r, err := (&ethpb.ForkData{
CurrentVersion: version[:],
GenesisValidatorsRoot: root[:],
}).HashTreeRoot()
if err != nil {
return [32]byte{}, nil
}
return r, nil
}
// Fork returns the fork version for the given epoch.
func Fork(epoch primitives.Epoch) (*ethpb.Fork, error) {
cfg := BeaconConfig()
return ForkFromConfig(cfg, epoch), nil
}
func ForkFromConfig(cfg *BeaconChainConfig, epoch primitives.Epoch) *ethpb.Fork {
current := cfg.networkSchedule.ForEpoch(epoch)
previous := current
if current.Epoch > 0 {
previous = BeaconConfig().networkSchedule.ForEpoch(current.Epoch - 1)
}
return &ethpb.Fork{
PreviousVersion: previous.ForkVersion[:],
CurrentVersion: current.ForkVersion[:],
Epoch: current.Epoch,
}
}
// RetrieveForkDataFromDigest performs the inverse, where it tries to determine the fork version
// and epoch from a provided digest by looping through our current fork schedule.
func ForkDataFromDigest(digest [4]byte) ([4]byte, primitives.Epoch, error) {
cfg := BeaconConfig()
entry, ok := cfg.networkSchedule.byDigest[digest]
if !ok {
return [4]byte{}, 0, errors.Errorf("no fork exists for a digest of %#x", digest)
}
return entry.ForkVersion, entry.Epoch, nil
}
// NextForkData retrieves the next fork data according to the
// provided current epoch.
func NextForkData(epoch primitives.Epoch) ([4]byte, primitives.Epoch) {
entry := BeaconConfig().networkSchedule.Next(epoch)
return entry.ForkVersion, entry.Epoch
}
func SortedNetworkScheduleEntries() []NetworkScheduleEntry {
return BeaconConfig().networkSchedule.entries
}
func SortedForkSchedule() []NetworkScheduleEntry {
entries := BeaconConfig().networkSchedule.entries
schedule := make([]NetworkScheduleEntry, 0, len(entries))
for _, entry := range entries {
if entry.isFork {
schedule = append(schedule, entry)
}
}
return schedule
}
// LastForkEpoch returns the last valid fork epoch that exists in our
// fork schedule.
func LastForkEpoch() primitives.Epoch {
return BeaconConfig().networkSchedule.LastFork().Epoch
}

165
config/params/fork_test.go Normal file
View File

@@ -0,0 +1,165 @@
package params_test
import (
"reflect"
"testing"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v6/testing/assert"
"github.com/OffchainLabs/prysm/v6/testing/require"
)
func TestFork(t *testing.T) {
params.SetupTestConfigCleanup(t)
cfg := params.BeaconConfig().Copy()
tests := []struct {
name string
targetEpoch primitives.Epoch
want *ethpb.Fork
wantErr bool
setConfg func()
}{
{
name: "genesis fork",
targetEpoch: 0,
want: &ethpb.Fork{
Epoch: cfg.GenesisEpoch,
CurrentVersion: cfg.GenesisForkVersion,
PreviousVersion: cfg.GenesisForkVersion,
},
},
{
name: "altair on fork",
targetEpoch: cfg.AltairForkEpoch,
want: &ethpb.Fork{
Epoch: cfg.AltairForkEpoch,
CurrentVersion: cfg.AltairForkVersion,
PreviousVersion: cfg.GenesisForkVersion,
},
},
{
name: "altair post fork",
targetEpoch: cfg.CapellaForkEpoch + 1,
want: &ethpb.Fork{
Epoch: cfg.CapellaForkEpoch,
CurrentVersion: cfg.CapellaForkVersion,
PreviousVersion: cfg.BellatrixForkVersion,
},
},
{
name: "3 forks, pre-fork",
targetEpoch: cfg.ElectraForkEpoch - 1,
want: &ethpb.Fork{
Epoch: cfg.DenebForkEpoch,
CurrentVersion: cfg.DenebForkVersion,
PreviousVersion: cfg.CapellaForkVersion,
},
},
{
name: "3 forks, on fork",
targetEpoch: cfg.ElectraForkEpoch,
want: &ethpb.Fork{
Epoch: cfg.ElectraForkEpoch,
CurrentVersion: cfg.ElectraForkVersion,
PreviousVersion: cfg.DenebForkVersion,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
copied := cfg.Copy()
params.OverrideBeaconConfig(copied)
got, err := params.Fork(tt.targetEpoch)
if (err != nil) != tt.wantErr {
t.Errorf("Fork() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Fork() got = %v, want %v", got, tt.want)
}
})
}
}
func TestRetrieveForkDataFromDigest(t *testing.T) {
params.SetupTestConfigCleanup(t)
digest := params.ForkDigest(params.BeaconConfig().AltairForkEpoch)
version, epoch, err := params.ForkDataFromDigest(digest)
require.NoError(t, err)
require.Equal(t, [4]byte(params.BeaconConfig().AltairForkVersion), version)
require.Equal(t, params.BeaconConfig().AltairForkEpoch, epoch)
}
func TestIsForkNextEpoch(t *testing.T) {
// at
assert.Equal(t, false, params.IsForkNextEpoch(params.BeaconConfig().ElectraForkEpoch))
// just before
assert.Equal(t, true, params.IsForkNextEpoch(params.BeaconConfig().ElectraForkEpoch-1))
// just after
assert.Equal(t, false, params.IsForkNextEpoch(params.BeaconConfig().ElectraForkEpoch+1))
}
func TestNextForkData(t *testing.T) {
params.SetupTestConfigCleanup(t)
cfg := params.BeaconConfig().Copy()
tests := []struct {
name string
setConfg func()
currEpoch primitives.Epoch
wantedForkVersion [4]byte
wantedEpoch primitives.Epoch
}{
{
name: "genesis",
currEpoch: 0,
wantedForkVersion: [4]byte(cfg.AltairForkVersion),
wantedEpoch: cfg.AltairForkEpoch,
},
{
name: "altair pre-fork",
currEpoch: cfg.AltairForkEpoch - 1,
wantedForkVersion: [4]byte(cfg.AltairForkVersion),
wantedEpoch: cfg.AltairForkEpoch,
},
{
name: "altair on fork",
currEpoch: cfg.AltairForkEpoch,
wantedForkVersion: [4]byte(cfg.BellatrixForkVersion),
wantedEpoch: cfg.BellatrixForkEpoch,
},
{
name: "altair post fork",
currEpoch: cfg.AltairForkEpoch + 1,
wantedForkVersion: [4]byte(cfg.BellatrixForkVersion),
wantedEpoch: cfg.BellatrixForkEpoch,
},
{
name: "electra post fork",
currEpoch: cfg.ElectraForkEpoch + 1,
wantedForkVersion: [4]byte(cfg.ElectraForkVersion),
wantedEpoch: cfg.ElectraForkEpoch,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
params.OverrideBeaconConfig(cfg.Copy())
fVersion, fEpoch := params.NextForkData(tt.currEpoch)
if fVersion != tt.wantedForkVersion {
t.Errorf("NextForkData() fork version = %v, want %v", fVersion, tt.wantedForkVersion)
}
if fEpoch != tt.wantedEpoch {
t.Errorf("NextForkData() fork epoch = %v, want %v", fEpoch, tt.wantedEpoch)
}
})
}
}
func TestLastForkEpoch(t *testing.T) {
params.SetupTestConfigCleanup(t)
cfg := params.BeaconConfig().Copy()
require.Equal(t, cfg.ElectraForkEpoch, params.LastForkEpoch())
}

View File

@@ -197,7 +197,7 @@ var mainnetBeaconConfig = &BeaconChainConfig{
BeaconStateCapellaFieldCount: 28,
BeaconStateDenebFieldCount: 28,
BeaconStateElectraFieldCount: 37,
BeaconStateFuluFieldCount: 37,
BeaconStateFuluFieldCount: 38,
// Slasher related values.
WeakSubjectivityPeriod: 54000,
@@ -340,10 +340,7 @@ var mainnetBeaconConfig = &BeaconChainConfig{
SubnetsPerNode: 2,
NodeIdBits: 256,
BlobSchedule: []BlobScheduleEntry{
{Epoch: 269568, MaxBlobsPerBlock: 6},
{Epoch: 364032, MaxBlobsPerBlock: 9},
},
BlobSchedule: []BlobScheduleEntry{},
}
// MainnetTestConfig provides a version of the mainnet config that has a different name

View File

@@ -127,10 +127,7 @@ func MinimalSpecConfig() *BeaconChainConfig {
minimalConfig.ConfigName = MinimalName
minimalConfig.PresetBase = "minimal"
minimalConfig.BlobSchedule = []BlobScheduleEntry{
{Epoch: 18446744073709551615, MaxBlobsPerBlock: 6},
{Epoch: 18446744073709551615, MaxBlobsPerBlock: 9},
}
minimalConfig.BlobSchedule = make([]BlobScheduleEntry, 0)
minimalConfig.InitializeForkSchedule()
return minimalConfig

View File

@@ -46,10 +46,7 @@ func HoleskyConfig() *BeaconChainConfig {
cfg.TerminalTotalDifficulty = "0"
cfg.DepositContractAddress = "0x4242424242424242424242424242424242424242"
cfg.EjectionBalance = 28000000000
cfg.BlobSchedule = []BlobScheduleEntry{
{Epoch: 29696, MaxBlobsPerBlock: 6},
{Epoch: 115968, MaxBlobsPerBlock: 9},
}
cfg.BlobSchedule = []BlobScheduleEntry{}
cfg.InitializeForkSchedule()
return cfg
}

Some files were not shown because too many files have changed in this diff Show More