Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement consensus spec v1.5.0-alpha.10 #14733

Merged
merged 25 commits into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
ee39207
Use 16 bit random value
terencechain Dec 16, 2024
491498e
enforce 0x02 credentials for consolidations
terencechain Nov 30, 2024
45c4612
Limit consolidating balance by validator effective balance
terencechain Dec 16, 2024
910f1ce
Update max blob commitment size
terencechain Dec 16, 2024
83cbd88
Fix next sync committee indices
terencechain Dec 16, 2024
bc47d24
Bytes to little endian
terencechain Dec 16, 2024
16473b9
Handle proposer computations in between forks
terencechain Dec 17, 2024
511adcc
Fix config and tests
terencechain Dec 17, 2024
f553245
Fix test stream events by properly set effective balance
terencechain Dec 18, 2024
6448406
Preallocate buffers to avoid repeated allocations
terencechain Dec 18, 2024
aee1467
Potuz's feedback
terencechain Dec 19, 2024
ed695aa
Use 16 bit random value
terencechain Dec 16, 2024
96dadbd
enforce 0x02 credentials for consolidations
terencechain Nov 30, 2024
fa39ce4
Limit consolidating balance by validator effective balance
terencechain Dec 16, 2024
acc70e7
Update max blob commitment size
terencechain Dec 16, 2024
30a0a37
Fix next sync committee indices
terencechain Dec 16, 2024
c9b8eef
Bytes to little endian
terencechain Dec 16, 2024
f37f0c2
Handle proposer computations in between forks
terencechain Dec 17, 2024
35da875
Fix config and tests
terencechain Dec 17, 2024
070eaa0
Fix test stream events by properly set effective balance
terencechain Dec 18, 2024
012b224
Preallocate buffers to avoid repeated allocations
terencechain Dec 18, 2024
1a49d61
Potuz's feedback
terencechain Dec 19, 2024
cea2442
Merge branch 'alpha10-spec-tests' of github.com:prysmaticlabs/prysm i…
terencechain Dec 20, 2024
73d78c9
Fix change log
terencechain Dec 20, 2024
1145786
Merge branch 'develop' of github.com:prysmaticlabs/prysm into alpha10…
terencechain Dec 23, 2024
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ Notable features:
- Save light client updates and bootstraps in DB.
- Added more comprehensive tests for `BlockToLightClientHeader`. [PR](https://github.com/prysmaticlabs/prysm/pull/14699)
- Added light client feature flag check to RPC handlers. [PR](https://github.com/prysmaticlabs/prysm/pull/14736)
- Add field param placeholder for Electra blob target and max to pass spec tests.
Copy link
Member

Choose a reason for hiding this comment

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

Please add this to the unreleased section


### Changed

Expand Down Expand Up @@ -126,6 +127,9 @@ Notable features:
- Check kzg commitments align with blobs and proofs for beacon api end point.
- Revert "Proposer checks gas limit before accepting builder's bid".
- Updated quic-go to v0.48.2 .
- Enforce Compound prefix (0x02) for target when processing pending consolidation request.
- Limit consolidating by validator's effective balance.
- Use 16-bit random value for proposer and sync committee selection filter.
Copy link
Member

Choose a reason for hiding this comment

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

Please add this to the unreleased section


### Deprecated

Expand Down
10 changes: 5 additions & 5 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ filegroup(
url = "https://github.com/ethereum/EIPs/archive/5480440fe51742ed23342b68cf106cefd427e39d.tar.gz",
)

consensus_spec_version = "v1.5.0-alpha.9"
consensus_spec_version = "v1.5.0-alpha.10"

bls_test_version = "v0.1.1"

Expand All @@ -243,7 +243,7 @@ filegroup(
visibility = ["//visibility:public"],
)
""",
integrity = "sha256-gHbvlnErUeJGWzW8/8JiVlk28JwmXSMhOzkynEIz+8g=",
integrity = "sha256-NtWIhbO/mVMb1edq5jqABL0o8R1tNFiuG8PCMAsUHcs=",
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/general.tar.gz" % consensus_spec_version,
)

Expand All @@ -259,7 +259,7 @@ filegroup(
visibility = ["//visibility:public"],
)
""",
integrity = "sha256-hQkQdpm5ng4miGYa5WsOKWa0q8WtZu99Oqbv9QtBeJM=",
integrity = "sha256-DFlFlnzls1bBrDm+/xD8NK2ivvkhxR+rSNVLLqScVKc=",
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/minimal.tar.gz" % consensus_spec_version,
)

Expand All @@ -275,7 +275,7 @@ filegroup(
visibility = ["//visibility:public"],
)
""",
integrity = "sha256-33sBsmApnJpcyYfR3olKaPB+WC1q00ZKNzHa2TczIxk=",
integrity = "sha256-G9ENPF8udZL/BqRHbi60GhFPnZDPZAH6UjcjRiOlvbk=",
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/mainnet.tar.gz" % consensus_spec_version,
)

Expand All @@ -290,7 +290,7 @@ filegroup(
visibility = ["//visibility:public"],
)
""",
integrity = "sha256-GQulBKLc2khpql2K/MxV+NG/d2kAhLXl+gLnKIg7rt4=",
integrity = "sha256-ClOLKkmAcEi8/uKi6LDeqthask5+E3sgxVoA0bqmQ0c=",
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
47 changes: 30 additions & 17 deletions beacon-chain/core/altair/sync_committee.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package altair

import (
"context"
"encoding/binary"
goErrors "errors"
"fmt"
"time"
Expand All @@ -22,8 +23,6 @@ import (
"github.com/prysmaticlabs/prysm/v5/time/slots"
)

const maxRandomByte = uint64(1<<8 - 1)

var (
ErrTooLate = errors.New("sync message is too late")
)
Expand Down Expand Up @@ -91,19 +90,22 @@ func NextSyncCommittee(ctx context.Context, s state.BeaconState) (*ethpb.SyncCom
// """
// epoch = Epoch(get_current_epoch(state) + 1)
//
// MAX_RANDOM_BYTE = 2**8 - 1
// MAX_RANDOM_VALUE = 2**16 - 1 # [Modified in Electra]
// active_validator_indices = get_active_validator_indices(state, epoch)
// active_validator_count = uint64(len(active_validator_indices))
// seed = get_seed(state, epoch, DOMAIN_SYNC_COMMITTEE)
// i = 0
// i = uint64(0)
// sync_committee_indices: List[ValidatorIndex] = []
// while len(sync_committee_indices) < SYNC_COMMITTEE_SIZE:
// shuffled_index = compute_shuffled_index(uint64(i % active_validator_count), active_validator_count, seed)
// candidate_index = active_validator_indices[shuffled_index]
// random_byte = hash(seed + uint_to_bytes(uint64(i // 32)))[i % 32]
// # [Modified in Electra]
// random_bytes = hash(seed + uint_to_bytes(i // 16))
// offset = i % 16 * 2
// random_value = bytes_to_uint64(random_bytes[offset:offset + 2])
// effective_balance = state.validators[candidate_index].effective_balance
// # [Modified in Electra:EIP7251]
// if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE_ELECTRA * random_byte:
// if effective_balance * MAX_RANDOM_VALUE >= MAX_EFFECTIVE_BALANCE_ELECTRA * random_value:
// sync_committee_indices.append(candidate_index)
// i += 1
// return sync_committee_indices
Expand All @@ -123,12 +125,11 @@ func NextSyncCommitteeIndices(ctx context.Context, s state.BeaconState) ([]primi
cIndices := make([]primitives.ValidatorIndex, 0, syncCommitteeSize)
hashFunc := hash.CustomSHA256Hasher()

maxEB := cfg.MaxEffectiveBalanceElectra
if s.Version() < version.Electra {
maxEB = cfg.MaxEffectiveBalance
}
// Preallocate buffers to avoid repeated allocations
seedBuffer := make([]byte, len(seed)+8)
copy(seedBuffer, seed[:])

for i := primitives.ValidatorIndex(0); uint64(len(cIndices)) < params.BeaconConfig().SyncCommitteeSize; i++ {
for i := primitives.ValidatorIndex(0); uint64(len(cIndices)) < syncCommitteeSize; i++ {
if ctx.Err() != nil {
return nil, ctx.Err()
}
Expand All @@ -137,18 +138,30 @@ func NextSyncCommitteeIndices(ctx context.Context, s state.BeaconState) ([]primi
if err != nil {
return nil, err
}

b := append(seed[:], bytesutil.Bytes8(uint64(i.Div(32)))...)
randomByte := hashFunc(b)[i%32]
cIndex := indices[sIndex]
v, err := s.ValidatorAtIndexReadOnly(cIndex)
if err != nil {
return nil, err
}

effectiveBal := v.EffectiveBalance()
if effectiveBal*maxRandomByte >= maxEB*uint64(randomByte) {
cIndices = append(cIndices, cIndex)

if s.Version() >= version.Electra {
Copy link
Member Author

Choose a reason for hiding this comment

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

This change is related to: ethereum/consensus-specs#4039
We defer fieldparams for MaxRandomByte as single source of truth

// Use the preallocated seed buffer
binary.LittleEndian.PutUint64(seedBuffer[len(seed):], uint64(i/16))
randomByte := hashFunc(seedBuffer)
offset := (i % 16) * 2
randomValue := uint64(randomByte[offset]) | uint64(randomByte[offset+1])<<8

if effectiveBal*fieldparams.MaxRandomValueElectra >= cfg.MaxEffectiveBalanceElectra*randomValue {
cIndices = append(cIndices, cIndex)
}
} else {
// Use the preallocated seed buffer
binary.LittleEndian.PutUint64(seedBuffer[len(seed):], uint64(i/32))
randomByte := hashFunc(seedBuffer)[i%32]
if effectiveBal*fieldparams.MaxRandomByte >= cfg.MaxEffectiveBalance*uint64(randomByte) {
cIndices = append(cIndices, cIndex)
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/core/electra/churn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func createValidatorsWithTotalActiveBalance(totalBal primitives.Gwei) []*eth.Val
vals := make([]*eth.Validator, num)
for i := range vals {
wd := make([]byte, 32)
wd[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
Copy link
Member

Choose a reason for hiding this comment

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

This seems unexpected. Why is it changed?

Copy link
Member Author

Choose a reason for hiding this comment

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

Related to: ethereum/consensus-specs#4020
In latest spec, consolidation is only allowed if validator has 0x02

wd[0] = params.BeaconConfig().CompoundingWithdrawalPrefixByte
wd[31] = byte(i)

vals[i] = &eth.Validator{
Expand Down
22 changes: 5 additions & 17 deletions beacon-chain/core/electra/consolidations.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ import (
// break
//
// # Calculate the consolidated balance
// max_effective_balance = get_max_effective_balance(source_validator)
// source_effective_balance = min(state.balances[pending_consolidation.source_index], max_effective_balance)
// source_effective_balance = min(state.balances[pending_consolidation.source_index], source_validator.effective_balance)
//
// # Move active balance to target. Excess balance is withdrawable.
// decrease_balance(state, pending_consolidation.source_index, source_effective_balance)
Expand Down Expand Up @@ -78,7 +77,7 @@ func ProcessPendingConsolidations(ctx context.Context, st state.BeaconState) err
if err != nil {
return err
}
b := min(validatorBalance, helpers.ValidatorMaxEffectiveBalance(sourceValidator))
b := min(validatorBalance, sourceValidator.EffectiveBalance())
Copy link
Member Author

@terencechain terencechain Dec 17, 2024

Choose a reason for hiding this comment

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

This is related to: ethereum/consensus-specs#4040
Also updated spec test above


if err := helpers.DecreaseBalance(st, pc.SourceIndex, b); err != nil {
return err
Expand Down Expand Up @@ -141,8 +140,8 @@ func ProcessPendingConsolidations(ctx context.Context, st state.BeaconState) err
// if not (has_correct_credential and is_correct_source_address):
// return
//
// # Verify that target has execution withdrawal credentials
// if not has_execution_withdrawal_credential(target_validator):
// # Verify that target has compounding withdrawal credentials
// if not has_compounding_withdrawal_credential(target_validator):
// return
//
// # Verify the source and the target are active
Expand Down Expand Up @@ -175,10 +174,6 @@ func ProcessPendingConsolidations(ctx context.Context, st state.BeaconState) err
// source_index=source_index,
// target_index=target_index
// ))
//
// # Churn any target excess active balance of target and raise its max
// if has_eth1_withdrawal_credential(target_validator):
// switch_to_compounding_validator(state, target_index)
func ProcessConsolidationRequests(ctx context.Context, st state.BeaconState, reqs []*enginev1.ConsolidationRequest) error {
if len(reqs) == 0 || st == nil {
return nil
Expand Down Expand Up @@ -253,7 +248,7 @@ func ProcessConsolidationRequests(ctx context.Context, st state.BeaconState, req
}

// Target validator must have their withdrawal credentials set appropriately.
if !helpers.HasExecutionWithdrawalCredentials(tgtV) {
if !helpers.HasCompoundingWithdrawalCredential(tgtV) {
Copy link
Member Author

Choose a reason for hiding this comment

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

This is related to ethereum/consensus-specs#4020

continue
}

Expand Down Expand Up @@ -298,13 +293,6 @@ func ProcessConsolidationRequests(ctx context.Context, st state.BeaconState, req
if err := st.AppendPendingConsolidation(&eth.PendingConsolidation{SourceIndex: srcIdx, TargetIndex: tgtIdx}); err != nil {
return fmt.Errorf("failed to append pending consolidation: %w", err) // This should never happen.
}

if helpers.HasETH1WithdrawalCredential(tgtV) {
if err := SwitchToCompoundingValidator(st, tgtIdx); err != nil {
log.WithError(err).Error("failed to switch to compounding validator")
continue
}
}
}

return nil
Expand Down
5 changes: 3 additions & 2 deletions beacon-chain/core/electra/consolidations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ func TestProcessPendingConsolidations(t *testing.T) {
Validators: []*eth.Validator{
{
WithdrawalCredentials: []byte{0x01, 0xFF},
EffectiveBalance: params.BeaconConfig().MinActivationBalance,
},
{
WithdrawalCredentials: []byte{0x01, 0xAB},
Expand Down Expand Up @@ -218,7 +219,7 @@ func TestProcessConsolidationRequests(t *testing.T) {
}
// Validator scenario setup. See comments in reqs section.
st.Validators[3].WithdrawalCredentials = bytesutil.Bytes32(0)
st.Validators[8].WithdrawalCredentials = bytesutil.Bytes32(0)
st.Validators[8].WithdrawalCredentials = bytesutil.Bytes32(1)
st.Validators[9].ActivationEpoch = params.BeaconConfig().FarFutureEpoch
st.Validators[12].ActivationEpoch = params.BeaconConfig().FarFutureEpoch
st.Validators[13].ExitEpoch = 10
Expand Down Expand Up @@ -246,7 +247,7 @@ func TestProcessConsolidationRequests(t *testing.T) {
SourcePubkey: []byte("val_5"),
TargetPubkey: []byte("val_6"),
},
// Target does not have their withdrawal credentials set appropriately.
// Target does not have their withdrawal credentials set appropriately. (Using eth1 address prefix)
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(7)),
SourcePubkey: []byte("val_7"),
Expand Down
61 changes: 38 additions & 23 deletions beacon-chain/core/helpers/validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package helpers
import (
"bytes"
"context"
"encoding/binary"

"github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus"
Expand All @@ -11,6 +12,7 @@ import (
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time"
forkchoicetypes "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice/types"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
Expand Down Expand Up @@ -347,27 +349,33 @@ func BeaconProposerIndexAtSlot(ctx context.Context, state state.ReadOnlyBeaconSt
// Spec pseudocode definition:
//
// def compute_proposer_index(state: BeaconState, indices: Sequence[ValidatorIndex], seed: Bytes32) -> ValidatorIndex:
// """
// Return from ``indices`` a random index sampled by effective balance.
// """
// assert len(indices) > 0
// MAX_RANDOM_BYTE = 2**8 - 1
// i = uint64(0)
// total = uint64(len(indices))
// while True:
// candidate_index = indices[compute_shuffled_index(i % total, total, seed)]
// random_byte = hash(seed + uint_to_bytes(uint64(i // 32)))[i % 32]
// effective_balance = state.validators[candidate_index].effective_balance
// if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE_ELECTRA * random_byte: #[Modified in Electra:EIP7251]
// return candidate_index
// i += 1
// """
// Return from ``indices`` a random index sampled by effective balance.
// """
// assert len(indices) > 0
// MAX_RANDOM_VALUE = 2**16 - 1 # [Modified in Electra]
// i = uint64(0)
// total = uint64(len(indices))
// while True:
// candidate_index = indices[compute_shuffled_index(i % total, total, seed)]
// # [Modified in Electra]
// random_bytes = hash(seed + uint_to_bytes(i // 16))
// offset = i % 16 * 2
// random_value = bytes_to_uint64(random_bytes[offset:offset + 2])
// effective_balance = state.validators[candidate_index].effective_balance
// # [Modified in Electra:EIP7251]
// if effective_balance * MAX_RANDOM_VALUE >= MAX_EFFECTIVE_BALANCE_ELECTRA * random_value:
// return candidate_index
// i += 1
func ComputeProposerIndex(bState state.ReadOnlyBeaconState, activeIndices []primitives.ValidatorIndex, seed [32]byte) (primitives.ValidatorIndex, error) {
length := uint64(len(activeIndices))
if length == 0 {
return 0, errors.New("empty active indices list")
}
maxRandomByte := uint64(1<<8 - 1)
hashFunc := hash.CustomSHA256Hasher()
beaconConfig := params.BeaconConfig()
seedBuffer := make([]byte, len(seed)+8)
copy(seedBuffer, seed[:])

for i := uint64(0); ; i++ {
candidateIndex, err := ComputeShuffledIndex(primitives.ValidatorIndex(i%length), length, seed, true /* shuffle */)
Expand All @@ -378,21 +386,28 @@ func ComputeProposerIndex(bState state.ReadOnlyBeaconState, activeIndices []prim
if uint64(candidateIndex) >= uint64(bState.NumValidators()) {
return 0, errors.New("active index out of range")
}
b := append(seed[:], bytesutil.Bytes8(i/32)...)
randomByte := hashFunc(b)[i%32]

v, err := bState.ValidatorAtIndexReadOnly(candidateIndex)
if err != nil {
return 0, err
}
effectiveBal := v.EffectiveBalance()

maxEB := params.BeaconConfig().MaxEffectiveBalance
if bState.Version() >= version.Electra {
maxEB = params.BeaconConfig().MaxEffectiveBalanceElectra
}
binary.LittleEndian.PutUint64(seedBuffer[len(seed):], i/16)
randomByte := hashFunc(seedBuffer)
offset := (i % 16) * 2
randomValue := uint64(randomByte[offset]) | uint64(randomByte[offset+1])<<8

if effectiveBal*fieldparams.MaxRandomValueElectra >= beaconConfig.MaxEffectiveBalanceElectra*randomValue {
return candidateIndex, nil
}
} else {
binary.LittleEndian.PutUint64(seedBuffer[len(seed):], i/32)
randomByte := hashFunc(seedBuffer)[i%32]

if effectiveBal*maxRandomByte >= maxEB*uint64(randomByte) {
return candidateIndex, nil
if effectiveBal*fieldparams.MaxRandomByte >= beaconConfig.MaxEffectiveBalance*uint64(randomByte) {
return candidateIndex, nil
}
}
}
}
Expand Down
3 changes: 1 addition & 2 deletions beacon-chain/core/helpers/validators_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -841,7 +841,6 @@ func computeProposerIndexWithValidators(validators []*ethpb.Validator, activeInd
if length == 0 {
return 0, errors.New("empty active indices list")
}
maxRandomByte := uint64(1<<8 - 1)
hashFunc := hash.CustomSHA256Hasher()

for i := uint64(0); ; i++ {
Expand All @@ -860,7 +859,7 @@ func computeProposerIndexWithValidators(validators []*ethpb.Validator, activeInd
if v != nil {
effectiveBal = v.EffectiveBalance
}
if effectiveBal*maxRandomByte >= params.BeaconConfig().MaxEffectiveBalance*uint64(randomByte) {
if effectiveBal*fieldparams.MaxRandomByte >= params.BeaconConfig().MaxEffectiveBalance*uint64(randomByte) {
return candidateIndex, nil
}
}
Expand Down
1 change: 1 addition & 0 deletions beacon-chain/core/validators/validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ func TestSlashValidator_OK(t *testing.T) {
}

func TestSlashValidator_Electra(t *testing.T) {
helpers.ClearCache()
Copy link
Member Author

Choose a reason for hiding this comment

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

Running TestSlashValidator_Electra by itself passes but running the entire package will fail because previous test uses cache. This wasn't an issue before but now becomes an issue because shuffling is different after Electra

validatorCount := 100
registry := make([]*ethpb.Validator, 0, validatorCount)
balances := make([]uint64, 0, validatorCount)
Expand Down
1 change: 1 addition & 0 deletions beacon-chain/rpc/eth/events/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ go_test(
"//beacon-chain/core/feed/state:go_default_library",
"//beacon-chain/state:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//consensus-types/payload-attribute:go_default_library",
Expand Down
Loading
Loading