Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,9 @@ filegroup(
url = "https://github.com/ethereum/EIPs/archive/5480440fe51742ed23342b68cf106cefd427e39d.tar.gz",
)

consensus_spec_version = "v1.4.0-beta.1"
consensus_spec_test_version = "v1.4.0-beta.2-hotfix"

consensus_spec_version = "v1.4.0-beta.2"

bls_test_version = "v0.1.1"

Expand All @@ -263,8 +265,8 @@ filegroup(
visibility = ["//visibility:public"],
)
""",
sha256 = "24399b60ce3fbeb2311952d213dc3731b6dcb0f8881b016c283de5b518d2bbba",
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/general.tar.gz" % consensus_spec_version,
sha256 = "99770a001189f66204a4ef79161c8002bcbbcbd8236f1c6479bd5b83a3c68d42",
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/general.tar.gz" % consensus_spec_test_version,
)

http_archive(
Expand All @@ -279,8 +281,8 @@ filegroup(
visibility = ["//visibility:public"],
)
""",
sha256 = "8e656ee48d2e2ebc9cf9baedb81f27925bc625b3e3fbb2883444a08758a5884a",
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/minimal.tar.gz" % consensus_spec_version,
sha256 = "56763f6492ee137108271007d62feef60d8e3f1698e53dee4bc4b07e55f7326b",
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/minimal.tar.gz" % consensus_spec_test_version,
)

http_archive(
Expand All @@ -295,8 +297,8 @@ filegroup(
visibility = ["//visibility:public"],
)
""",
sha256 = "8bd137da6cc57a25383bfac5bc37e31265098145278bd8002b88e24c8b4718b9",
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/mainnet.tar.gz" % consensus_spec_version,
sha256 = "bc1cac1a991cdc7426efea14385dcf215df85ed3f0572b824ad6a1d7ca0c89ad",
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/mainnet.tar.gz" % consensus_spec_test_version,
)

http_archive(
Expand All @@ -310,7 +312,7 @@ filegroup(
visibility = ["//visibility:public"],
)
""",
sha256 = "2bc1edb6e4a4f86c00317c04618a90b0ca29ee1eba833d0a64dd67fdd83fdbe3",
sha256 = "c5898001aaab2a5bb38a39ff9d17a52f1f9befcc26e63752cbf556040f0c884e",
strip_prefix = "consensus-specs-" + consensus_spec_version[1:],
url = "https://github.com/ethereum/consensus-specs/archive/refs/tags/%s.tar.gz" % consensus_spec_version,
)
Expand Down
18 changes: 17 additions & 1 deletion beacon-chain/blockchain/receive_blob.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,23 @@
package blockchain

import (
"context"

ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
)

// SendNewBlobEvent sends a message to the BlobNotifier channel that the blob
// for the blocroot `root` is ready in the database
func (s *Service) SendNewBlobEvent(root [32]byte, index uint64) {
func (s *Service) sendNewBlobEvent(root [32]byte, index uint64) {
s.blobNotifiers.forRoot(root) <- index
}

// ReceiveBlob saves the blob to database and sends the new event
func (s *Service) ReceiveBlob(ctx context.Context, b *ethpb.BlobSidecar) error {
if err := s.cfg.BeaconDB.SaveBlobSidecar(ctx, []*ethpb.BlobSidecar{b}); err != nil {
return err
}

s.sendNewBlobEvent([32]byte(b.BlockRoot), b.Index)
return nil
}
4 changes: 2 additions & 2 deletions beacon-chain/blockchain/receive_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package blockchain
import (
"bytes"
"context"
"time"

"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed"
Expand All @@ -21,7 +22,6 @@ import (
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1/attestation"
"github.com/prysmaticlabs/prysm/v4/runtime/version"
"github.com/prysmaticlabs/prysm/v4/time"
"github.com/prysmaticlabs/prysm/v4/time/slots"
"go.opencensus.io/trace"
"golang.org/x/sync/errgroup"
Expand All @@ -42,7 +42,7 @@ type BlockReceiver interface {
// BlobReceiver interface defines the methods of chain service for receiving new
// blobs
type BlobReceiver interface {
SendNewBlobEvent([32]byte, uint64)
ReceiveBlob(context.Context, *ethpb.BlobSidecar) error
}

// SlashingReceiver interface defines the methods of chain service for receiving validated slashing over the wire.
Expand Down
8 changes: 5 additions & 3 deletions beacon-chain/blockchain/testing/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -606,10 +606,12 @@ func (s *ChainService) UnrealizedJustifiedPayloadBlockHash() [32]byte {
return [32]byte{}
}

// SendNewBlobEvent mocks the same method in the chain service
func (*ChainService) SendNewBlobEvent(_ [32]byte, _ uint64) {}

// BlockBeingSynced mocks the same method in the chain service
func (c *ChainService) BlockBeingSynced(root [32]byte) bool {
return root == c.SyncingRoot
}

// ReceiveBlob implements the same method in the chain service
func (*ChainService) ReceiveBlob(_ context.Context, _ *ethpb.BlobSidecar) error {
return nil
}
7 changes: 7 additions & 0 deletions beacon-chain/core/epoch/epoch_processing.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,13 @@ func ProcessRegistryUpdates(ctx context.Context, state state.BeaconState) (state
return nil, errors.Wrap(err, "could not get churn limit")
}

if state.Version() >= version.Deneb {
// Cap churn limit to max per epoch churn limit. New in EIP7514.
if churnLimit > params.BeaconConfig().MaxPerEpochActivationChurnLimit {
churnLimit = params.BeaconConfig().MaxPerEpochActivationChurnLimit
}
}

Comment on lines +145 to +151
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add unit tests for this? It's likely covered by spectest but we should have our own tests as well as spectests are a bit of a blackbox sometimes.

// Prevent churn limit cause index out of bound.
if churnLimit < limit {
limit = churnLimit
Expand Down
36 changes: 36 additions & 0 deletions beacon-chain/core/epoch/epoch_processing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,42 @@ func TestProcessRegistryUpdates_EligibleToActivate(t *testing.T) {
}
}

func TestProcessRegistryUpdates_EligibleToActivate_Cancun(t *testing.T) {
base := &ethpb.BeaconStateDeneb{
Slot: 5 * params.BeaconConfig().SlotsPerEpoch,
FinalizedCheckpoint: &ethpb.Checkpoint{Epoch: 6, Root: make([]byte, fieldparams.RootLength)},
}
cfg := params.BeaconConfig()
cfg.MinPerEpochChurnLimit = 10
cfg.ChurnLimitQuotient = 1
params.OverrideBeaconConfig(cfg)

for i := uint64(0); i < 10; i++ {
base.Validators = append(base.Validators, &ethpb.Validator{
ActivationEligibilityEpoch: params.BeaconConfig().FarFutureEpoch,
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
ActivationEpoch: params.BeaconConfig().FarFutureEpoch,
})
}
beaconState, err := state_native.InitializeFromProtoDeneb(base)
require.NoError(t, err)
currentEpoch := time.CurrentEpoch(beaconState)
newState, err := epoch.ProcessRegistryUpdates(context.Background(), beaconState)
require.NoError(t, err)
for i, validator := range newState.Validators() {
assert.Equal(t, currentEpoch+1, validator.ActivationEligibilityEpoch, "Could not update registry %d, unexpected activation eligibility epoch", i)
// Note: In Deneb, only validators indices before `MaxPerEpochActivationChurnLimit` should be activated.
if uint64(i) < params.BeaconConfig().MaxPerEpochActivationChurnLimit && validator.ActivationEpoch != helpers.ActivationExitEpoch(currentEpoch) {
t.Errorf("Could not update registry %d, validators failed to activate: wanted activation epoch %d, got %d",
i, helpers.ActivationExitEpoch(currentEpoch), validator.ActivationEpoch)
}
if uint64(i) >= params.BeaconConfig().MaxPerEpochActivationChurnLimit && validator.ActivationEpoch != params.BeaconConfig().FarFutureEpoch {
t.Errorf("Could not update registry %d, validators should not have been activated, wanted activation epoch: %d, got %d",
i, params.BeaconConfig().FarFutureEpoch, validator.ActivationEpoch)
}
}
}

func TestProcessRegistryUpdates_ActivationCompletes(t *testing.T) {
base := &ethpb.BeaconState{
Slot: 5 * params.BeaconConfig().SlotsPerEpoch,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
slot := primitives.Slot(1)
driftGenesisTime(f, slot, 0)
newRoot := indexToHash(1)
f.store.proposerBoostRoot = [32]byte{}
state, blkRoot, err := prepareForkchoiceState(
ctx,
slot,
Expand All @@ -74,6 +75,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
slot = primitives.Slot(2)
driftGenesisTime(f, slot, 0)
newRoot = indexToHash(2)
f.store.proposerBoostRoot = [32]byte{}
state, blkRoot, err = prepareForkchoiceState(
ctx,
slot,
Expand Down Expand Up @@ -101,6 +103,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
slot = primitives.Slot(3)
driftGenesisTime(f, slot, 0)
newRoot = indexToHash(3)
f.store.proposerBoostRoot = [32]byte{}
state, blkRoot, err = prepareForkchoiceState(
ctx,
slot,
Expand Down Expand Up @@ -129,6 +132,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
slot = primitives.Slot(4)
driftGenesisTime(f, slot, 0)
newRoot = indexToHash(4)
f.store.proposerBoostRoot = [32]byte{}
state, blkRoot, err = prepareForkchoiceState(
ctx,
slot,
Expand Down Expand Up @@ -335,6 +339,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
cSlot := primitives.Slot(2)
driftGenesisTime(f, cSlot, 0)
c := indexToHash(2)
f.store.proposerBoostRoot = [32]byte{}
state, blkRoot, err := prepareForkchoiceState(
ctx,
cSlot,
Expand All @@ -354,6 +359,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {

bSlot := primitives.Slot(1)
b := indexToHash(1)
f.store.proposerBoostRoot = [32]byte{}
state, blkRoot, err = prepareForkchoiceState(
ctx,
bSlot,
Expand All @@ -378,6 +384,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
// A block D, building on B, is received at slot N+3. It should not be able to win without boosting.
dSlot := primitives.Slot(3)
d := indexToHash(3)
f.store.proposerBoostRoot = [32]byte{}
state, blkRoot, err = prepareForkchoiceState(
ctx,
dSlot,
Expand All @@ -398,6 +405,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
// If the same block arrives with boosting then it becomes head:
driftGenesisTime(f, dSlot, 0)
d2 := indexToHash(30)
f.store.proposerBoostRoot = [32]byte{}
state, blkRoot, err = prepareForkchoiceState(
ctx,
dSlot,
Expand Down
3 changes: 2 additions & 1 deletion beacon-chain/forkchoice/doubly-linked-tree/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ func (s *Store) insert(ctx context.Context,
secondsIntoSlot := (timeNow - s.genesisTime) % params.BeaconConfig().SecondsPerSlot
currentSlot := slots.CurrentSlot(s.genesisTime)
boostThreshold := params.BeaconConfig().SecondsPerSlot / params.BeaconConfig().IntervalsPerSlot
if currentSlot == slot && secondsIntoSlot < boostThreshold {
isFirstBlock := s.proposerBoostRoot == [32]byte{}
if currentSlot == slot && secondsIntoSlot < boostThreshold && isFirstBlock {
s.proposerBoostRoot = root
}

Expand Down
4 changes: 3 additions & 1 deletion beacon-chain/rpc/eth/beacon/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ func TestGetSpec(t *testing.T) {
resp, err := server.GetSpec(context.Background(), &emptypb.Empty{})
require.NoError(t, err)

assert.Equal(t, 111, len(resp.Data))
assert.Equal(t, 112, len(resp.Data))
for k, v := range resp.Data {
switch k {
case "CONFIG_NAME":
Expand Down Expand Up @@ -380,6 +380,8 @@ func TestGetSpec(t *testing.T) {
assert.Equal(t, "20", v)
case "REORG_PARENT_WEIGHT_THRESHOLD":
assert.Equal(t, "160", v)
case "MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT":
assert.Equal(t, "8", v)
case "SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY":
default:
t.Errorf("Incorrect key: %s", k)
Expand Down
4 changes: 1 addition & 3 deletions beacon-chain/sync/subscriber_blob_sidecar.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,10 @@ func (s *Service) blobSubscriber(ctx context.Context, msg proto.Message) error {

s.setSeenBlobIndex(b.Message.Blob, b.Message.Index)

if err := s.cfg.beaconDB.SaveBlobSidecar(ctx, []*eth.BlobSidecar{b.Message}); err != nil {
if err := s.cfg.chain.ReceiveBlob(ctx, b.Message); err != nil {
return err
}

s.cfg.chain.SendNewBlobEvent([32]byte(b.Message.BlockRoot), b.Message.Index)

s.cfg.operationNotifier.OperationFeed().Send(&feed.Event{
Type: opfeed.BlobSidecarReceived,
Data: &opfeed.BlobSidecarReceivedData{
Expand Down
5 changes: 4 additions & 1 deletion config/params/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,14 +213,17 @@ type BeaconChainConfig struct {

// Mev-boost circuit breaker
MaxBuilderConsecutiveMissedSlots primitives.Slot // MaxBuilderConsecutiveMissedSlots defines the number of consecutive skip slot to fallback from using relay/builder to local execution engine for block construction.
MaxBuilderEpochMissedSlots primitives.Slot // MaxBuilderEpochMissedSlots is defines the number of total skip slot (per epoch rolling windows) to fallback from using relay/builder to local execution engine for block construction.
MaxBuilderEpochMissedSlots primitives.Slot // MaxBuilderEpochMissedSlots is defining the number of total skip slot (per epoch rolling windows) to fallback from using relay/builder to local execution engine for block construction.
LocalBlockValueBoost uint64 // LocalBlockValueBoost is the value boost for local block construction. This is used to prioritize local block construction over relay/builder block construction.

// Execution engine timeout value
ExecutionEngineTimeoutValue uint64 // ExecutionEngineTimeoutValue defines the seconds to wait before timing out engine endpoints with execution payload execution semantics (newPayload, forkchoiceUpdated).

// Subnet value
BlobsidecarSubnetCount uint64 `yaml:"BLOB_SIDECAR_SUBNET_COUNT"` // BlobsidecarSubnetCount is the number of blobsidecar subnets used in the gossipsub protocol.

// Values introduced in Deneb hard fork
MaxPerEpochActivationChurnLimit uint64 `yaml:"MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT" spec:"true"` // MaxPerEpochActivationChurnLimit is the maximum amount of churn allotted for validator activation.
}

// InitializeForkSchedule initializes the schedules forks baked into the config.
Expand Down
2 changes: 2 additions & 0 deletions config/params/loader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,10 @@ var placeholderFields = []string{
"SUBNETS_PER_NODE",
"TTFB_TIMEOUT",
"UPDATE_TIMEOUT",
"WHISK_EPOCHS_PER_SHUFFLING_PHASE",
"WHISK_FORK_EPOCH",
"WHISK_FORK_VERSION",
"WHISK_PROPOSER_SELECTION_GAP",
}

func TestPlaceholderFieldsDistinctSorted(t *testing.T) {
Expand Down
2 changes: 2 additions & 0 deletions config/params/mainnet_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,8 @@ var mainnetBeaconConfig = &BeaconChainConfig{

// Subnet value
BlobsidecarSubnetCount: 6,

MaxPerEpochActivationChurnLimit: 8,
}

// MainnetTestConfig provides a version of the mainnet config that has a different name
Expand Down
3 changes: 2 additions & 1 deletion config/params/minimal_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ func MinimalSpecConfig() *BeaconChainConfig {
minimalConfig.MaxCommitteesPerSlot = 4
minimalConfig.TargetCommitteeSize = 4
minimalConfig.MaxValidatorsPerCommittee = 2048
minimalConfig.MinPerEpochChurnLimit = 4
minimalConfig.MinPerEpochChurnLimit = 2 // Changed in EIP7514
minimalConfig.MaxPerEpochActivationChurnLimit = 4 // New in EIP7514
minimalConfig.ChurnLimitQuotient = 32
minimalConfig.ShuffleRoundCount = 10
minimalConfig.MinGenesisActiveValidatorCount = 64
Expand Down
4 changes: 2 additions & 2 deletions config/params/testdata/e2e_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ INACTIVITY_SCORE_BIAS: 4
INACTIVITY_SCORE_RECOVERY_RATE: 16
# 2**4 * 10**9 (= 16,000,000,000) Gwei
EJECTION_BALANCE: 16000000000
# 2**2 (= 4)
MIN_PER_EPOCH_CHURN_LIMIT: 4
# 2**1 (= 2)
MIN_PER_EPOCH_CHURN_LIMIT: 2
# [customized] scale queue churn at much lower validator counts for testing
CHURN_LIMIT_QUOTIENT: 65536

Expand Down
3 changes: 3 additions & 0 deletions config/params/testnet_e2e_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ func E2EMainnetTestConfig() *BeaconChainConfig {
e2eConfig.CapellaForkVersion = []byte{3, 0, 0, 254}
e2eConfig.DenebForkVersion = []byte{4, 0, 0, 254}

// Deneb changes.
e2eConfig.MinPerEpochChurnLimit = 2

e2eConfig.InitializeForkSchedule()
return e2eConfig
}
2 changes: 1 addition & 1 deletion proto/eth/v1/generated.ssz.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion proto/eth/v2/generated.ssz.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion proto/prysm/v1alpha1/blobs.proto
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,4 @@ message SignedBlindedBlobSidecar {
message BlobIdentifier {
bytes block_root = 1 [(ethereum.eth.ext.ssz_size) = "32"];
uint64 index = 2;
}
}
2 changes: 1 addition & 1 deletion proto/prysm/v1alpha1/generated.ssz.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading