Compare commits

...

31 Commits

Author SHA1 Message Date
terence
6791dd2367 Remove inclusion list from epbs (#14188) 2024-07-15 13:20:12 -03:00
Potuz
a4d13611ad Enable validator client to submit payload attestation message (#14064) 2024-07-15 13:20:06 -03:00
Potuz
030bf62da3 Add PTC assignment support for Duty endpoint (#14032) 2024-07-15 13:14:41 -03:00
Potuz
fa6688c3ec use Keymanager() in validator client 2024-07-15 13:13:46 -03:00
Potuz
f5799372b6 Change gwei math to primitives package for ePBS state 2024-07-15 13:13:46 -03:00
terence
ab4a563bb1 Fix GetPayloadTimelinessCommittee to return correct PTC size (#14012) 2024-07-15 13:13:46 -03:00
Potuz
7badaf7b4d Add ePBS to db (#13971)
* Add ePBS to db
2024-07-15 13:13:46 -03:00
Potuz
572a9d3d65 Add EPBS slashing params 2024-07-15 13:13:17 -03:00
Potuz
02dce037dc Implement get_ptc
This implements a helper to get the ptc committee from a state. It uses
the cached beacon committees if possible

It also implements a helper to compute the largest power of two of a
uint64 and a helper to test for nil payload attestation messages
2024-07-15 13:13:17 -03:00
Potuz
f2a2189203 Add ePBS to state (#13926) 2024-07-15 13:13:17 -03:00
Potuz
173dcab20c Add testing utility methods to return randomly populated ePBS objects 2024-07-15 13:13:17 -03:00
Potuz
152612eaec Add ePBS stuff to consensus-types: block 2024-07-15 13:13:13 -03:00
Potuz
9c452a6b0e Helper for Payload Attestation Signing (#13901) 2024-07-15 13:12:09 -03:00
Potuz
720a9b7491 ePBS configuration constants 2024-07-15 13:10:48 -03:00
Potuz
0b9169f42c Add ePBS beacon state proto 2024-07-15 13:10:48 -03:00
Potuz
6dfbdad1aa Add protos for ePBS except state 2024-07-15 13:10:42 -03:00
Potuz
e5b25071f9 Fix effective balance updates in Electra (#14215) 2024-07-15 15:28:56 +00:00
terence
498ee635e1 Remove warning eip_7251.proto is unused (#14213) 2024-07-15 15:23:09 +00:00
Preston Van Loon
c238c00630 Electra: EIP-7251 implement process_withdrawal updates (#14181)
* Electra: EIP-7251 implement process_withdrawal updates

* Unit tests for new process_withdrawal logic in electra
2024-07-12 16:59:04 +00:00
Preston Van Loon
3eacc37831 Electra: Forkchoice spectest fix (#14180) 2024-07-12 16:50:29 +00:00
Potuz
5267b4b4d4 Fix Merkle proof generator for Electra (#14211) 2024-07-12 16:38:17 +00:00
Radosław Kapka
ec84a1b49c EIP-7549: Allow multiple committee bits (#14203) 2024-07-12 15:37:29 +00:00
james-prysm
afb7383225 adding electra version to payload attribute event (#14212) 2024-07-12 15:21:06 +00:00
Preston Van Loon
a00b40fa81 State: HasPendingBalanceToWithdraw (#14200)
* Implement HasPendingBalanceToWithdraw to improve the best / average case lookup

* Add tests for HasPendingBalanceToWithdraw
2024-07-11 20:31:08 +00:00
Radosław Kapka
365c6252ba EIP-7549: validator client (#14158)
* EIP-7549: validator client

* server code

* tests

* build fix

* review

* remove context

* Revert "Auxiliary commit to revert individual files from 16fed79a1ae0bbe4a08cb9819c2785d6e34958dd"

This reverts commit f59e1459f3f7561e0483bc8542110794951585c5.
2024-07-11 18:41:09 +00:00
kira
7c81c7da90 fix: Multiple network flags should prevent the BN to start (#14169)
* Implement Initial Logic

* Include check in main.go

* Add tests for multiple flags

* remove usage of append

* remove config/features dependency

* Move ValidateNetworkFlags to config/features

* Nit

* removed NetworkFlags from cmd

* remove usage of empty string literal

* add comment

* add flag validation to prysctl validator-exit

---------

Co-authored-by: Manu NALEPA <enalepa@offchainlabs.com>
2024-07-10 11:08:37 +00:00
Nishant Das
f8950c8c40 Avoid Cloning When Creating a New Gossip Message (#14201)
* Add Current Changes

* add back check

* Avoid a Panic
2024-07-10 05:51:41 +00:00
Preston Van Loon
18be899aef Electra: EIP-7251 Update process_voluntary_exit (#14176)
* Electra: EIP-7251 Update `process_voluntary_exit`

* Add unit test for VerifyExitAndSignature EIP-7251

* @potuz peer feedback
2024-07-09 20:13:48 +00:00
Nishant Das
9dc3b645c4 Optimize ProcessRegistryUpdates Further (#14197)
* Add it in

* Clean it Up
2024-07-09 12:41:07 +00:00
Potuz
318561999d copy just the pointer in the votes loop (#14196) 2024-07-08 23:47:29 +00:00
Preston Van Loon
ae5b0b4391 Electra: EIP-7251 update process_pending_balance_deposits (#14177)
* EIP-7251: Implement changes from https://github.com/ethereum/consensus-specs/pull/3776

* Unskip epoch processing spectest

* EIP-7251: unit tests for logic in https://github.com/ethereum/consensus-specs/pull/3776

* Radek feedback
2024-07-08 16:37:57 +00:00
165 changed files with 14382 additions and 3820 deletions

View File

@@ -98,6 +98,8 @@ func ProcessVoluntaryExits(
// assert get_current_epoch(state) >= voluntary_exit.epoch
// # Verify the validator has been active long enough
// assert get_current_epoch(state) >= validator.activation_epoch + SHARD_COMMITTEE_PERIOD
// # Only exit validator if it has no pending withdrawals in the queue
// assert get_pending_balance_to_withdraw(state, voluntary_exit.validator_index) == 0 # [New in Electra:EIP7251]
// # Verify signature
// domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, voluntary_exit.epoch)
// signing_root = compute_signing_root(voluntary_exit, domain)
@@ -113,7 +115,6 @@ func VerifyExitAndSignature(
return errors.New("nil exit")
}
currentSlot := state.Slot()
fork := state.Fork()
genesisRoot := state.GenesisValidatorsRoot()
@@ -128,7 +129,7 @@ func VerifyExitAndSignature(
}
exit := signed.Exit
if err := verifyExitConditions(validator, currentSlot, exit); err != nil {
if err := verifyExitConditions(state, validator, exit); err != nil {
return err
}
domain, err := signing.Domain(fork, exit.Epoch, params.BeaconConfig().DomainVoluntaryExit, genesisRoot)
@@ -157,14 +158,16 @@ func VerifyExitAndSignature(
// assert get_current_epoch(state) >= voluntary_exit.epoch
// # Verify the validator has been active long enough
// assert get_current_epoch(state) >= validator.activation_epoch + SHARD_COMMITTEE_PERIOD
// # Only exit validator if it has no pending withdrawals in the queue
// assert get_pending_balance_to_withdraw(state, voluntary_exit.validator_index) == 0 # [New in Electra:EIP7251]
// # Verify signature
// domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, voluntary_exit.epoch)
// signing_root = compute_signing_root(voluntary_exit, domain)
// assert bls.Verify(validator.pubkey, signing_root, signed_voluntary_exit.signature)
// # Initiate exit
// initiate_validator_exit(state, voluntary_exit.validator_index)
func verifyExitConditions(validator state.ReadOnlyValidator, currentSlot primitives.Slot, exit *ethpb.VoluntaryExit) error {
currentEpoch := slots.ToEpoch(currentSlot)
func verifyExitConditions(st state.ReadOnlyBeaconState, validator state.ReadOnlyValidator, exit *ethpb.VoluntaryExit) error {
currentEpoch := slots.ToEpoch(st.Slot())
// Verify the validator is active.
if !helpers.IsActiveValidatorUsingTrie(validator, currentEpoch) {
return errors.New("non-active validator cannot exit")
@@ -187,5 +190,17 @@ func verifyExitConditions(validator state.ReadOnlyValidator, currentSlot primiti
validator.ActivationEpoch()+params.BeaconConfig().ShardCommitteePeriod,
)
}
if st.Version() >= version.Electra {
// Only exit validator if it has no pending withdrawals in the queue.
ok, err := st.HasPendingBalanceToWithdraw(exit.ValidatorIndex)
if err != nil {
return fmt.Errorf("unable to retrieve pending balance to withdraw for validator %d: %w", exit.ValidatorIndex, err)
}
if ok {
return fmt.Errorf("validator %d must have no pending balance to withdraw", exit.ValidatorIndex)
}
}
return nil
}

View File

@@ -135,6 +135,11 @@ func TestProcessVoluntaryExits_AppliesCorrectStatus(t *testing.T) {
}
func TestVerifyExitAndSignature(t *testing.T) {
// Remove after electra fork epoch is defined.
cfg := params.BeaconConfig()
cfg.ElectraForkEpoch = cfg.DenebForkEpoch * 2
params.SetActiveTestCleanup(t, cfg)
// End remove section.
denebSlot, err := slots.EpochStart(params.BeaconConfig().DenebForkEpoch)
require.NoError(t, err)
tests := []struct {
@@ -167,7 +172,7 @@ func TestVerifyExitAndSignature(t *testing.T) {
wantErr: "nil exit",
},
{
name: "Happy Path",
name: "Happy Path phase0",
setup: func() (*ethpb.Validator, *ethpb.SignedVoluntaryExit, state.ReadOnlyBeaconState, error) {
fork := &ethpb.Fork{
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
@@ -275,6 +280,52 @@ func TestVerifyExitAndSignature(t *testing.T) {
return validator, signedExit, bs, nil
},
},
{
name: "EIP-7251 - pending balance to withdraw must be zero",
setup: func() (*ethpb.Validator, *ethpb.SignedVoluntaryExit, state.ReadOnlyBeaconState, error) {
fork := &ethpb.Fork{
PreviousVersion: params.BeaconConfig().DenebForkVersion,
CurrentVersion: params.BeaconConfig().ElectraForkVersion,
Epoch: params.BeaconConfig().ElectraForkEpoch,
}
signedExit := &ethpb.SignedVoluntaryExit{
Exit: &ethpb.VoluntaryExit{
Epoch: params.BeaconConfig().DenebForkEpoch + 1,
ValidatorIndex: 0,
},
}
electraSlot, err := slots.EpochStart(params.BeaconConfig().ElectraForkEpoch)
require.NoError(t, err)
bs, keys := util.DeterministicGenesisState(t, 1)
bs, err = state_native.InitializeFromProtoUnsafeElectra(&ethpb.BeaconStateElectra{
GenesisValidatorsRoot: bs.GenesisValidatorsRoot(),
Fork: fork,
Slot: electraSlot,
Validators: bs.Validators(),
})
if err != nil {
return nil, nil, nil, err
}
validator := bs.Validators()[0]
validator.ActivationEpoch = 1
err = bs.UpdateValidatorAtIndex(0, validator)
require.NoError(t, err)
sb, err := signing.ComputeDomainAndSign(bs, signedExit.Exit.Epoch, signedExit.Exit, params.BeaconConfig().DomainVoluntaryExit, keys[0])
require.NoError(t, err)
sig, err := bls.SignatureFromBytes(sb)
require.NoError(t, err)
signedExit.Signature = sig.Marshal()
// Give validator a pending balance to withdraw.
require.NoError(t, bs.AppendPendingPartialWithdrawal(&ethpb.PendingPartialWithdrawal{
Index: 0,
Amount: 500,
}))
return validator, signedExit, bs, nil
},
wantErr: "validator 0 must have no pending balance to withdraw",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

View File

@@ -120,32 +120,35 @@ func ValidateBLSToExecutionChange(st state.ReadOnlyBeaconState, signed *ethpb.Si
//
// Spec pseudocode definition:
//
// def process_withdrawals(state: BeaconState, payload: ExecutionPayload) -> None:
// def process_withdrawals(state: BeaconState, payload: ExecutionPayload) -> None:
// expected_withdrawals, partial_withdrawals_count = get_expected_withdrawals(state) # [Modified in Electra:EIP7251]
//
// expected_withdrawals = get_expected_withdrawals(state)
// assert len(payload.withdrawals) == len(expected_withdrawals)
// assert len(payload.withdrawals) == len(expected_withdrawals)
//
// for expected_withdrawal, withdrawal in zip(expected_withdrawals, payload.withdrawals):
// assert withdrawal == expected_withdrawal
// decrease_balance(state, withdrawal.validator_index, withdrawal.amount)
// for expected_withdrawal, withdrawal in zip(expected_withdrawals, payload.withdrawals):
// assert withdrawal == expected_withdrawal
// decrease_balance(state, withdrawal.validator_index, withdrawal.amount)
//
// # Update the next withdrawal index if this block contained withdrawals
// if len(expected_withdrawals) != 0:
// latest_withdrawal = expected_withdrawals[-1]
// state.next_withdrawal_index = WithdrawalIndex(latest_withdrawal.index + 1)
// # Update pending partial withdrawals [New in Electra:EIP7251]
// state.pending_partial_withdrawals = state.pending_partial_withdrawals[partial_withdrawals_count:]
//
// # Update the next validator index to start the next withdrawal sweep
// if len(expected_withdrawals) == MAX_WITHDRAWALS_PER_PAYLOAD:
// # Next sweep starts after the latest withdrawal's validator index
// next_validator_index = ValidatorIndex((expected_withdrawals[-1].validator_index + 1) % len(state.validators))
// state.next_withdrawal_validator_index = next_validator_index
// else:
// # Advance sweep by the max length of the sweep if there was not a full set of withdrawals
// next_index = state.next_withdrawal_validator_index + MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP
// next_validator_index = ValidatorIndex(next_index % len(state.validators))
// state.next_withdrawal_validator_index = next_validator_index
// # Update the next withdrawal index if this block contained withdrawals
// if len(expected_withdrawals) != 0:
// latest_withdrawal = expected_withdrawals[-1]
// state.next_withdrawal_index = WithdrawalIndex(latest_withdrawal.index + 1)
//
// # Update the next validator index to start the next withdrawal sweep
// if len(expected_withdrawals) == MAX_WITHDRAWALS_PER_PAYLOAD:
// # Next sweep starts after the latest withdrawal's validator index
// next_validator_index = ValidatorIndex((expected_withdrawals[-1].validator_index + 1) % len(state.validators))
// state.next_withdrawal_validator_index = next_validator_index
// else:
// # Advance sweep by the max length of the sweep if there was not a full set of withdrawals
// next_index = state.next_withdrawal_validator_index + MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP
// next_validator_index = ValidatorIndex(next_index % len(state.validators))
// state.next_withdrawal_validator_index = next_validator_index
func ProcessWithdrawals(st state.BeaconState, executionData interfaces.ExecutionData) (state.BeaconState, error) {
expectedWithdrawals, _, err := st.ExpectedWithdrawals()
expectedWithdrawals, partialWithdrawalsCount, err := st.ExpectedWithdrawals()
if err != nil {
return nil, errors.Wrap(err, "could not get expected withdrawals")
}
@@ -162,6 +165,11 @@ func ProcessWithdrawals(st state.BeaconState, executionData interfaces.Execution
if err != nil {
return nil, errors.Wrap(err, "could not get withdrawals")
}
if len(wds) != len(expectedWithdrawals) {
return nil, fmt.Errorf("execution payload header has %d withdrawals when %d were expected", len(wds), len(expectedWithdrawals))
}
wdRoot, err = ssz.WithdrawalSliceRoot(wds, fieldparams.MaxWithdrawalsPerPayload)
if err != nil {
return nil, errors.Wrap(err, "could not get withdrawals root")
@@ -182,6 +190,13 @@ func ProcessWithdrawals(st state.BeaconState, executionData interfaces.Execution
return nil, errors.Wrap(err, "could not decrease balance")
}
}
if st.Version() >= version.Electra {
if err := st.DequeuePartialWithdrawals(partialWithdrawalsCount); err != nil {
return nil, fmt.Errorf("unable to dequeue partial withdrawals from state: %w", err)
}
}
if len(expectedWithdrawals) > 0 {
if err := st.SetNextWithdrawalIndex(expectedWithdrawals[len(expectedWithdrawals)-1].Index + 1); err != nil {
return nil, errors.Wrap(err, "could not set next withdrawal index")

View File

@@ -12,6 +12,7 @@ import (
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/config/params"
consensusblocks "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/crypto/bls"
"github.com/prysmaticlabs/prysm/v5/crypto/bls/common"
@@ -19,6 +20,7 @@ import (
"github.com/prysmaticlabs/prysm/v5/encoding/ssz"
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/prysmaticlabs/prysm/v5/testing/require"
"github.com/prysmaticlabs/prysm/v5/time/slots"
)
@@ -675,6 +677,7 @@ func TestProcessWithdrawals(t *testing.T) {
FullWithdrawalIndices []primitives.ValidatorIndex
PendingPartialWithdrawalIndices []primitives.ValidatorIndex
Withdrawals []*enginev1.Withdrawal
PendingPartialWithdrawals []*ethpb.PendingPartialWithdrawal // Electra
}
type control struct {
NextWithdrawalValidatorIndex primitives.ValidatorIndex
@@ -772,7 +775,7 @@ func TestProcessWithdrawals(t *testing.T) {
},
{
Args: args{
Name: "Less than max sweep at end",
Name: "less than max sweep at end",
NextWithdrawalIndex: 22,
NextWithdrawalValidatorIndex: 4,
FullWithdrawalIndices: []primitives.ValidatorIndex{80, 81, 82, 83},
@@ -789,7 +792,7 @@ func TestProcessWithdrawals(t *testing.T) {
},
{
Args: args{
Name: "Less than max sweep and beginning",
Name: "less than max sweep and beginning",
NextWithdrawalIndex: 22,
NextWithdrawalValidatorIndex: 4,
FullWithdrawalIndices: []primitives.ValidatorIndex{4, 5, 6},
@@ -846,6 +849,36 @@ func TestProcessWithdrawals(t *testing.T) {
},
},
},
{
Args: args{
Name: "success many withdrawals with pending partial withdrawals in state",
NextWithdrawalIndex: 22,
NextWithdrawalValidatorIndex: 88,
FullWithdrawalIndices: []primitives.ValidatorIndex{7, 19, 28},
PendingPartialWithdrawalIndices: []primitives.ValidatorIndex{2, 1, 89, 15},
Withdrawals: []*enginev1.Withdrawal{
PendingPartialWithdrawal(89, 22), PendingPartialWithdrawal(1, 23), PendingPartialWithdrawal(2, 24),
fullWithdrawal(7, 25), PendingPartialWithdrawal(15, 26), fullWithdrawal(19, 27),
fullWithdrawal(28, 28),
},
PendingPartialWithdrawals: []*ethpb.PendingPartialWithdrawal{
{
Index: 11,
Amount: withdrawalAmount(11) - maxEffectiveBalance,
},
},
},
Control: control{
NextWithdrawalValidatorIndex: 40,
NextWithdrawalIndex: 29,
Balances: map[uint64]uint64{
7: 0, 19: 0, 28: 0,
2: maxEffectiveBalance, 1: maxEffectiveBalance, 89: maxEffectiveBalance,
15: maxEffectiveBalance,
},
},
},
{
Args: args{
Name: "success more than max fully withdrawals",
@@ -1011,65 +1044,97 @@ func TestProcessWithdrawals(t *testing.T) {
}
}
prepareValidators := func(st *ethpb.BeaconStateCapella, arguments args) (state.BeaconState, error) {
prepareValidators := func(st state.BeaconState, arguments args) error {
validators := make([]*ethpb.Validator, numValidators)
st.Balances = make([]uint64, numValidators)
if err := st.SetBalances(make([]uint64, numValidators)); err != nil {
return err
}
for i := range validators {
v := &ethpb.Validator{}
v.EffectiveBalance = maxEffectiveBalance
v.WithdrawableEpoch = epochInFuture
v.WithdrawalCredentials = make([]byte, 32)
v.WithdrawalCredentials[31] = byte(i)
st.Balances[i] = v.EffectiveBalance - uint64(rand.Intn(1000))
if err := st.UpdateBalancesAtIndex(primitives.ValidatorIndex(i), v.EffectiveBalance-uint64(rand.Intn(1000))); err != nil {
return err
}
validators[i] = v
}
for _, idx := range arguments.FullWithdrawalIndices {
if idx != notWithdrawableIndex {
validators[idx].WithdrawableEpoch = epochInPast
}
st.Balances[idx] = withdrawalAmount(idx)
if err := st.UpdateBalancesAtIndex(idx, withdrawalAmount(idx)); err != nil {
return err
}
validators[idx].WithdrawalCredentials[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
}
for _, idx := range arguments.PendingPartialWithdrawalIndices {
validators[idx].WithdrawalCredentials[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
st.Balances[idx] = withdrawalAmount(idx)
if err := st.UpdateBalancesAtIndex(idx, withdrawalAmount(idx)); err != nil {
return err
}
}
st.Validators = validators
return state_native.InitializeFromProtoCapella(st)
return st.SetValidators(validators)
}
for _, test := range tests {
t.Run(test.Args.Name, func(t *testing.T) {
saved := params.BeaconConfig().MaxValidatorsPerWithdrawalsSweep
params.BeaconConfig().MaxValidatorsPerWithdrawalsSweep = maxSweep
if test.Args.Withdrawals == nil {
test.Args.Withdrawals = make([]*enginev1.Withdrawal, 0)
for _, fork := range []int{version.Capella, version.Electra} {
t.Run(version.String(fork), func(t *testing.T) {
saved := params.BeaconConfig().MaxValidatorsPerWithdrawalsSweep
params.BeaconConfig().MaxValidatorsPerWithdrawalsSweep = maxSweep
if test.Args.Withdrawals == nil {
test.Args.Withdrawals = make([]*enginev1.Withdrawal, 0)
}
if test.Args.FullWithdrawalIndices == nil {
test.Args.FullWithdrawalIndices = make([]primitives.ValidatorIndex, 0)
}
if test.Args.PendingPartialWithdrawalIndices == nil {
test.Args.PendingPartialWithdrawalIndices = make([]primitives.ValidatorIndex, 0)
}
slot, err := slots.EpochStart(currentEpoch)
require.NoError(t, err)
var st state.BeaconState
var p interfaces.ExecutionData
switch fork {
case version.Capella:
spb := &ethpb.BeaconStateCapella{
Slot: slot,
NextWithdrawalValidatorIndex: test.Args.NextWithdrawalValidatorIndex,
NextWithdrawalIndex: test.Args.NextWithdrawalIndex,
}
st, err = state_native.InitializeFromProtoUnsafeCapella(spb)
require.NoError(t, err)
p, err = consensusblocks.WrappedExecutionPayloadCapella(&enginev1.ExecutionPayloadCapella{Withdrawals: test.Args.Withdrawals})
require.NoError(t, err)
case version.Electra:
spb := &ethpb.BeaconStateElectra{
Slot: slot,
NextWithdrawalValidatorIndex: test.Args.NextWithdrawalValidatorIndex,
NextWithdrawalIndex: test.Args.NextWithdrawalIndex,
PendingPartialWithdrawals: test.Args.PendingPartialWithdrawals,
}
st, err = state_native.InitializeFromProtoUnsafeElectra(spb)
require.NoError(t, err)
p, err = consensusblocks.WrappedExecutionPayloadElectra(&enginev1.ExecutionPayloadElectra{Withdrawals: test.Args.Withdrawals})
require.NoError(t, err)
default:
t.Fatalf("Add a beacon state setup for version %s", version.String(fork))
}
err = prepareValidators(st, test.Args)
require.NoError(t, err)
post, err := blocks.ProcessWithdrawals(st, p)
if test.Control.ExpectedError {
require.NotNil(t, err)
} else {
require.NoError(t, err)
checkPostState(t, test.Control, post)
}
params.BeaconConfig().MaxValidatorsPerWithdrawalsSweep = saved
})
}
if test.Args.FullWithdrawalIndices == nil {
test.Args.FullWithdrawalIndices = make([]primitives.ValidatorIndex, 0)
}
if test.Args.PendingPartialWithdrawalIndices == nil {
test.Args.PendingPartialWithdrawalIndices = make([]primitives.ValidatorIndex, 0)
}
slot, err := slots.EpochStart(currentEpoch)
require.NoError(t, err)
spb := &ethpb.BeaconStateCapella{
Slot: slot,
NextWithdrawalValidatorIndex: test.Args.NextWithdrawalValidatorIndex,
NextWithdrawalIndex: test.Args.NextWithdrawalIndex,
}
st, err := prepareValidators(spb, test.Args)
require.NoError(t, err)
p, err := consensusblocks.WrappedExecutionPayloadCapella(&enginev1.ExecutionPayloadCapella{Withdrawals: test.Args.Withdrawals})
require.NoError(t, err)
post, err := blocks.ProcessWithdrawals(st, p)
if test.Control.ExpectedError {
require.NotNil(t, err)
} else {
require.NoError(t, err)
checkPostState(t, test.Control, post)
}
params.BeaconConfig().MaxValidatorsPerWithdrawalsSweep = saved
})
}
}

View File

@@ -2,6 +2,7 @@ package electra
import (
"context"
"fmt"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/blocks"
@@ -13,7 +14,9 @@ import (
"github.com/prysmaticlabs/prysm/v5/contracts/deposit"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/time/slots"
log "github.com/sirupsen/logrus"
"go.opencensus.io/trace"
)
@@ -190,12 +193,27 @@ func verifyDepositDataSigningRoot(obj *ethpb.Deposit_Data, domain []byte) error
// available_for_processing = state.deposit_balance_to_consume + get_activation_exit_churn_limit(state)
// processed_amount = 0
// next_deposit_index = 0
// deposits_to_postpone = []
//
// for deposit in state.pending_balance_deposits:
// if processed_amount + deposit.amount > available_for_processing:
// break
// increase_balance(state, deposit.index, deposit.amount)
// processed_amount += deposit.amount
// validator = state.validators[deposit.index]
// # Validator is exiting, postpone the deposit until after withdrawable epoch
// if validator.exit_epoch < FAR_FUTURE_EPOCH:
// if get_current_epoch(state) <= validator.withdrawable_epoch:
// deposits_to_postpone.append(deposit)
// # Deposited balance will never become active. Increase balance but do not consume churn
// else:
// increase_balance(state, deposit.index, deposit.amount)
// # Validator is not exiting, attempt to process deposit
// else:
// # Deposit does not fit in the churn, no more deposit processing in this epoch.
// if processed_amount + deposit.amount > available_for_processing:
// break
// # Deposit fits in the churn, process it. Increase balance and consume churn.
// else:
// increase_balance(state, deposit.index, deposit.amount)
// processed_amount += deposit.amount
// # Regardless of how the deposit was handled, we move on in the queue.
// next_deposit_index += 1
//
// state.pending_balance_deposits = state.pending_balance_deposits[next_deposit_index:]
@@ -204,6 +222,8 @@ func verifyDepositDataSigningRoot(obj *ethpb.Deposit_Data, domain []byte) error
// state.deposit_balance_to_consume = Gwei(0)
// else:
// state.deposit_balance_to_consume = available_for_processing - processed_amount
//
// state.pending_balance_deposits += deposits_to_postpone
func ProcessPendingBalanceDeposits(ctx context.Context, st state.BeaconState, activeBalance primitives.Gwei) error {
_, span := trace.StartSpan(ctx, "electra.ProcessPendingBalanceDeposits")
defer span.End()
@@ -216,35 +236,69 @@ func ProcessPendingBalanceDeposits(ctx context.Context, st state.BeaconState, ac
if err != nil {
return err
}
availableForProcessing := depBalToConsume + helpers.ActivationExitChurnLimit(activeBalance)
processedAmount := uint64(0)
nextDepositIndex := 0
var depositsToPostpone []*eth.PendingBalanceDeposit
deposits, err := st.PendingBalanceDeposits()
if err != nil {
return err
}
// constants
ffe := params.BeaconConfig().FarFutureEpoch
curEpoch := slots.ToEpoch(st.Slot())
for _, balanceDeposit := range deposits {
if primitives.Gwei(balanceDeposit.Amount) > availableForProcessing {
break
v, err := st.ValidatorAtIndexReadOnly(balanceDeposit.Index)
if err != nil {
return fmt.Errorf("failed to fetch validator at index: %w", err)
}
if err := helpers.IncreaseBalance(st, balanceDeposit.Index, balanceDeposit.Amount); err != nil {
return err
// If the validator is currently exiting, postpone the deposit until after the withdrawable
// epoch.
if v.ExitEpoch() < ffe {
if curEpoch <= v.WithdrawableEpoch() {
depositsToPostpone = append(depositsToPostpone, balanceDeposit)
} else {
// The deposited balance will never become active. Therefore, we increase the balance but do
// not consume the churn.
if err := helpers.IncreaseBalance(st, balanceDeposit.Index, balanceDeposit.Amount); err != nil {
return err
}
}
} else {
// Validator is not exiting, attempt to process deposit.
if primitives.Gwei(processedAmount+balanceDeposit.Amount) > availableForProcessing {
break
}
// Deposit fits in churn, process it. Increase balance and consume churn.
if err := helpers.IncreaseBalance(st, balanceDeposit.Index, balanceDeposit.Amount); err != nil {
return err
}
processedAmount += balanceDeposit.Amount
}
availableForProcessing -= primitives.Gwei(balanceDeposit.Amount)
// Regardless of how the deposit was handled, we move on in the queue.
nextDepositIndex++
}
deposits = deposits[nextDepositIndex:]
// Combined operation:
// - state.pending_balance_deposits = state.pending_balance_deposits[next_deposit_index:]
// - state.pending_balance_deposits += deposits_to_postpone
// However, the number of remaining deposits must be maintained to properly update the deposit
// balance to consume.
numRemainingDeposits := len(deposits[nextDepositIndex:])
deposits = append(deposits[nextDepositIndex:], depositsToPostpone...)
if err := st.SetPendingBalanceDeposits(deposits); err != nil {
return err
}
if len(deposits) == 0 {
if numRemainingDeposits == 0 {
return st.SetDepositBalanceToConsume(0)
} else {
return st.SetDepositBalanceToConsume(availableForProcessing)
return st.SetDepositBalanceToConsume(availableForProcessing - primitives.Gwei(processedAmount))
}
}

View File

@@ -107,6 +107,80 @@ func TestProcessPendingBalanceDeposits(t *testing.T) {
require.Equal(t, params.BeaconConfig().MinActivationBalance+uint64(amountAvailForProcessing)/5, b)
}
// All of the balance deposits should have been processed.
remaining, err := st.PendingBalanceDeposits()
require.NoError(t, err)
require.Equal(t, 0, len(remaining))
},
},
{
name: "exiting validator deposit postponed",
state: func() state.BeaconState {
st := stateWithActiveBalanceETH(t, 1_000)
require.NoError(t, st.SetDepositBalanceToConsume(0))
amountAvailForProcessing := helpers.ActivationExitChurnLimit(1_000 * 1e9)
deps := make([]*eth.PendingBalanceDeposit, 5)
for i := 0; i < len(deps); i += 1 {
deps[i] = &eth.PendingBalanceDeposit{
Amount: uint64(amountAvailForProcessing) / 5,
Index: primitives.ValidatorIndex(i),
}
}
require.NoError(t, st.SetPendingBalanceDeposits(deps))
v, err := st.ValidatorAtIndex(0)
require.NoError(t, err)
v.ExitEpoch = 10
v.WithdrawableEpoch = 20
require.NoError(t, st.UpdateValidatorAtIndex(0, v))
return st
}(),
check: func(t *testing.T, st state.BeaconState) {
amountAvailForProcessing := helpers.ActivationExitChurnLimit(1_000 * 1e9)
res, err := st.DepositBalanceToConsume()
require.NoError(t, err)
require.Equal(t, primitives.Gwei(0), res)
// Validators 1..4 should have their balance increased
for i := primitives.ValidatorIndex(1); i < 4; i++ {
b, err := st.BalanceAtIndex(i)
require.NoError(t, err)
require.Equal(t, params.BeaconConfig().MinActivationBalance+uint64(amountAvailForProcessing)/5, b)
}
// All of the balance deposits should have been processed, except validator index 0 was
// added back to the pending deposits queue.
remaining, err := st.PendingBalanceDeposits()
require.NoError(t, err)
require.Equal(t, 1, len(remaining))
},
},
{
name: "exited validator balance increased",
state: func() state.BeaconState {
st := stateWithActiveBalanceETH(t, 1_000)
deps := make([]*eth.PendingBalanceDeposit, 1)
for i := 0; i < len(deps); i += 1 {
deps[i] = &eth.PendingBalanceDeposit{
Amount: 1_000_000,
Index: primitives.ValidatorIndex(i),
}
}
require.NoError(t, st.SetPendingBalanceDeposits(deps))
v, err := st.ValidatorAtIndex(0)
require.NoError(t, err)
v.ExitEpoch = 2
v.WithdrawableEpoch = 8
require.NoError(t, st.UpdateValidatorAtIndex(0, v))
require.NoError(t, st.UpdateBalancesAtIndex(0, 100_000))
return st
}(),
check: func(t *testing.T, st state.BeaconState) {
res, err := st.DepositBalanceToConsume()
require.NoError(t, err)
require.Equal(t, primitives.Gwei(0), res)
b, err := st.BalanceAtIndex(0)
require.NoError(t, err)
require.Equal(t, uint64(1_100_000), b)
// All of the balance deposits should have been processed.
remaining, err := st.PendingBalanceDeposits()
require.NoError(t, err)

View File

@@ -56,7 +56,7 @@ func ProcessEffectiveBalanceUpdates(state state.BeaconState) error {
if balance+downwardThreshold < val.EffectiveBalance || val.EffectiveBalance+upwardThreshold < balance {
effectiveBal := min(balance-balance%effBalanceInc, effectiveBalanceLimit)
val.EffectiveBalance = effectiveBal
return false, val, nil
return true, val, nil
}
return false, val, nil
}

View File

@@ -58,7 +58,7 @@ func ProcessRegistryUpdates(ctx context.Context, st state.BeaconState) error {
}
// Collect validators eligible for activation and not yet dequeued for activation.
if helpers.IsEligibleForActivationUsingTrie(st, val) {
if helpers.IsEligibleForActivationUsingROVal(st, val) {
eligibleForActivation = append(eligibleForActivation, primitives.ValidatorIndex(idx))
}

View File

@@ -26,66 +26,67 @@ import (
//
// def process_withdrawal_request(
//
// state: BeaconState,
// withdrawal_request: WithdrawalRequest
// state: BeaconState,
// withdrawal_request: WithdrawalRequest
//
// ) -> None:
// amount = execution_layer_withdrawal_request.amount
// is_full_exit_request = amount == FULL_EXIT_REQUEST_AMOUNT
// ) -> None:
//
// # If partial withdrawal queue is full, only full exits are processed
// if len(state.pending_partial_withdrawals) == PENDING_PARTIAL_WITHDRAWALS_LIMIT and not is_full_exit_request:
// return
// amount = withdrawal_request.amount
// is_full_exit_request = amount == FULL_EXIT_REQUEST_AMOUNT
//
// validator_pubkeys = [v.pubkey for v in state.validators]
// # Verify pubkey exists
// request_pubkey = execution_layer_withdrawal_request.validator_pubkey
// if request_pubkey not in validator_pubkeys:
// return
// index = ValidatorIndex(validator_pubkeys.index(request_pubkey))
// validator = state.validators[index]
// # If partial withdrawal queue is full, only full exits are processed
// if len(state.pending_partial_withdrawals) == PENDING_PARTIAL_WITHDRAWALS_LIMIT and not is_full_exit_request:
// return
//
// # Verify withdrawal credentials
// has_correct_credential = has_execution_withdrawal_credential(validator)
// is_correct_source_address = (
// validator.withdrawal_credentials[12:] == execution_layer_withdrawal_request.source_address
// )
// if not (has_correct_credential and is_correct_source_address):
// return
// # Verify the validator is active
// if not is_active_validator(validator, get_current_epoch(state)):
// return
// # Verify exit has not been initiated
// if validator.exit_epoch != FAR_FUTURE_EPOCH:
// return
// # Verify the validator has been active long enough
// if get_current_epoch(state) < validator.activation_epoch + SHARD_COMMITTEE_PERIOD:
// return
// validator_pubkeys = [v.pubkey for v in state.validators]
// # Verify pubkey exists
// request_pubkey = withdrawal_request.validator_pubkey
// if request_pubkey not in validator_pubkeys:
// return
// index = ValidatorIndex(validator_pubkeys.index(request_pubkey))
// validator = state.validators[index]
//
// pending_balance_to_withdraw = get_pending_balance_to_withdraw(state, index)
// # Verify withdrawal credentials
// has_correct_credential = has_execution_withdrawal_credential(validator)
// is_correct_source_address = (
// validator.withdrawal_credentials[12:] == withdrawal_request.source_address
// )
// if not (has_correct_credential and is_correct_source_address):
// return
// # Verify the validator is active
// if not is_active_validator(validator, get_current_epoch(state)):
// return
// # Verify exit has not been initiated
// if validator.exit_epoch != FAR_FUTURE_EPOCH:
// return
// # Verify the validator has been active long enough
// if get_current_epoch(state) < validator.activation_epoch + SHARD_COMMITTEE_PERIOD:
// return
//
// if is_full_exit_request:
// # Only exit validator if it has no pending withdrawals in the queue
// if pending_balance_to_withdraw == 0:
// initiate_validator_exit(state, index)
// return
// pending_balance_to_withdraw = get_pending_balance_to_withdraw(state, index)
//
// has_sufficient_effective_balance = validator.effective_balance >= MIN_ACTIVATION_BALANCE
// has_excess_balance = state.balances[index] > MIN_ACTIVATION_BALANCE + pending_balance_to_withdraw
// if is_full_exit_request:
// # Only exit validator if it has no pending withdrawals in the queue
// if pending_balance_to_withdraw == 0:
// initiate_validator_exit(state, index)
// return
//
// # Only allow partial withdrawals with compounding withdrawal credentials
// if has_compounding_withdrawal_credential(validator) and has_sufficient_effective_balance and has_excess_balance:
// to_withdraw = min(
// state.balances[index] - MIN_ACTIVATION_BALANCE - pending_balance_to_withdraw,
// amount
// )
// exit_queue_epoch = compute_exit_epoch_and_update_churn(state, to_withdraw)
// withdrawable_epoch = Epoch(exit_queue_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY)
// state.pending_partial_withdrawals.append(PendingPartialWithdrawal(
// index=index,
// amount=to_withdraw,
// withdrawable_epoch=withdrawable_epoch,
// ))
// has_sufficient_effective_balance = validator.effective_balance >= MIN_ACTIVATION_BALANCE
// has_excess_balance = state.balances[index] > MIN_ACTIVATION_BALANCE + pending_balance_to_withdraw
//
// # Only allow partial withdrawals with compounding withdrawal credentials
// if has_compounding_withdrawal_credential(validator) and has_sufficient_effective_balance and has_excess_balance:
// to_withdraw = min(
// state.balances[index] - MIN_ACTIVATION_BALANCE - pending_balance_to_withdraw,
// amount
// )
// exit_queue_epoch = compute_exit_epoch_and_update_churn(state, to_withdraw)
// withdrawable_epoch = Epoch(exit_queue_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY)
// state.pending_partial_withdrawals.append(PendingPartialWithdrawal(
// index=index,
// amount=to_withdraw,
// withdrawable_epoch=withdrawable_epoch,
// ))
func ProcessWithdrawalRequests(ctx context.Context, st state.BeaconState, wrs []*enginev1.WithdrawalRequest) (state.BeaconState, error) {
ctx, span := trace.StartSpan(ctx, "electra.ProcessWithdrawalRequests")
defer span.End()

View File

@@ -96,7 +96,7 @@ func ProcessRegistryUpdates(ctx context.Context, st state.BeaconState) (state.Be
}
// Collect validators eligible for activation and not yet dequeued for activation.
if helpers.IsEligibleForActivationUsingTrie(st, val) {
if helpers.IsEligibleForActivationUsingROVal(st, val) {
eligibleForActivation = append(eligibleForActivation, primitives.ValidatorIndex(idx))
}

View File

@@ -8,6 +8,7 @@ go_library(
"block.go",
"genesis.go",
"metrics.go",
"payload_attestation.go",
"randao.go",
"rewards_penalties.go",
"shuffle.go",
@@ -53,6 +54,8 @@ go_test(
"attestation_test.go",
"beacon_committee_test.go",
"block_test.go",
"exports_test.go",
"payload_attestation_test.go",
"private_access_fuzz_noop_test.go", # keep
"private_access_test.go",
"randao_test.go",
@@ -78,10 +81,13 @@ go_test(
"//container/slice:go_default_library",
"//crypto/hash:go_default_library",
"//encoding/bytesutil:go_default_library",
"//math:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//runtime/version:go_default_library",
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
"//testing/util:go_default_library",
"//testing/util/random:go_default_library",
"//time:go_default_library",
"//time/slots:go_default_library",
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",

View File

@@ -172,6 +172,7 @@ type CommitteeAssignment struct {
Committee []primitives.ValidatorIndex
AttesterSlot primitives.Slot
CommitteeIndex primitives.CommitteeIndex
PtcSlot primitives.Slot
}
// verifyAssignmentEpoch verifies if the given epoch is valid for assignment based on the provided state.
@@ -274,6 +275,8 @@ func CommitteeAssignments(ctx context.Context, state state.BeaconState, epoch pr
vals[v] = struct{}{}
}
ptcPerSlot, PtcMembersPerCommittee := PtcAllocation(activeValidatorCount)
// Compute committee assignments for each slot in the epoch.
for slot := startSlot; slot < startSlot+params.BeaconConfig().SlotsPerEpoch; slot++ {
// Compute committees for the current slot.
@@ -294,12 +297,53 @@ func CommitteeAssignments(ctx context.Context, state state.BeaconState, epoch pr
assignments[vIndex].AttesterSlot = slot
assignments[vIndex].CommitteeIndex = primitives.CommitteeIndex(j)
}
// We only need to assign PTC slots for the first `PTCPerSlot` committees of a given slot.
if j < ptcPerSlot {
assignments = PTCAssignments(committee, assignments, PtcMembersPerCommittee, slot)
}
}
}
return assignments, nil
}
// PTCAssignments updates the PTC slot assignments for the given committee members.
// committee: a slice of ValidatorIndex representing committee members.
// assignments: a map of ValidatorIndex to CommitteeAssignment where assignments will be updated.
// membersPerCommittee: the number of members to be assigned to the PTC committee.
// slot: the slot to be assigned for PTC assignment.
// Returns the updated assignments map.
func PTCAssignments(committee []primitives.ValidatorIndex,
assignments map[primitives.ValidatorIndex]*CommitteeAssignment,
membersPerCommittee uint64,
slot primitives.Slot) map[primitives.ValidatorIndex]*CommitteeAssignment {
committeeLength := uint64(len(committee))
// If the number of PTC members is greater than Beacon members,
// return the current assignments without changes.
if membersPerCommittee > committeeLength {
return assignments
}
// Calculate the starting index for PTC committee.
ptcStartIndex := committeeLength - membersPerCommittee
// Loop through the selected committee members for PTC assignments.
for i := ptcStartIndex; i < committeeLength; i++ {
vIndex := committee[i]
assignment, exists := assignments[vIndex]
if !exists {
assignment = &CommitteeAssignment{}
assignments[vIndex] = assignment
}
assignment.PtcSlot = slot
}
return assignments
}
// VerifyBitfieldLength verifies that a bitfield length matches the given committee size.
func VerifyBitfieldLength(bf bitfield.Bitfield, committeeSize uint64) error {
if bf.Len() != committeeSize {

View File

@@ -3,6 +3,7 @@ package helpers_test
import (
"context"
"fmt"
"slices"
"strconv"
"testing"
@@ -10,6 +11,7 @@ import (
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time"
state_native "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native"
field_params "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/container/slice"
@@ -716,15 +718,26 @@ func TestCommitteeIndices(t *testing.T) {
assert.DeepEqual(t, []primitives.CommitteeIndex{0, 1, 3}, indices)
}
func TestAttestationCommittees(t *testing.T) {
validators := make([]*ethpb.Validator, params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().TargetCommitteeSize))
func TestCommitteeAssignments_PTC(t *testing.T) {
helpers.ClearCache()
// Create 10 committees. Total 40960 validators.
committeeCount := uint64(10)
validatorCount := committeeCount * params.BeaconConfig().TargetCommitteeSize * uint64(params.BeaconConfig().SlotsPerEpoch)
validators := make([]*ethpb.Validator, validatorCount)
validatorIndices := make([]primitives.ValidatorIndex, validatorCount)
for i := 0; i < len(validators); i++ {
k := make([]byte, 48)
copy(k, strconv.Itoa(i))
validators[i] = &ethpb.Validator{
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
PublicKey: k,
WithdrawalCredentials: make([]byte, 32),
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
}
validatorIndices[i] = primitives.ValidatorIndex(i)
}
state, err := state_native.InitializeFromProtoPhase0(&ethpb.BeaconState{
state, err := state_native.InitializeFromProtoEpbs(&ethpb.BeaconStateEPBS{
Validators: validators,
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
})
@@ -748,4 +761,29 @@ func TestAttestationCommittees(t *testing.T) {
assert.Equal(t, params.BeaconConfig().TargetCommitteeSize, uint64(len(committees[0])))
assert.Equal(t, params.BeaconConfig().TargetCommitteeSize, uint64(len(committees[1])))
})
as, err := helpers.CommitteeAssignments(context.Background(), state, 1, validatorIndices)
require.NoError(t, err)
// Capture all the slots and all the validator index that belonged in a PTC using a map for verification later.
slotValidatorMap := make(map[primitives.Slot][]primitives.ValidatorIndex)
for i, a := range as {
slotValidatorMap[a.PtcSlot] = append(slotValidatorMap[a.PtcSlot], i)
}
// Verify that all the slots have the correct number of PTC.
for s, v := range slotValidatorMap {
if s == 0 {
continue
}
// Make sure all the PTC are the correct size from the map.
require.Equal(t, len(v), field_params.PTCSize)
// Get the actual PTC from the beacon state using the helper function
ptc, err := helpers.GetPayloadTimelinessCommittee(context.Background(), state, s)
require.NoError(t, err)
for _, index := range ptc {
i := slices.Index(v, index)
require.NotEqual(t, -1, i) // PTC not found from the assignment map
}
}
}

View File

@@ -0,0 +1,12 @@
package helpers
var (
ErrNilMessage = errNilMessage
ErrNilData = errNilData
ErrNilBeaconBlockRoot = errNilBeaconBlockRoot
ErrNilPayloadAttestation = errNilPayloadAttestation
ErrNilSignature = errNilSignature
ErrNilAggregationBits = errNilAggregationBits
ErrPreEPBSState = errPreEPBSState
ErrCommitteeOverflow = errCommitteeOverflow
)

View File

@@ -0,0 +1,100 @@
package helpers
import (
"context"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/math"
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/prysmaticlabs/prysm/v5/time/slots"
)
var (
errNilMessage = errors.New("nil PayloadAttestationMessage")
errNilData = errors.New("nil PayloadAttestationData")
errNilBeaconBlockRoot = errors.New("nil BeaconBlockRoot")
errNilPayloadAttestation = errors.New("nil PayloadAttestation")
errNilSignature = errors.New("nil Signature")
errNilAggregationBits = errors.New("nil AggregationBits")
errPreEPBSState = errors.New("beacon state pre ePBS fork")
errCommitteeOverflow = errors.New("beacon committee of insufficient size")
)
// ValidateNilPayloadAttestationData checks if any composite field of the
// payload attestation data is nil
func ValidateNilPayloadAttestationData(data *eth.PayloadAttestationData) error {
if data == nil {
return errNilData
}
if data.BeaconBlockRoot == nil {
return errNilBeaconBlockRoot
}
return nil
}
// ValidateNilPayloadAttestationMessage checks if any composite field of the
// payload attestation message is nil
func ValidateNilPayloadAttestationMessage(att *eth.PayloadAttestationMessage) error {
if att == nil {
return errNilMessage
}
if att.Signature == nil {
return errNilSignature
}
return ValidateNilPayloadAttestationData(att.Data)
}
// ValidateNilPayloadAttestation checks if any composite field of the
// payload attestation is nil
func ValidateNilPayloadAttestation(att *eth.PayloadAttestation) error {
if att == nil {
return errNilPayloadAttestation
}
if att.AggregationBits == nil {
return errNilAggregationBits
}
if att.Signature == nil {
return errNilSignature
}
return ValidateNilPayloadAttestationData(att.Data)
}
// GetPayloadTimelinessCommittee returns the PTC for the given slot, computed from the passed state as in the
// spec function `get_ptc`.
func GetPayloadTimelinessCommittee(ctx context.Context, state state.ReadOnlyBeaconState, slot primitives.Slot) (indices []primitives.ValidatorIndex, err error) {
if state.Version() < version.EPBS {
return nil, errPreEPBSState
}
epoch := slots.ToEpoch(slot)
activeCount, err := ActiveValidatorCount(ctx, state, epoch)
if err != nil {
return nil, errors.Wrap(err, "could not compute active validator count")
}
committeesPerSlot, membersPerCommittee := PtcAllocation(activeCount)
for i := uint64(0); i < committeesPerSlot; i++ {
committee, err := BeaconCommitteeFromState(ctx, state, slot, primitives.CommitteeIndex(i))
if err != nil {
return nil, err
}
if uint64(len(committee)) < membersPerCommittee {
return nil, errCommitteeOverflow
}
start := uint64(len(committee)) - membersPerCommittee
indices = append(indices, committee[start:]...)
}
return
}
// PtcAllocation returns:
// 1. The number of beacon committees that PTC will borrow from in a slot.
// 2. The number of validators that PTC will borrow from in a beacon committee.
func PtcAllocation(totalActive uint64) (committeesPerSlot, membersPerCommittee uint64) {
slotCommittees := SlotCommitteeCount(totalActive)
committeesPerSlot = math.LargestPowerOfTwo(math.Min(slotCommittees, fieldparams.PTCSize))
membersPerCommittee = fieldparams.PTCSize / committeesPerSlot
return
}

View File

@@ -0,0 +1,117 @@
package helpers_test
import (
"context"
"strconv"
"testing"
"github.com/prysmaticlabs/go-bitfield"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
state_native "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/math"
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/testing/require"
"github.com/prysmaticlabs/prysm/v5/testing/util/random"
"github.com/prysmaticlabs/prysm/v5/time/slots"
)
func TestValidateNilPayloadAttestation(t *testing.T) {
require.ErrorIs(t, helpers.ErrNilData, helpers.ValidateNilPayloadAttestationData(nil))
data := &eth.PayloadAttestationData{}
require.ErrorIs(t, helpers.ErrNilBeaconBlockRoot, helpers.ValidateNilPayloadAttestationData(data))
data.BeaconBlockRoot = make([]byte, 32)
require.NoError(t, helpers.ValidateNilPayloadAttestationData(data))
require.ErrorIs(t, helpers.ErrNilMessage, helpers.ValidateNilPayloadAttestationMessage(nil))
message := &eth.PayloadAttestationMessage{}
require.ErrorIs(t, helpers.ErrNilSignature, helpers.ValidateNilPayloadAttestationMessage(message))
message.Signature = make([]byte, 96)
require.ErrorIs(t, helpers.ErrNilData, helpers.ValidateNilPayloadAttestationMessage(message))
message.Data = data
require.NoError(t, helpers.ValidateNilPayloadAttestationMessage(message))
require.ErrorIs(t, helpers.ErrNilPayloadAttestation, helpers.ValidateNilPayloadAttestation(nil))
att := &eth.PayloadAttestation{}
require.ErrorIs(t, helpers.ErrNilAggregationBits, helpers.ValidateNilPayloadAttestation(att))
att.AggregationBits = bitfield.NewBitvector512()
require.ErrorIs(t, helpers.ErrNilSignature, helpers.ValidateNilPayloadAttestation(att))
att.Signature = message.Signature
require.ErrorIs(t, helpers.ErrNilData, helpers.ValidateNilPayloadAttestation(att))
att.Data = data
require.NoError(t, helpers.ValidateNilPayloadAttestation(att))
}
func TestGetPayloadTimelinessCommittee(t *testing.T) {
helpers.ClearCache()
// Create 10 committees
committeeCount := uint64(10)
validatorCount := committeeCount * params.BeaconConfig().TargetCommitteeSize * uint64(params.BeaconConfig().SlotsPerEpoch)
validators := make([]*ethpb.Validator, validatorCount)
for i := 0; i < len(validators); i++ {
k := make([]byte, 48)
copy(k, strconv.Itoa(i))
validators[i] = &ethpb.Validator{
PublicKey: k,
WithdrawalCredentials: make([]byte, 32),
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
}
}
state, err := state_native.InitializeFromProtoEpbs(random.BeaconState(t))
require.NoError(t, err)
require.NoError(t, state.SetValidators(validators))
require.NoError(t, state.SetSlot(200))
ctx := context.Background()
indices, err := helpers.BeaconCommitteeFromState(ctx, state, state.Slot(), 1)
require.NoError(t, err)
require.Equal(t, 128, len(indices))
epoch := slots.ToEpoch(state.Slot())
activeCount, err := helpers.ActiveValidatorCount(ctx, state, epoch)
require.NoError(t, err)
require.Equal(t, uint64(40960), activeCount)
computedCommitteeCount := helpers.SlotCommitteeCount(activeCount)
require.Equal(t, committeeCount, computedCommitteeCount)
committeesPerSlot := math.LargestPowerOfTwo(math.Min(committeeCount, fieldparams.PTCSize))
require.Equal(t, uint64(8), committeesPerSlot)
ptc, err := helpers.GetPayloadTimelinessCommittee(ctx, state, state.Slot())
require.NoError(t, err)
require.Equal(t, fieldparams.PTCSize, len(ptc))
committee1, err := helpers.BeaconCommitteeFromState(ctx, state, state.Slot(), 0)
require.NoError(t, err)
require.DeepEqual(t, committee1[len(committee1)-64:], ptc[:64])
}
func Test_PtcAllocation(t *testing.T) {
tests := []struct {
totalActive uint64
memberPerCommittee uint64
committeesPerSlot uint64
}{
{64, 512, 1},
{params.BeaconConfig().MinGenesisActiveValidatorCount, 128, 4},
{25600, 128, 4},
{256000, 16, 32},
{1024000, 8, 64},
}
for _, test := range tests {
committeesPerSlot, memberPerCommittee := helpers.PtcAllocation(test.totalActive)
if memberPerCommittee != test.memberPerCommittee {
t.Errorf("memberPerCommittee(%d) = %d; expected %d", test.totalActive, memberPerCommittee, test.memberPerCommittee)
}
if committeesPerSlot != test.committeesPerSlot {
t.Errorf("committeesPerSlot(%d) = %d; expected %d", test.totalActive, committeesPerSlot, test.committeesPerSlot)
}
}
}

View File

@@ -470,13 +470,9 @@ func IsEligibleForActivation(state state.ReadOnlyCheckpoint, validator *ethpb.Va
return isEligibleForActivation(validator.ActivationEligibilityEpoch, validator.ActivationEpoch, finalizedEpoch)
}
// IsEligibleForActivationUsingTrie checks if the validator is eligible for activation.
func IsEligibleForActivationUsingTrie(state state.ReadOnlyCheckpoint, validator state.ReadOnlyValidator) bool {
cpt := state.FinalizedCheckpoint()
if cpt == nil {
return false
}
return isEligibleForActivation(validator.ActivationEligibilityEpoch(), validator.ActivationEpoch(), cpt.Epoch)
// IsEligibleForActivationUsingROVal checks if the validator is eligible for activation using the provided read only validator.
func IsEligibleForActivationUsingROVal(state state.ReadOnlyCheckpoint, validator state.ReadOnlyValidator) bool {
return isEligibleForActivation(validator.ActivationEligibilityEpoch(), validator.ActivationEpoch(), state.FinalizedCheckpointEpoch())
}
// isEligibleForActivation carries out the logic for IsEligibleForActivation*
@@ -588,13 +584,13 @@ func IsSameWithdrawalCredentials(a, b *ethpb.Validator) bool {
// and validator.withdrawable_epoch <= epoch
// and balance > 0
// )
func IsFullyWithdrawableValidator(val *ethpb.Validator, balance uint64, epoch primitives.Epoch) bool {
func IsFullyWithdrawableValidator(val *ethpb.Validator, balance uint64, epoch primitives.Epoch, fork int) bool {
if val == nil || balance <= 0 {
return false
}
// Electra / EIP-7251 logic
if epoch >= params.BeaconConfig().ElectraForkEpoch {
if fork >= version.Electra {
return HasExecutionWithdrawalCredentials(val) && val.WithdrawableEpoch <= epoch
}
@@ -604,12 +600,12 @@ func IsFullyWithdrawableValidator(val *ethpb.Validator, balance uint64, epoch pr
// IsPartiallyWithdrawableValidator returns whether the validator is able to perform a
// partial withdrawal. This function assumes that the caller has a lock on the state.
// This method conditionally calls the fork appropriate implementation based on the epoch argument.
func IsPartiallyWithdrawableValidator(val *ethpb.Validator, balance uint64, epoch primitives.Epoch) bool {
func IsPartiallyWithdrawableValidator(val *ethpb.Validator, balance uint64, epoch primitives.Epoch, fork int) bool {
if val == nil {
return false
}
if epoch < params.BeaconConfig().ElectraForkEpoch {
if fork < version.Electra {
return isPartiallyWithdrawableValidatorCapella(val, balance, epoch)
}

View File

@@ -16,6 +16,7 @@ import (
"github.com/prysmaticlabs/prysm/v5/crypto/hash"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/prysmaticlabs/prysm/v5/testing/assert"
"github.com/prysmaticlabs/prysm/v5/testing/require"
)
@@ -970,6 +971,7 @@ func TestIsFullyWithdrawableValidator(t *testing.T) {
validator *ethpb.Validator
balance uint64
epoch primitives.Epoch
fork int
want bool
}{
{
@@ -1027,13 +1029,14 @@ func TestIsFullyWithdrawableValidator(t *testing.T) {
},
balance: params.BeaconConfig().MaxEffectiveBalance,
epoch: params.BeaconConfig().ElectraForkEpoch,
fork: version.Electra,
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.want, helpers.IsFullyWithdrawableValidator(tt.validator, tt.balance, tt.epoch))
assert.Equal(t, tt.want, helpers.IsFullyWithdrawableValidator(tt.validator, tt.balance, tt.epoch, tt.fork))
})
}
}
@@ -1044,6 +1047,7 @@ func TestIsPartiallyWithdrawableValidator(t *testing.T) {
validator *ethpb.Validator
balance uint64
epoch primitives.Epoch
fork int
want bool
}{
{
@@ -1091,6 +1095,7 @@ func TestIsPartiallyWithdrawableValidator(t *testing.T) {
},
balance: params.BeaconConfig().MinActivationBalance * 2,
epoch: params.BeaconConfig().ElectraForkEpoch,
fork: version.Electra,
want: true,
},
{
@@ -1101,13 +1106,14 @@ func TestIsPartiallyWithdrawableValidator(t *testing.T) {
},
balance: params.BeaconConfig().MaxEffectiveBalanceElectra * 2,
epoch: params.BeaconConfig().ElectraForkEpoch,
fork: version.Electra,
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.want, helpers.IsPartiallyWithdrawableValidator(tt.validator, tt.balance, tt.epoch))
assert.Equal(t, tt.want, helpers.IsPartiallyWithdrawableValidator(tt.validator, tt.balance, tt.epoch, tt.fork))
})
}
}

View File

@@ -22,7 +22,7 @@ func SlashingParamsPerVersion(v int) (slashingQuotient, proposerRewardQuotient,
slashingQuotient = cfg.MinSlashingPenaltyQuotientBellatrix
proposerRewardQuotient = cfg.ProposerRewardQuotient
whistleblowerRewardQuotient = cfg.WhistleBlowerRewardQuotient
case version.Electra:
case version.Electra, version.EPBS:
slashingQuotient = cfg.MinSlashingPenaltyQuotientElectra
proposerRewardQuotient = cfg.ProposerRewardQuotient
whistleblowerRewardQuotient = cfg.WhistleBlowerRewardQuotientElectra

View File

@@ -53,6 +53,7 @@ type ReadOnlyDatabase interface {
DepositContractAddress(ctx context.Context) ([]byte, error)
// ExecutionChainData operations.
ExecutionChainData(ctx context.Context) (*ethpb.ETH1ChainData, error)
SignedBlindPayloadEnvelope(ctx context.Context, blockRoot []byte) (*ethpb.SignedBlindPayloadEnvelope, error)
// Fee recipients operations.
FeeRecipientByValidatorID(ctx context.Context, id primitives.ValidatorIndex) (common.Address, error)
RegistrationByValidatorID(ctx context.Context, id primitives.ValidatorIndex) (*ethpb.ValidatorRegistrationV1, error)
@@ -87,6 +88,7 @@ type NoHeadAccessDatabase interface {
SaveDepositContractAddress(ctx context.Context, addr common.Address) error
// SaveExecutionChainData operations.
SaveExecutionChainData(ctx context.Context, data *ethpb.ETH1ChainData) error
SaveBlindPayloadEnvelope(ctx context.Context, envelope *ethpb.SignedBlindPayloadEnvelope) error
// Run any required database migrations.
RunMigrations(ctx context.Context) error
// Fee recipients operations.

View File

@@ -6,6 +6,7 @@ go_library(
"archived_point.go",
"backfill.go",
"backup.go",
"blind_payload_envelope.go",
"blocks.go",
"checkpoint.go",
"deposit_contract.go",
@@ -78,6 +79,7 @@ go_test(
"archived_point_test.go",
"backfill_test.go",
"backup_test.go",
"blind_payload_envelope_test.go",
"blocks_test.go",
"checkpoint_test.go",
"deposit_contract_test.go",
@@ -119,6 +121,7 @@ go_test(
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
"//testing/util:go_default_library",
"//testing/util/random:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_golang_snappy//:go_default_library",
"@com_github_pkg_errors//:go_default_library",

View File

@@ -0,0 +1,45 @@
package kv
import (
"context"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
bolt "go.etcd.io/bbolt"
"go.opencensus.io/trace"
)
// SaveBlindPayloadEnvelope saves a signed execution payload envelope blind in the database.
func (s *Store) SaveBlindPayloadEnvelope(ctx context.Context, env *ethpb.SignedBlindPayloadEnvelope) error {
ctx, span := trace.StartSpan(ctx, "BeaconDB.SaveBlindPayloadEnvelope")
defer span.End()
enc, err := encode(ctx, env)
if err != nil {
return err
}
r := env.Message.BeaconBlockRoot
err = s.db.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket(executionPayloadEnvelopeBucket)
return bucket.Put(r, enc)
})
return err
}
// SignedBlindPayloadEnvelope retrieves a signed execution payload envelope blind from the database.
func (s *Store) SignedBlindPayloadEnvelope(ctx context.Context, blockRoot []byte) (*ethpb.SignedBlindPayloadEnvelope, error) {
ctx, span := trace.StartSpan(ctx, "BeaconDB.SignedBlindPayloadEnvelope")
defer span.End()
env := &ethpb.SignedBlindPayloadEnvelope{}
err := s.db.View(func(tx *bolt.Tx) error {
bkt := tx.Bucket(executionPayloadEnvelopeBucket)
enc := bkt.Get(blockRoot)
if enc == nil {
return ErrNotFound
}
return decode(ctx, enc, env)
})
return env, err
}

View File

@@ -0,0 +1,23 @@
package kv
import (
"context"
"testing"
"github.com/prysmaticlabs/prysm/v5/testing/require"
"github.com/prysmaticlabs/prysm/v5/testing/util/random"
)
func TestStore_SignedBlindPayloadEnvelope(t *testing.T) {
db := setupDB(t)
ctx := context.Background()
_, err := db.SignedBlindPayloadEnvelope(ctx, []byte("test"))
require.ErrorIs(t, err, ErrNotFound)
env := random.SignedBlindPayloadEnvelope(t)
err = db.SaveBlindPayloadEnvelope(ctx, env)
require.NoError(t, err)
got, err := db.SignedBlindPayloadEnvelope(ctx, env.Message.BeaconBlockRoot)
require.NoError(t, err)
require.DeepEqual(t, got, env)
}

View File

@@ -823,6 +823,11 @@ func unmarshalBlock(_ context.Context, enc []byte) (interfaces.ReadOnlySignedBea
if err := rawBlock.UnmarshalSSZ(enc[len(electraBlindKey):]); err != nil {
return nil, errors.Wrap(err, "could not unmarshal blinded Electra block")
}
case hasEpbsKey(enc):
rawBlock = &ethpb.SignedBeaconBlockEpbs{}
if err := rawBlock.UnmarshalSSZ(enc[len(epbsKey):]); err != nil {
return nil, errors.Wrap(err, "could not unmarshal EPBS block")
}
default:
// Marshal block bytes to phase 0 beacon block.
rawBlock = &ethpb.SignedBeaconBlock{}
@@ -852,6 +857,8 @@ func encodeBlock(blk interfaces.ReadOnlySignedBeaconBlock) ([]byte, error) {
func keyForBlock(blk interfaces.ReadOnlySignedBeaconBlock) ([]byte, error) {
switch blk.Version() {
case version.EPBS:
return epbsKey, nil
case version.Electra:
if blk.IsBlinded() {
return electraBlindKey, nil

View File

@@ -18,6 +18,7 @@ import (
"github.com/prysmaticlabs/prysm/v5/testing/assert"
"github.com/prysmaticlabs/prysm/v5/testing/require"
"github.com/prysmaticlabs/prysm/v5/testing/util"
"github.com/prysmaticlabs/prysm/v5/testing/util/random"
"google.golang.org/protobuf/proto"
)
@@ -146,6 +147,17 @@ var blockTests = []struct {
}
return blocks.NewSignedBeaconBlock(b)
}},
{
name: "epbs",
newBlock: func(slot primitives.Slot, root []byte) (interfaces.ReadOnlySignedBeaconBlock, error) {
b := random.SignedBeaconBlock(&testing.T{})
b.Block.Slot = slot
if root != nil {
b.Block.ParentRoot = root
}
return blocks.NewSignedBeaconBlock(b)
},
},
}
func TestStore_SaveBlock_NoDuplicates(t *testing.T) {
@@ -202,7 +214,7 @@ func TestStore_BlocksCRUD(t *testing.T) {
retrievedBlock, err = db.Block(ctx, blockRoot)
require.NoError(t, err)
wanted := retrievedBlock
if retrievedBlock.Version() >= version.Bellatrix {
if retrievedBlock.Version() >= version.Bellatrix && retrievedBlock.Version() < version.EPBS {
wanted, err = retrievedBlock.ToBlinded()
require.NoError(t, err)
}
@@ -390,7 +402,7 @@ func TestStore_BlocksCRUD_NoCache(t *testing.T) {
require.NoError(t, err)
wanted := blk
if blk.Version() >= version.Bellatrix {
if blk.Version() >= version.Bellatrix && blk.Version() < version.EPBS {
wanted, err = blk.ToBlinded()
require.NoError(t, err)
}
@@ -609,7 +621,7 @@ func TestStore_SaveBlock_CanGetHighestAt(t *testing.T) {
b, err := db.Block(ctx, root)
require.NoError(t, err)
wanted := block1
if block1.Version() >= version.Bellatrix {
if block1.Version() >= version.Bellatrix && block1.Version() < version.EPBS {
wanted, err = wanted.ToBlinded()
require.NoError(t, err)
}
@@ -627,7 +639,7 @@ func TestStore_SaveBlock_CanGetHighestAt(t *testing.T) {
b, err = db.Block(ctx, root)
require.NoError(t, err)
wanted2 := block2
if block2.Version() >= version.Bellatrix {
if block2.Version() >= version.Bellatrix && block2.Version() < version.EPBS {
wanted2, err = block2.ToBlinded()
require.NoError(t, err)
}
@@ -645,7 +657,7 @@ func TestStore_SaveBlock_CanGetHighestAt(t *testing.T) {
b, err = db.Block(ctx, root)
require.NoError(t, err)
wanted = block3
if block3.Version() >= version.Bellatrix {
if block3.Version() >= version.Bellatrix && block3.Version() < version.EPBS {
wanted, err = wanted.ToBlinded()
require.NoError(t, err)
}
@@ -681,7 +693,7 @@ func TestStore_GenesisBlock_CanGetHighestAt(t *testing.T) {
b, err := db.Block(ctx, root)
require.NoError(t, err)
wanted := block1
if block1.Version() >= version.Bellatrix {
if block1.Version() >= version.Bellatrix && block1.Version() < version.EPBS {
wanted, err = block1.ToBlinded()
require.NoError(t, err)
}
@@ -698,7 +710,7 @@ func TestStore_GenesisBlock_CanGetHighestAt(t *testing.T) {
b, err = db.Block(ctx, root)
require.NoError(t, err)
wanted = genesisBlock
if genesisBlock.Version() >= version.Bellatrix {
if genesisBlock.Version() >= version.Bellatrix && genesisBlock.Version() < version.EPBS {
wanted, err = genesisBlock.ToBlinded()
require.NoError(t, err)
}
@@ -715,7 +727,7 @@ func TestStore_GenesisBlock_CanGetHighestAt(t *testing.T) {
b, err = db.Block(ctx, root)
require.NoError(t, err)
wanted = genesisBlock
if genesisBlock.Version() >= version.Bellatrix {
if genesisBlock.Version() >= version.Bellatrix && genesisBlock.Version() < version.EPBS {
wanted, err = genesisBlock.ToBlinded()
require.NoError(t, err)
}
@@ -811,7 +823,7 @@ func TestStore_BlocksBySlot_BlockRootsBySlot(t *testing.T) {
require.NoError(t, err)
wanted := b1
if b1.Version() >= version.Bellatrix {
if b1.Version() >= version.Bellatrix && b1.Version() < version.EPBS {
wanted, err = b1.ToBlinded()
require.NoError(t, err)
}
@@ -827,7 +839,7 @@ func TestStore_BlocksBySlot_BlockRootsBySlot(t *testing.T) {
t.Fatalf("Expected 2 blocks, received %d blocks", len(retrievedBlocks))
}
wanted = b2
if b2.Version() >= version.Bellatrix {
if b2.Version() >= version.Bellatrix && b2.Version() < version.EPBS {
wanted, err = b2.ToBlinded()
require.NoError(t, err)
}
@@ -837,7 +849,7 @@ func TestStore_BlocksBySlot_BlockRootsBySlot(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, true, proto.Equal(wantedPb, retrieved0Pb), "Wanted: %v, received: %v", retrievedBlocks[0], wanted)
wanted = b3
if b3.Version() >= version.Bellatrix {
if b3.Version() >= version.Bellatrix && b3.Version() < version.EPBS {
wanted, err = b3.ToBlinded()
require.NoError(t, err)
}

View File

@@ -78,6 +78,8 @@ func isSSZStorageFormat(obj interface{}) bool {
return true
case *ethpb.VoluntaryExit:
return true
case *ethpb.SignedBlindPayloadEnvelope:
return true
case *ethpb.ValidatorRegistrationV1:
return true
default:

View File

@@ -65,3 +65,10 @@ func hasElectraBlindKey(enc []byte) bool {
}
return bytes.Equal(enc[:len(electraBlindKey)], electraBlindKey)
}
func hasEpbsKey(enc []byte) bool {
if len(epbsKey) >= len(enc) {
return false
}
return bytes.Equal(enc[:len(epbsKey)], epbsKey)
}

View File

@@ -118,6 +118,9 @@ var Buckets = [][]byte{
feeRecipientBucket,
registrationBucket,
// ePBS
executionPayloadEnvelopeBucket,
}
// KVStoreOption is a functional option that modifies a kv.Store.

View File

@@ -7,15 +7,16 @@ package kv
// it easy to scan for keys that have a certain shard number as a prefix and return those
// corresponding attestations.
var (
blocksBucket = []byte("blocks")
stateBucket = []byte("state")
stateSummaryBucket = []byte("state-summary")
chainMetadataBucket = []byte("chain-metadata")
checkpointBucket = []byte("check-point")
powchainBucket = []byte("powchain")
stateValidatorsBucket = []byte("state-validators")
feeRecipientBucket = []byte("fee-recipient")
registrationBucket = []byte("registration")
blocksBucket = []byte("blocks")
stateBucket = []byte("state")
stateSummaryBucket = []byte("state-summary")
chainMetadataBucket = []byte("chain-metadata")
checkpointBucket = []byte("check-point")
powchainBucket = []byte("powchain")
stateValidatorsBucket = []byte("state-validators")
feeRecipientBucket = []byte("fee-recipient")
registrationBucket = []byte("registration")
executionPayloadEnvelopeBucket = []byte("execution-payload-envelope")
// Deprecated: This bucket was migrated in PR 6461. Do not use, except for migrations.
slotsHasObjectBucket = []byte("slots-has-objects")
@@ -50,6 +51,7 @@ var (
denebBlindKey = []byte("blind-deneb")
electraKey = []byte("electra")
electraBlindKey = []byte("blind-electra")
epbsKey = []byte("epbs")
// block root included in the beacon state used by weak subjectivity initial sync
originCheckpointBlockRootKey = []byte("origin-checkpoint-block-root")

View File

@@ -252,6 +252,10 @@ func (s *Store) saveStatesEfficientInternal(ctx context.Context, tx *bolt.Tx, bl
if err := s.processElectra(ctx, rawType, rt[:], bucket, valIdxBkt, validatorKeys[i]); err != nil {
return err
}
case *ethpb.BeaconStateEPBS:
if err := s.processEPBS(ctx, rawType, rt[:], bucket, valIdxBkt, validatorKeys[i]); err != nil {
return err
}
default:
return errors.New("invalid state type")
}
@@ -367,6 +371,24 @@ func (s *Store) processElectra(ctx context.Context, pbState *ethpb.BeaconStateEl
return nil
}
func (s *Store) processEPBS(ctx context.Context, pbState *ethpb.BeaconStateEPBS, rootHash []byte, bucket, valIdxBkt *bolt.Bucket, validatorKey []byte) error {
valEntries := pbState.Validators
pbState.Validators = make([]*ethpb.Validator, 0)
rawObj, err := pbState.MarshalSSZ()
if err != nil {
return err
}
encodedState := snappy.Encode(nil, append(epbsKey, rawObj...))
if err := bucket.Put(rootHash, encodedState); err != nil {
return err
}
pbState.Validators = valEntries
if err := valIdxBkt.Put(rootHash, validatorKey); err != nil {
return err
}
return nil
}
func (s *Store) storeValidatorEntriesSeparately(ctx context.Context, tx *bolt.Tx, validatorsEntries map[string]*ethpb.Validator) error {
valBkt := tx.Bucket(stateValidatorsBucket)
for hashStr, validatorEntry := range validatorsEntries {
@@ -516,6 +538,19 @@ func (s *Store) unmarshalState(_ context.Context, enc []byte, validatorEntries [
}
switch {
case hasEpbsKey(enc):
protoState := &ethpb.BeaconStateEPBS{}
if err := protoState.UnmarshalSSZ(enc[len(epbsKey):]); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal encoding for EPBS")
}
ok, err := s.isStateValidatorMigrationOver()
if err != nil {
return nil, err
}
if ok {
protoState.Validators = validatorEntries
}
return statenative.InitializeFromProtoEpbs(protoState)
case hasElectraKey(enc):
protoState := &ethpb.BeaconStateElectra{}
if err := protoState.UnmarshalSSZ(enc[len(electraKey):]); err != nil {
@@ -675,6 +710,19 @@ func marshalState(ctx context.Context, st state.ReadOnlyBeaconState) ([]byte, er
return nil, err
}
return snappy.Encode(nil, append(electraKey, rawObj...)), nil
case *ethpb.BeaconStateEPBS:
rState, ok := st.ToProtoUnsafe().(*ethpb.BeaconStateEPBS)
if !ok {
return nil, errors.New("non valid inner state")
}
if rState == nil {
return nil, errors.New("nil state")
}
rawObj, err := rState.MarshalSSZ()
if err != nil {
return nil, err
}
return snappy.Encode(nil, append(epbsKey, rawObj...)), nil
default:
return nil, errors.New("invalid inner state")
}

View File

@@ -9,6 +9,7 @@ import (
"time"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
statenative "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native"
"github.com/prysmaticlabs/prysm/v5/config/features"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
@@ -20,6 +21,7 @@ import (
"github.com/prysmaticlabs/prysm/v5/testing/assert"
"github.com/prysmaticlabs/prysm/v5/testing/require"
"github.com/prysmaticlabs/prysm/v5/testing/util"
"github.com/prysmaticlabs/prysm/v5/testing/util/random"
bolt "go.etcd.io/bbolt"
)
@@ -159,6 +161,16 @@ func TestState_CanSaveRetrieve(t *testing.T) {
},
rootSeed: 'E',
},
{
name: "epbs",
s: func() state.BeaconState {
stPb := random.BeaconState(t)
st, err := statenative.InitializeFromProtoUnsafeEpbs(stPb)
require.NoError(t, err)
return st
},
rootSeed: 'F',
},
}
db := setupDB(t)
@@ -1113,6 +1125,26 @@ func TestDenebState_CanDelete(t *testing.T) {
require.Equal(t, state.ReadOnlyBeaconState(nil), savedS, "Unsaved state should've been nil")
}
func TestEpbsState_CanDelete(t *testing.T) {
db := setupDB(t)
r := [32]byte{'A'}
require.Equal(t, false, db.HasState(context.Background(), r))
s := random.BeaconState(t)
st, err := statenative.InitializeFromProtoUnsafeEpbs(s)
require.NoError(t, err)
require.NoError(t, db.SaveState(context.Background(), st, r))
require.Equal(t, true, db.HasState(context.Background(), r))
require.NoError(t, db.DeleteState(context.Background(), r))
savedS, err := db.State(context.Background(), r)
require.NoError(t, err)
require.Equal(t, state.ReadOnlyBeaconState(nil), savedS, "Unsaved state should've been nil")
}
func TestStateDeneb_CanSaveRetrieveValidatorEntries(t *testing.T) {
db := setupDB(t)

View File

@@ -267,11 +267,12 @@ func (f *ForkChoice) updateBalances() error {
newBalances := f.justifiedBalances
zHash := params.BeaconConfig().ZeroHash
for index, vote := range f.votes {
for index := 0; index < len(f.votes); index++ {
// Skip if validator has been slashed
if f.store.slashedIndices[primitives.ValidatorIndex(index)] {
continue
}
vote := &f.votes[index]
// Skip if validator has never voted for current root and next root (i.e. if the
// votes are zero hash aka genesis block), there's nothing to compute.
if vote.currentRoot == zHash && vote.nextRoot == zHash {

View File

@@ -11,17 +11,17 @@ import (
// gossipTopicMappings represent the protocol ID to protobuf message type map for easy
// lookup.
var gossipTopicMappings = map[string]proto.Message{
BlockSubnetTopicFormat: &ethpb.SignedBeaconBlock{},
AttestationSubnetTopicFormat: &ethpb.Attestation{},
ExitSubnetTopicFormat: &ethpb.SignedVoluntaryExit{},
ProposerSlashingSubnetTopicFormat: &ethpb.ProposerSlashing{},
AttesterSlashingSubnetTopicFormat: &ethpb.AttesterSlashing{},
AggregateAndProofSubnetTopicFormat: &ethpb.SignedAggregateAttestationAndProof{},
SyncContributionAndProofSubnetTopicFormat: &ethpb.SignedContributionAndProof{},
SyncCommitteeSubnetTopicFormat: &ethpb.SyncCommitteeMessage{},
BlsToExecutionChangeSubnetTopicFormat: &ethpb.SignedBLSToExecutionChange{},
BlobSubnetTopicFormat: &ethpb.BlobSidecar{},
var gossipTopicMappings = map[string]func() proto.Message{
BlockSubnetTopicFormat: func() proto.Message { return &ethpb.SignedBeaconBlock{} },
AttestationSubnetTopicFormat: func() proto.Message { return &ethpb.Attestation{} },
ExitSubnetTopicFormat: func() proto.Message { return &ethpb.SignedVoluntaryExit{} },
ProposerSlashingSubnetTopicFormat: func() proto.Message { return &ethpb.ProposerSlashing{} },
AttesterSlashingSubnetTopicFormat: func() proto.Message { return &ethpb.AttesterSlashing{} },
AggregateAndProofSubnetTopicFormat: func() proto.Message { return &ethpb.SignedAggregateAttestationAndProof{} },
SyncContributionAndProofSubnetTopicFormat: func() proto.Message { return &ethpb.SignedContributionAndProof{} },
SyncCommitteeSubnetTopicFormat: func() proto.Message { return &ethpb.SyncCommitteeMessage{} },
BlsToExecutionChangeSubnetTopicFormat: func() proto.Message { return &ethpb.SignedBLSToExecutionChange{} },
BlobSubnetTopicFormat: func() proto.Message { return &ethpb.BlobSidecar{} },
}
// GossipTopicMappings is a function to return the assigned data type
@@ -44,27 +44,35 @@ func GossipTopicMappings(topic string, epoch primitives.Epoch) proto.Message {
if epoch >= params.BeaconConfig().AltairForkEpoch {
return &ethpb.SignedBeaconBlockAltair{}
}
return gossipTopicMappings[topic]
return gossipMessage(topic)
case AttestationSubnetTopicFormat:
if epoch >= params.BeaconConfig().ElectraForkEpoch {
return &ethpb.AttestationElectra{}
}
return gossipTopicMappings[topic]
return gossipMessage(topic)
case AttesterSlashingSubnetTopicFormat:
if epoch >= params.BeaconConfig().ElectraForkEpoch {
return &ethpb.AttesterSlashingElectra{}
}
return gossipTopicMappings[topic]
return gossipMessage(topic)
case AggregateAndProofSubnetTopicFormat:
if epoch >= params.BeaconConfig().ElectraForkEpoch {
return &ethpb.SignedAggregateAttestationAndProofElectra{}
}
return gossipTopicMappings[topic]
return gossipMessage(topic)
default:
return gossipTopicMappings[topic]
return gossipMessage(topic)
}
}
func gossipMessage(topic string) proto.Message {
msgGen, ok := gossipTopicMappings[topic]
if !ok {
return nil
}
return msgGen()
}
// AllTopics returns all topics stored in our
// gossip mapping.
func AllTopics() []string {
@@ -81,7 +89,7 @@ var GossipTypeMapping = make(map[reflect.Type]string, len(gossipTopicMappings))
func init() {
for k, v := range gossipTopicMappings {
GossipTypeMapping[reflect.TypeOf(v)] = k
GossipTypeMapping[reflect.TypeOf(v())] = k
}
// Specially handle Altair objects.
GossipTypeMapping[reflect.TypeOf(&ethpb.SignedBeaconBlockAltair{})] = BlockSubnetTopicFormat

View File

@@ -15,7 +15,7 @@ func TestMappingHasNoDuplicates(t *testing.T) {
params.SetupTestConfigCleanup(t)
m := make(map[reflect.Type]bool)
for _, v := range gossipTopicMappings {
if _, ok := m[reflect.TypeOf(v)]; ok {
if _, ok := m[reflect.TypeOf(v())]; ok {
t.Errorf("%T is duplicated in the topic mapping", v)
}
m[reflect.TypeOf(v)] = true

View File

@@ -20,6 +20,10 @@ import (
"github.com/prysmaticlabs/prysm/v5/testing/require"
)
// Variables defined in the placeholderFields will not be tested in `TestGetSpec`.
// These are variables that we don't use in Prysm. (i.e. future hardfork, light client... etc)
var placeholderFields = []string{"DOMAIN_BEACON_BUILDER", "DOMAIN_PTC_ATTESTER"}
func TestGetDepositContract(t *testing.T) {
params.SetupTestConfigCleanup(t)
config := params.BeaconConfig().Copy()
@@ -192,7 +196,7 @@ func TestGetSpec(t *testing.T) {
data, ok := resp.Data.(map[string]interface{})
require.Equal(t, true, ok)
assert.Equal(t, 155, len(data))
assert.Equal(t, 157, len(data))
for k, v := range data {
t.Run(k, func(t *testing.T) {
switch k {
@@ -530,6 +534,12 @@ func TestGetSpec(t *testing.T) {
case "MAX_DEPOSIT_REQUESTS_PER_PAYLOAD":
assert.Equal(t, "93", v)
default:
for _, pf := range placeholderFields {
if k == pf {
t.Logf("Skipping placeholder field: %s", k)
return
}
}
t.Errorf("Incorrect key: %s", k)
}
})

View File

@@ -459,7 +459,7 @@ func (s *Server) sendPayloadAttributes(ctx context.Context, w http.ResponseWrite
SuggestedFeeRecipient: hexutil.Encode(headPayload.FeeRecipient()),
Withdrawals: structs.WithdrawalsFromConsensus(withdrawals),
}
case version.Deneb:
case version.Deneb, version.Electra:
withdrawals, _, err := headState.ExpectedWithdrawals()
if err != nil {
return write(w, flusher, "Could not get head state expected withdrawals: "+err.Error())

View File

@@ -24,6 +24,7 @@ go_library(
"proposer_exits.go",
"proposer_slashings.go",
"proposer_sync_aggregate.go",
"ptc_attester.go",
"server.go",
"status.go",
"sync_committee.go",
@@ -82,6 +83,7 @@ go_library(
"//proto/engine/v1:go_default_library",
"//proto/eth/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/attestation:go_default_library",
"//proto/prysm/v1alpha1/attestation/aggregation:go_default_library",
"//proto/prysm/v1alpha1/attestation/aggregation/attestations:go_default_library",
"//proto/prysm/v1alpha1/attestation/aggregation/sync_contribution:go_default_library",

View File

@@ -39,54 +39,59 @@ func (vs *Server) GetAttestationData(ctx context.Context, req *ethpb.Attestation
}
// ProposeAttestation is a function called by an attester to vote
// on a block via an attestation object as defined in the Ethereum Serenity specification.
// on a block via an attestation object as defined in the Ethereum specification.
func (vs *Server) ProposeAttestation(ctx context.Context, att *ethpb.Attestation) (*ethpb.AttestResponse, error) {
ctx, span := trace.StartSpan(ctx, "AttesterServer.ProposeAttestation")
defer span.End()
if _, err := bls.SignatureFromBytes(att.Signature); err != nil {
return nil, status.Error(codes.InvalidArgument, "Incorrect attestation signature")
}
root, err := att.Data.HashTreeRoot()
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not tree hash attestation: %v", err)
}
// Broadcast the unaggregated attestation on a feed to notify other services in the beacon node
// of a received unaggregated attestation.
vs.OperationNotifier.OperationFeed().Send(&feed.Event{
Type: operation.UnaggregatedAttReceived,
Data: &operation.UnAggregatedAttReceivedData{
Attestation: att,
},
})
// Determine subnet to broadcast attestation to
wantedEpoch := slots.ToEpoch(att.Data.Slot)
vals, err := vs.HeadFetcher.HeadValidatorsIndices(ctx, wantedEpoch)
resp, err := vs.proposeAtt(ctx, att, att.GetData().CommitteeIndex)
if err != nil {
return nil, err
}
subnet := helpers.ComputeSubnetFromCommitteeAndSlot(uint64(len(vals)), att.Data.CommitteeIndex, att.Data.Slot)
// Broadcast the new attestation to the network.
if err := vs.P2P.BroadcastAttestation(ctx, subnet, att); err != nil {
return nil, status.Errorf(codes.Internal, "Could not broadcast attestation: %v", err)
}
go func() {
ctx = trace.NewContext(context.Background(), trace.FromContext(ctx))
attCopy := ethpb.CopyAttestation(att)
if err := vs.AttPool.SaveUnaggregatedAttestation(attCopy); err != nil {
log.WithError(err).Error("Could not handle attestation in operations service")
log.WithError(err).Error("Could not save unaggregated attestation")
return
}
}()
return &ethpb.AttestResponse{
AttestationDataRoot: root[:],
}, nil
return resp, nil
}
// ProposeAttestationElectra is a function called by an attester to vote
// on a block via an attestation object as defined in the Ethereum specification.
func (vs *Server) ProposeAttestationElectra(ctx context.Context, att *ethpb.AttestationElectra) (*ethpb.AttestResponse, error) {
ctx, span := trace.StartSpan(ctx, "AttesterServer.ProposeAttestationElectra")
defer span.End()
if att.GetData().CommitteeIndex != 0 {
return nil, status.Errorf(codes.InvalidArgument, "Committee index must be set to 0")
}
committeeIndices := helpers.CommitteeIndices(att.CommitteeBits)
if len(committeeIndices) == 0 {
return nil, status.Errorf(codes.InvalidArgument, "Committee bits has no bit set")
}
if len(committeeIndices) > 1 {
return nil, status.Errorf(codes.InvalidArgument, "Committee bits has more than one bit set")
}
resp, err := vs.proposeAtt(ctx, att, committeeIndices[0])
if err != nil {
return nil, err
}
go func() {
ctx = trace.NewContext(context.Background(), trace.FromContext(ctx))
attCopy := ethpb.CopyAttestationElectra(att)
if err := vs.AttPool.SaveUnaggregatedAttestation(attCopy); err != nil {
log.WithError(err).Error("Could not save unaggregated attestation")
return
}
}()
return resp, nil
}
// SubscribeCommitteeSubnets subscribes to the committee ID subnet given subscribe request.
@@ -136,3 +141,40 @@ func (vs *Server) SubscribeCommitteeSubnets(ctx context.Context, req *ethpb.Comm
return &emptypb.Empty{}, nil
}
func (vs *Server) proposeAtt(ctx context.Context, att ethpb.Att, committee primitives.CommitteeIndex) (*ethpb.AttestResponse, error) {
if _, err := bls.SignatureFromBytes(att.GetSignature()); err != nil {
return nil, status.Error(codes.InvalidArgument, "Incorrect attestation signature")
}
root, err := att.GetData().HashTreeRoot()
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not tree hash attestation: %v", err)
}
// Broadcast the unaggregated attestation on a feed to notify other services in the beacon node
// of a received unaggregated attestation.
vs.OperationNotifier.OperationFeed().Send(&feed.Event{
Type: operation.UnaggregatedAttReceived,
Data: &operation.UnAggregatedAttReceivedData{
Attestation: att,
},
})
// Determine subnet to broadcast attestation to
wantedEpoch := slots.ToEpoch(att.GetData().Slot)
vals, err := vs.HeadFetcher.HeadValidatorsIndices(ctx, wantedEpoch)
if err != nil {
return nil, err
}
subnet := helpers.ComputeSubnetFromCommitteeAndSlot(uint64(len(vals)), committee, att.GetData().Slot)
// Broadcast the new attestation to the network.
if err := vs.P2P.BroadcastAttestation(ctx, subnet, att); err != nil {
return nil, status.Errorf(codes.Internal, "Could not broadcast attestation: %v", err)
}
return &ethpb.AttestResponse{
AttestationDataRoot: root[:],
}, nil
}

View File

@@ -30,7 +30,7 @@ import (
"google.golang.org/protobuf/proto"
)
func TestProposeAttestation_OK(t *testing.T) {
func TestProposeAttestation(t *testing.T) {
attesterServer := &Server{
HeadFetcher: &mock.ChainService{},
P2P: &mockp2p.MockBroadcaster{},
@@ -53,24 +53,107 @@ func TestProposeAttestation_OK(t *testing.T) {
}
}
state, err := util.NewBeaconState()
require.NoError(t, err)
require.NoError(t, state.SetSlot(params.BeaconConfig().SlotsPerEpoch+1))
require.NoError(t, state.SetValidators(validators))
sk, err := bls.RandKey()
require.NoError(t, err)
sig := sk.Sign([]byte("dummy_test_data"))
req := &ethpb.Attestation{
Signature: sig.Marshal(),
Data: &ethpb.AttestationData{
BeaconBlockRoot: root[:],
Source: &ethpb.Checkpoint{Root: make([]byte, 32)},
Target: &ethpb.Checkpoint{Root: make([]byte, 32)},
},
}
_, err = attesterServer.ProposeAttestation(context.Background(), req)
assert.NoError(t, err)
t.Run("Phase 0", func(t *testing.T) {
state, err := util.NewBeaconState()
require.NoError(t, err)
require.NoError(t, state.SetSlot(params.BeaconConfig().SlotsPerEpoch+1))
require.NoError(t, state.SetValidators(validators))
req := &ethpb.Attestation{
Signature: sig.Marshal(),
Data: &ethpb.AttestationData{
BeaconBlockRoot: root[:],
Source: &ethpb.Checkpoint{Root: make([]byte, 32)},
Target: &ethpb.Checkpoint{Root: make([]byte, 32)},
},
}
_, err = attesterServer.ProposeAttestation(context.Background(), req)
assert.NoError(t, err)
})
t.Run("Electra", func(t *testing.T) {
state, err := util.NewBeaconStateElectra()
require.NoError(t, err)
require.NoError(t, state.SetSlot(params.BeaconConfig().SlotsPerEpoch+1))
require.NoError(t, state.SetValidators(validators))
cb := primitives.NewAttestationCommitteeBits()
cb.SetBitAt(0, true)
req := &ethpb.AttestationElectra{
Signature: sig.Marshal(),
Data: &ethpb.AttestationData{
BeaconBlockRoot: root[:],
Source: &ethpb.Checkpoint{Root: make([]byte, 32)},
Target: &ethpb.Checkpoint{Root: make([]byte, 32)},
},
CommitteeBits: cb,
}
_, err = attesterServer.ProposeAttestationElectra(context.Background(), req)
assert.NoError(t, err)
})
t.Run("Electra - non-zero committee index", func(t *testing.T) {
state, err := util.NewBeaconStateElectra()
require.NoError(t, err)
require.NoError(t, state.SetSlot(params.BeaconConfig().SlotsPerEpoch+1))
require.NoError(t, state.SetValidators(validators))
cb := primitives.NewAttestationCommitteeBits()
cb.SetBitAt(0, true)
req := &ethpb.AttestationElectra{
Signature: sig.Marshal(),
Data: &ethpb.AttestationData{
BeaconBlockRoot: root[:],
Source: &ethpb.Checkpoint{Root: make([]byte, 32)},
Target: &ethpb.Checkpoint{Root: make([]byte, 32)},
CommitteeIndex: 1,
},
CommitteeBits: cb,
}
_, err = attesterServer.ProposeAttestationElectra(context.Background(), req)
assert.ErrorContains(t, "Committee index must be set to 0", err)
})
t.Run("Electra - no committee bit set", func(t *testing.T) {
state, err := util.NewBeaconStateElectra()
require.NoError(t, err)
require.NoError(t, state.SetSlot(params.BeaconConfig().SlotsPerEpoch+1))
require.NoError(t, state.SetValidators(validators))
req := &ethpb.AttestationElectra{
Signature: sig.Marshal(),
Data: &ethpb.AttestationData{
BeaconBlockRoot: root[:],
Source: &ethpb.Checkpoint{Root: make([]byte, 32)},
Target: &ethpb.Checkpoint{Root: make([]byte, 32)},
},
CommitteeBits: primitives.NewAttestationCommitteeBits(),
}
_, err = attesterServer.ProposeAttestationElectra(context.Background(), req)
assert.ErrorContains(t, "Committee bits has no bit set", err)
})
t.Run("Electra - multiple committee bits set", func(t *testing.T) {
state, err := util.NewBeaconStateElectra()
require.NoError(t, err)
require.NoError(t, state.SetSlot(params.BeaconConfig().SlotsPerEpoch+1))
require.NoError(t, state.SetValidators(validators))
cb := primitives.NewAttestationCommitteeBits()
cb.SetBitAt(0, true)
cb.SetBitAt(1, true)
req := &ethpb.AttestationElectra{
Signature: sig.Marshal(),
Data: &ethpb.AttestationData{
BeaconBlockRoot: root[:],
Source: &ethpb.Checkpoint{Root: make([]byte, 32)},
Target: &ethpb.Checkpoint{Root: make([]byte, 32)},
},
CommitteeBits: cb,
}
_, err = attesterServer.ProposeAttestationElectra(context.Background(), req)
assert.ErrorContains(t, "Committee bits has more than one bit set", err)
})
}
func TestProposeAttestation_IncorrectSignature(t *testing.T) {

View File

@@ -108,6 +108,7 @@ func (vs *Server) duties(ctx context.Context, req *ethpb.DutiesRequest) (*ethpb.
assignment.Committee = ca.Committee
assignment.AttesterSlot = ca.AttesterSlot
assignment.CommitteeIndex = ca.CommitteeIndex
assignment.PtcSlot = ca.PtcSlot
}
// Save the next epoch assignments.
ca, ok = nextEpochAssignments[idx]
@@ -115,6 +116,7 @@ func (vs *Server) duties(ctx context.Context, req *ethpb.DutiesRequest) (*ethpb.
nextAssignment.Committee = ca.Committee
nextAssignment.AttesterSlot = ca.AttesterSlot
nextAssignment.CommitteeIndex = ca.CommitteeIndex
nextAssignment.PtcSlot = ca.PtcSlot
}
} else {
// If the validator isn't in the beacon state, try finding their deposit to determine their status.

View File

@@ -194,7 +194,7 @@ func (vs *Server) BuildBlockParallel(ctx context.Context, sBlk interfaces.Signed
sBlk.SetEth1Data(eth1Data)
// Set deposit and attestation.
deposits, atts, err := vs.packDepositsAndAttestations(ctx, head, eth1Data) // TODO: split attestations and deposits
deposits, atts, err := vs.packDepositsAndAttestations(ctx, head, sBlk.Block().Slot(), eth1Data) // TODO: split attestations and deposits
if err != nil {
sBlk.SetDeposits([]*ethpb.Deposit{})
if err := sBlk.SetAttestations([]ethpb.Att{}); err != nil {

View File

@@ -12,14 +12,17 @@ import (
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1/attestation"
"github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1/attestation/aggregation"
attaggregation "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1/attestation/aggregation/attestations"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/prysmaticlabs/prysm/v5/time/slots"
"go.opencensus.io/trace"
)
type proposerAtts []ethpb.Att
func (vs *Server) packAttestations(ctx context.Context, latestState state.BeaconState) ([]ethpb.Att, error) {
func (vs *Server) packAttestations(ctx context.Context, latestState state.BeaconState, blkSlot primitives.Slot) ([]ethpb.Att, error) {
ctx, span := trace.StartSpan(ctx, "ProposerServer.packAttestations")
defer span.End()
@@ -39,20 +42,37 @@ func (vs *Server) packAttestations(ctx context.Context, latestState state.Beacon
}
atts = append(atts, uAtts...)
postElectra := slots.ToEpoch(blkSlot) >= params.BeaconConfig().ElectraForkEpoch
versionAtts := make([]ethpb.Att, 0, len(atts))
if postElectra {
for _, a := range atts {
if a.Version() == version.Electra {
versionAtts = append(versionAtts, a)
}
}
} else {
for _, a := range atts {
if a.Version() == version.Phase0 {
versionAtts = append(versionAtts, a)
}
}
}
// Remove duplicates from both aggregated/unaggregated attestations. This
// prevents inefficient aggregates being created.
atts, err = proposerAtts(atts).dedup()
versionAtts, err = proposerAtts(versionAtts).dedup()
if err != nil {
return nil, err
}
attsByDataRoot := make(map[[32]byte][]ethpb.Att, len(atts))
for _, att := range atts {
attDataRoot, err := att.GetData().HashTreeRoot()
attsByDataRoot := make(map[attestation.Id][]ethpb.Att, len(versionAtts))
for _, att := range versionAtts {
id, err := attestation.NewId(att, attestation.Data)
if err != nil {
return nil, err
return nil, errors.Wrap(err, "could not create attestation ID")
}
attsByDataRoot[attDataRoot] = append(attsByDataRoot[attDataRoot], att)
attsByDataRoot[id] = append(attsByDataRoot[id], att)
}
attsForInclusion := proposerAtts(make([]ethpb.Att, 0))
@@ -169,8 +189,18 @@ func (a proposerAtts) sortByProfitabilityUsingMaxCover() (proposerAtts, error) {
// limitToMaxAttestations limits attestations to maximum attestations per block.
func (a proposerAtts) limitToMaxAttestations() proposerAtts {
if uint64(len(a)) > params.BeaconConfig().MaxAttestations {
return a[:params.BeaconConfig().MaxAttestations]
if len(a) == 0 {
return a
}
var limit uint64
if a[0].Version() == version.Phase0 {
limit = params.BeaconConfig().MaxAttestations
} else {
limit = params.BeaconConfig().MaxAttestationsElectra
}
if uint64(len(a)) > limit {
return a[:limit]
}
return a
}
@@ -182,13 +212,13 @@ func (a proposerAtts) dedup() (proposerAtts, error) {
if len(a) < 2 {
return a, nil
}
attsByDataRoot := make(map[[32]byte][]ethpb.Att, len(a))
attsByDataRoot := make(map[attestation.Id][]ethpb.Att, len(a))
for _, att := range a {
attDataRoot, err := att.GetData().HashTreeRoot()
id, err := attestation.NewId(att, attestation.Data)
if err != nil {
continue
return nil, errors.Wrap(err, "failed to create attestation ID")
}
attsByDataRoot[attDataRoot] = append(attsByDataRoot[attDataRoot], att)
attsByDataRoot[id] = append(attsByDataRoot[id], att)
}
uniqAtts := make([]ethpb.Att, 0, len(a))

View File

@@ -2,10 +2,13 @@ package validator
import (
"bytes"
"context"
"sort"
"testing"
"github.com/prysmaticlabs/go-bitfield"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/operations/attestations"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/testing/assert"
@@ -423,3 +426,106 @@ func TestProposer_ProposerAtts_dedup(t *testing.T) {
})
}
}
func Test_packAttestations(t *testing.T) {
ctx := context.Background()
phase0Att := &ethpb.Attestation{
AggregationBits: bitfield.Bitlist{0b11111},
Data: &ethpb.AttestationData{
BeaconBlockRoot: make([]byte, 32),
Source: &ethpb.Checkpoint{
Epoch: 0,
Root: make([]byte, 32),
},
Target: &ethpb.Checkpoint{
Epoch: 0,
Root: make([]byte, 32),
},
},
Signature: make([]byte, 96),
}
cb := primitives.NewAttestationCommitteeBits()
cb.SetBitAt(0, true)
electraAtt := &ethpb.AttestationElectra{
AggregationBits: bitfield.Bitlist{0b11111},
CommitteeBits: cb,
Data: &ethpb.AttestationData{
BeaconBlockRoot: make([]byte, 32),
Source: &ethpb.Checkpoint{
Epoch: 0,
Root: make([]byte, 32),
},
Target: &ethpb.Checkpoint{
Epoch: 0,
Root: make([]byte, 32),
},
},
Signature: make([]byte, 96),
}
pool := attestations.NewPool()
require.NoError(t, pool.SaveAggregatedAttestations([]ethpb.Att{phase0Att, electraAtt}))
s := &Server{AttPool: pool}
t.Run("Phase 0", func(t *testing.T) {
st, _ := util.DeterministicGenesisState(t, 64)
require.NoError(t, st.SetSlot(1))
atts, err := s.packAttestations(ctx, st, 0)
require.NoError(t, err)
require.Equal(t, 1, len(atts))
assert.DeepEqual(t, phase0Att, atts[0])
})
t.Run("Electra", func(t *testing.T) {
params.SetupTestConfigCleanup(t)
cfg := params.BeaconConfig().Copy()
cfg.ElectraForkEpoch = 1
params.OverrideBeaconConfig(cfg)
st, _ := util.DeterministicGenesisStateElectra(t, 64)
require.NoError(t, st.SetSlot(params.BeaconConfig().SlotsPerEpoch+1))
atts, err := s.packAttestations(ctx, st, params.BeaconConfig().SlotsPerEpoch)
require.NoError(t, err)
require.Equal(t, 1, len(atts))
assert.DeepEqual(t, electraAtt, atts[0])
})
}
func Test_limitToMaxAttestations(t *testing.T) {
t.Run("Phase 0", func(t *testing.T) {
atts := make([]ethpb.Att, params.BeaconConfig().MaxAttestations+1)
for i := range atts {
atts[i] = &ethpb.Attestation{}
}
// 1 less than limit
pAtts := proposerAtts(atts[:len(atts)-3])
assert.Equal(t, len(pAtts), len(pAtts.limitToMaxAttestations()))
// equal to limit
pAtts = atts[:len(atts)-2]
assert.Equal(t, len(pAtts), len(pAtts.limitToMaxAttestations()))
// 1 more than limit
pAtts = atts
assert.Equal(t, len(pAtts)-1, len(pAtts.limitToMaxAttestations()))
})
t.Run("Electra", func(t *testing.T) {
atts := make([]ethpb.Att, params.BeaconConfig().MaxAttestationsElectra+1)
for i := range atts {
atts[i] = &ethpb.AttestationElectra{}
}
// 1 less than limit
pAtts := proposerAtts(atts[:len(atts)-3])
assert.Equal(t, len(pAtts), len(pAtts.limitToMaxAttestations()))
// equal to limit
pAtts = atts[:len(atts)-2]
assert.Equal(t, len(pAtts), len(pAtts.limitToMaxAttestations()))
// 1 more than limit
pAtts = atts
assert.Equal(t, len(pAtts)-1, len(pAtts.limitToMaxAttestations()))
})
}

View File

@@ -9,6 +9,7 @@ import (
"github.com/prysmaticlabs/prysm/v5/beacon-chain/cache"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/container/trie"
"github.com/prysmaticlabs/prysm/v5/math"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
@@ -20,7 +21,12 @@ import (
"google.golang.org/grpc/status"
)
func (vs *Server) packDepositsAndAttestations(ctx context.Context, head state.BeaconState, eth1Data *ethpb.Eth1Data) ([]*ethpb.Deposit, []ethpb.Att, error) {
func (vs *Server) packDepositsAndAttestations(
ctx context.Context,
head state.BeaconState,
blkSlot primitives.Slot,
eth1Data *ethpb.Eth1Data,
) ([]*ethpb.Deposit, []ethpb.Att, error) {
eg, egctx := errgroup.WithContext(ctx)
var deposits []*ethpb.Deposit
var atts []ethpb.Att
@@ -43,7 +49,7 @@ func (vs *Server) packDepositsAndAttestations(ctx context.Context, head state.Be
eg.Go(func() error {
// Pack aggregated attestations which have not been included in the beacon chain.
localAtts, err := vs.packAttestations(egctx, head)
localAtts, err := vs.packAttestations(egctx, head, blkSlot)
if err != nil {
return status.Errorf(codes.Internal, "Could not get attestations to pack into block: %v", err)
}

View File

@@ -0,0 +1,17 @@
package validator
import (
"context"
"github.com/golang/protobuf/ptypes/empty"
"github.com/pkg/errors"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
)
func (vs *Server) GetPayloadAttestationData(ctx context.Context, req *ethpb.GetPayloadAttestationDataRequest) (*ethpb.PayloadAttestationData, error) {
return nil, errors.New("not implemented")
}
func (vs *Server) SubmitPayloadAttestation(ctx context.Context, in *ethpb.PayloadAttestationMessage) (*empty.Empty, error) {
return nil, errors.New("not implemented")
}

View File

@@ -5,6 +5,7 @@ go_library(
srcs = [
"error.go",
"interfaces.go",
"interfaces_epbs.go",
"prometheus.go",
],
importpath = "github.com/prysmaticlabs/prysm/v5/beacon-chain/state",

View File

@@ -60,6 +60,7 @@ type ReadOnlyBeaconState interface {
ReadOnlySyncCommittee
ReadOnlyDeposits
ReadOnlyConsolidations
ReadOnlyEpbsFields
ToProtoUnsafe() interface{}
ToProto() interface{}
GenesisTime() uint64
@@ -94,6 +95,7 @@ type WriteOnlyBeaconState interface {
WriteOnlyConsolidations
WriteOnlyWithdrawals
WriteOnlyDeposits
WriteOnlyEpbsFields
SetGenesisTime(val uint64) error
SetGenesisValidatorsRoot(val []byte) error
SetSlot(val primitives.Slot) error
@@ -200,6 +202,7 @@ type ReadOnlyWithdrawals interface {
NextWithdrawalIndex() (uint64, error)
PendingBalanceToWithdraw(idx primitives.ValidatorIndex) (uint64, error)
NumPendingPartialWithdrawals() (uint64, error)
HasPendingBalanceToWithdraw(idx primitives.ValidatorIndex) (bool, error)
}
// ReadOnlyParticipation defines a struct which only has read access to participation methods.

View File

@@ -0,0 +1,21 @@
package state
import (
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
)
type ReadOnlyEpbsFields interface {
IsParentBlockFull() bool
ExecutionPayloadHeader() *enginev1.ExecutionPayloadHeaderEPBS
LatestBlockHash() []byte
LatestFullSlot() primitives.Slot
LastWithdrawalsRoot() []byte
}
type WriteOnlyEpbsFields interface {
SetExecutionPayloadHeader(val *enginev1.ExecutionPayloadHeaderEPBS)
SetLatestBlockHash(val []byte)
SetLatestFullSlot(val primitives.Slot)
SetLastWithdrawalsRoot(val []byte)
}

View File

@@ -13,11 +13,13 @@ go_library(
"getters_checkpoint.go",
"getters_consolidation.go",
"getters_deposit_requests.go",
"getters_epbs.go",
"getters_eth1.go",
"getters_exit.go",
"getters_misc.go",
"getters_participation.go",
"getters_payload_header.go",
"getters_payload_header_epbs.go",
"getters_randao.go",
"getters_state.go",
"getters_sync_committee.go",
@@ -34,6 +36,7 @@ go_library(
"setters_churn.go",
"setters_consolidation.go",
"setters_deposit_requests.go",
"setters_epbs.go",
"setters_eth1.go",
"setters_misc.go",
"setters_participation.go",
@@ -46,6 +49,7 @@ go_library(
"spec_parameters.go",
"ssz.go",
"state_trie.go",
"state_trie_epbs.go",
"types.go",
"validator_index_cache.go",
],
@@ -98,6 +102,7 @@ go_test(
"getters_deposit_requests_test.go",
"getters_exit_test.go",
"getters_participation_test.go",
"getters_setters_epbs_test.go",
"getters_test.go",
"getters_validator_test.go",
"getters_withdrawal_test.go",
@@ -119,6 +124,7 @@ go_test(
"setters_withdrawal_test.go",
"state_fuzz_test.go",
"state_test.go",
"state_trie_epbs_test.go",
"state_trie_test.go",
"types_test.go",
"validator_index_cache_test.go",
@@ -152,6 +158,7 @@ go_test(
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
"//testing/util:go_default_library",
"//testing/util/random:go_default_library",
"//time/slots:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
"@com_github_golang_snappy//:go_default_library",

View File

@@ -60,6 +60,11 @@ type BeaconState struct {
latestExecutionPayloadHeaderElectra *enginev1.ExecutionPayloadHeaderElectra
nextWithdrawalIndex uint64
nextWithdrawalValidatorIndex primitives.ValidatorIndex
// ePBS fields
latestBlockHash [32]byte
latestFullSlot primitives.Slot
executionPayloadHeader *enginev1.ExecutionPayloadHeaderEPBS
lastWithdrawalsRoot [32]byte
// Electra fields
depositRequestsStartIndex uint64

View File

@@ -60,6 +60,11 @@ type BeaconState struct {
latestExecutionPayloadHeaderElectra *enginev1.ExecutionPayloadHeaderElectra
nextWithdrawalIndex uint64
nextWithdrawalValidatorIndex primitives.ValidatorIndex
// ePBS fields
latestBlockHash [32]byte
latestFullSlot primitives.Slot
executionPayloadHeader *enginev1.ExecutionPayloadHeaderEPBS
lastWithdrawalsRoot [32]byte
// Electra fields
depositRequestsStartIndex uint64

View File

@@ -0,0 +1,51 @@
package state_native
import (
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
)
// ExecutionPayloadHeader retrieves a copy of the execution payload header.
// It returns an error if the operation is not supported for the beacon state's version.
func (b *BeaconState) ExecutionPayloadHeader() *enginev1.ExecutionPayloadHeaderEPBS {
b.lock.RLock()
defer b.lock.RUnlock()
return b.executionPayloadHeaderVal()
}
// IsParentBlockFull checks if the last committed payload header was fulfilled.
// Returns true if both the beacon block and payload were present.
// Call this function on a beacon state before processing the execution payload header.
func (b *BeaconState) IsParentBlockFull() bool {
b.lock.RLock()
defer b.lock.RUnlock()
headerBlockHash := bytesutil.ToBytes32(b.executionPayloadHeader.BlockHash)
return headerBlockHash == b.latestBlockHash
}
// LatestBlockHash returns the latest block hash.
func (b *BeaconState) LatestBlockHash() []byte {
b.lock.RLock()
defer b.lock.RUnlock()
return b.latestBlockHash[:]
}
// LatestFullSlot returns the slot of the latest full block.
func (b *BeaconState) LatestFullSlot() primitives.Slot {
b.lock.RLock()
defer b.lock.RUnlock()
return b.latestFullSlot
}
// LastWithdrawalsRoot returns the latest withdrawal root.
func (b *BeaconState) LastWithdrawalsRoot() []byte {
b.lock.RLock()
defer b.lock.RUnlock()
return b.lastWithdrawalsRoot[:]
}

View File

@@ -0,0 +1,10 @@
package state_native
import (
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
)
func (b *BeaconState) executionPayloadHeaderVal() *enginev1.ExecutionPayloadHeaderEPBS {
return eth.CopyExecutionPayloadHeaderEPBS(b.executionPayloadHeader)
}

View File

@@ -0,0 +1,67 @@
package state_native
import (
"crypto/rand"
"testing"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native/types"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/prysmaticlabs/prysm/v5/testing/require"
"github.com/prysmaticlabs/prysm/v5/testing/util/random"
)
func Test_LatestExecutionPayloadHeader(t *testing.T) {
s := &BeaconState{version: version.EPBS}
_, err := s.LatestExecutionPayloadHeader()
require.ErrorContains(t, "unsupported version (epbs) for latest execution payload header", err)
}
func Test_SetLatestExecutionPayloadHeader(t *testing.T) {
s := &BeaconState{version: version.EPBS}
require.ErrorContains(t, "SetLatestExecutionPayloadHeader is not supported for epbs", s.SetLatestExecutionPayloadHeader(nil))
}
func Test_SetExecutionPayloadHeader(t *testing.T) {
s := &BeaconState{version: version.EPBS, dirtyFields: make(map[types.FieldIndex]bool)}
header := random.ExecutionPayloadHeader(t)
s.SetExecutionPayloadHeader(header)
require.Equal(t, true, s.dirtyFields[types.ExecutionPayloadHeader])
got := s.ExecutionPayloadHeader()
require.DeepEqual(t, got, header)
}
func Test_SetLatestBlockHash(t *testing.T) {
s := &BeaconState{version: version.EPBS, dirtyFields: make(map[types.FieldIndex]bool)}
b := make([]byte, fieldparams.RootLength)
_, err := rand.Read(b)
require.NoError(t, err)
s.SetLatestBlockHash(b)
require.Equal(t, true, s.dirtyFields[types.LatestBlockHash])
got := s.LatestBlockHash()
require.DeepEqual(t, got, b)
}
func Test_SetLatestFullSlot(t *testing.T) {
s := &BeaconState{version: version.EPBS, dirtyFields: make(map[types.FieldIndex]bool)}
s.SetLatestFullSlot(3)
require.Equal(t, true, s.dirtyFields[types.LatestFullSlot])
got := s.LatestFullSlot()
require.Equal(t, primitives.Slot(3), got)
}
func Test_SetLastWithdrawalsRoot(t *testing.T) {
s := &BeaconState{version: version.EPBS, dirtyFields: make(map[types.FieldIndex]bool)}
b := make([]byte, fieldparams.RootLength)
_, err := rand.Read(b)
require.NoError(t, err)
s.SetLastWithdrawalsRoot(b)
require.Equal(t, true, s.dirtyFields[types.LastWithdrawalsRoot])
got := s.LastWithdrawalsRoot()
require.DeepEqual(t, got, b)
}

View File

@@ -212,6 +212,49 @@ func (b *BeaconState) ToProtoUnsafe() interface{} {
PendingPartialWithdrawals: b.pendingPartialWithdrawals,
PendingConsolidations: b.pendingConsolidations,
}
case version.EPBS:
return &ethpb.BeaconStateEPBS{
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: b.inactivityScoresVal(),
CurrentSyncCommittee: b.currentSyncCommittee,
NextSyncCommittee: b.nextSyncCommittee,
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,
PendingBalanceDeposits: b.pendingBalanceDeposits,
PendingPartialWithdrawals: b.pendingPartialWithdrawals,
PendingConsolidations: b.pendingConsolidations,
LatestBlockHash: b.latestBlockHash[:],
LatestFullSlot: b.latestFullSlot,
LatestExecutionPayloadHeader: b.executionPayloadHeader,
LastWithdrawalsRoot: b.lastWithdrawalsRoot[:],
}
default:
return nil
}
@@ -236,6 +279,9 @@ func (b *BeaconState) ToProto() interface{} {
inactivityScores = b.inactivityScoresVal()
}
LatestBlockHashCopy := b.latestBlockHash
lastWithdrawalsRootCopy := b.lastWithdrawalsRoot
switch b.version {
case version.Phase0:
return &ethpb.BeaconState{
@@ -418,6 +464,49 @@ func (b *BeaconState) ToProto() interface{} {
PendingPartialWithdrawals: b.pendingPartialWithdrawalsVal(),
PendingConsolidations: b.pendingConsolidationsVal(),
}
case version.EPBS:
return &ethpb.BeaconStateEPBS{
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(),
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,
PendingBalanceDeposits: b.pendingBalanceDepositsVal(),
PendingPartialWithdrawals: b.pendingPartialWithdrawalsVal(),
PendingConsolidations: b.pendingConsolidationsVal(),
LatestBlockHash: LatestBlockHashCopy[:],
LatestFullSlot: b.latestFullSlot,
LatestExecutionPayloadHeader: b.executionPayloadHeaderVal(),
LastWithdrawalsRoot: lastWithdrawalsRootCopy[:],
}
default:
return nil
}

View File

@@ -501,3 +501,24 @@ func (b *BeaconState) PendingBalanceToWithdraw(idx primitives.ValidatorIndex) (u
}
return sum, nil
}
func (b *BeaconState) HasPendingBalanceToWithdraw(idx primitives.ValidatorIndex) (bool, error) {
if b.version < version.Electra {
return false, errNotSupported("HasPendingBalanceToWithdraw", b.version)
}
b.lock.RLock()
defer b.lock.RUnlock()
// TODO: Consider maintaining this value in the state, if it's a potential bottleneck.
// This is n*m complexity, but this method can only be called
// MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD per slot. A more optimized storage indexing such as a
// lookup map could be used to reduce the complexity marginally.
for _, w := range b.pendingPartialWithdrawals {
if w.Index == idx {
return true, nil
}
}
return false, nil
}

View File

@@ -162,3 +162,32 @@ func TestAggregateKeyFromIndices(t *testing.T) {
assert.Equal(t, true, aggKey.Equals(retKey), "unequal aggregated keys")
}
func TestHasPendingBalanceToWithdraw(t *testing.T) {
pb := &ethpb.BeaconStateElectra{
PendingPartialWithdrawals: []*ethpb.PendingPartialWithdrawal{
{
Amount: 100,
Index: 1,
},
{
Amount: 200,
Index: 2,
},
{
Amount: 300,
Index: 3,
},
},
}
state, err := statenative.InitializeFromProtoUnsafeElectra(pb)
require.NoError(t, err)
ok, err := state.HasPendingBalanceToWithdraw(1)
require.NoError(t, err)
require.Equal(t, true, ok)
ok, err = state.HasPendingBalanceToWithdraw(5)
require.NoError(t, err)
require.Equal(t, false, ok)
}

View File

@@ -154,7 +154,7 @@ func (b *BeaconState) ExpectedWithdrawals() ([]*enginev1.Withdrawal, uint64, err
if err != nil {
return nil, 0, errors.Wrapf(err, "could not retrieve balance at index %d", validatorIndex)
}
if helpers.IsFullyWithdrawableValidator(val, balance, epoch) {
if helpers.IsFullyWithdrawableValidator(val, balance, epoch, b.version) {
withdrawals = append(withdrawals, &enginev1.Withdrawal{
Index: withdrawalIndex,
ValidatorIndex: validatorIndex,
@@ -162,7 +162,7 @@ func (b *BeaconState) ExpectedWithdrawals() ([]*enginev1.Withdrawal, uint64, err
Amount: balance,
})
withdrawalIndex++
} else if helpers.IsPartiallyWithdrawableValidator(val, balance, epoch) {
} else if helpers.IsPartiallyWithdrawableValidator(val, balance, epoch, b.version) {
withdrawals = append(withdrawals, &enginev1.Withdrawal{
Index: withdrawalIndex,
ValidatorIndex: validatorIndex,

View File

@@ -41,6 +41,8 @@ func ComputeFieldRootsWithHasher(ctx context.Context, state *BeaconState) ([][]b
fieldRoots = make([][]byte, params.BeaconConfig().BeaconStateDenebFieldCount)
case version.Electra:
fieldRoots = make([][]byte, params.BeaconConfig().BeaconStateElectraFieldCount)
case version.EPBS:
fieldRoots = make([][]byte, params.BeaconConfig().BeaconStateEpbsFieldCount)
default:
return nil, fmt.Errorf("unknown state version %s", version.String(state.version))
}
@@ -260,6 +262,14 @@ func ComputeFieldRootsWithHasher(ctx context.Context, state *BeaconState) ([][]b
}
fieldRoots[types.LatestExecutionPayloadHeaderElectra.RealPosition()] = executionPayloadRoot[:]
}
if state.version == version.EPBS {
// Execution payload header root.
executionPayloadRoot, err := state.executionPayloadHeader.HashTreeRoot()
if err != nil {
return nil, err
}
fieldRoots[types.ExecutionPayloadHeader.RealPosition()] = executionPayloadRoot[:]
}
if state.version >= version.Capella {
// Next withdrawal index root.
@@ -327,5 +337,19 @@ func ComputeFieldRootsWithHasher(ctx context.Context, state *BeaconState) ([][]b
fieldRoots[types.PendingConsolidations.RealPosition()] = pcRoot[:]
}
if state.version >= version.EPBS {
// Latest block hash root.
latestBlockHashRoot := state.latestBlockHash[:]
fieldRoots[types.LatestBlockHash.RealPosition()] = latestBlockHashRoot
// Latest full slot root.
latestFullSlotRoot := ssz.Uint64Root(uint64(state.latestFullSlot))
fieldRoots[types.LatestFullSlot.RealPosition()] = latestFullSlotRoot[:]
// Last withdrawals root.
lastWithdrawalsRoot := state.lastWithdrawalsRoot[:]
fieldRoots[types.LastWithdrawalsRoot.RealPosition()] = lastWithdrawalsRoot
}
return fieldRoots, nil
}

View File

@@ -0,0 +1,44 @@
package state_native
import (
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native/types"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
)
// SetExecutionPayloadHeader sets the execution payload header for the beacon state.
func (b *BeaconState) SetExecutionPayloadHeader(h *enginev1.ExecutionPayloadHeaderEPBS) {
b.lock.Lock()
defer b.lock.Unlock()
b.executionPayloadHeader = h
b.markFieldAsDirty(types.ExecutionPayloadHeader)
}
// SetLatestBlockHash sets the latest block hash for the beacon state.
func (b *BeaconState) SetLatestBlockHash(h []byte) {
b.lock.Lock()
defer b.lock.Unlock()
b.latestBlockHash = bytesutil.ToBytes32(h)
b.markFieldAsDirty(types.LatestBlockHash)
}
// SetLatestFullSlot sets the latest full slot for the beacon state.
func (b *BeaconState) SetLatestFullSlot(s primitives.Slot) {
b.lock.Lock()
defer b.lock.Unlock()
b.latestFullSlot = s
b.markFieldAsDirty(types.LatestFullSlot)
}
// SetLastWithdrawalsRoot sets the latest withdrawals root for the beacon state.
func (b *BeaconState) SetLastWithdrawalsRoot(r []byte) {
b.lock.Lock()
defer b.lock.Unlock()
b.lastWithdrawalsRoot = bytesutil.ToBytes32(r)
b.markFieldAsDirty(types.LastWithdrawalsRoot)
}

View File

@@ -17,7 +17,7 @@ func (b *BeaconState) SetLatestExecutionPayloadHeader(val interfaces.ExecutionDa
b.lock.Lock()
defer b.lock.Unlock()
if b.version < version.Bellatrix {
if b.version < version.Bellatrix || b.version >= version.EPBS {
return errNotSupported("SetLatestExecutionPayloadHeader", b.version)
}

View File

@@ -7,7 +7,7 @@ import (
func (b *BeaconState) ProportionalSlashingMultiplier() (uint64, error) {
switch b.version {
case version.Bellatrix, version.Capella, version.Deneb, version.Electra:
case version.Bellatrix, version.Capella, version.Deneb, version.Electra, version.EPBS:
return params.BeaconConfig().ProportionalSlashingMultiplierBellatrix, nil
case version.Altair:
return params.BeaconConfig().ProportionalSlashingMultiplierAltair, nil
@@ -19,7 +19,7 @@ func (b *BeaconState) ProportionalSlashingMultiplier() (uint64, error) {
func (b *BeaconState) InactivityPenaltyQuotient() (uint64, error) {
switch b.version {
case version.Bellatrix, version.Capella, version.Deneb, version.Electra:
case version.Bellatrix, version.Capella, version.Deneb, version.Electra, version.EPBS:
return params.BeaconConfig().InactivityPenaltyQuotientBellatrix, nil
case version.Altair:
return params.BeaconConfig().InactivityPenaltyQuotientAltair, nil

View File

@@ -111,6 +111,27 @@ var electraFields = append(
types.PendingConsolidations,
)
var epbsFields = append(
altairFields,
types.NextWithdrawalIndex,
types.NextWithdrawalValidatorIndex,
types.HistoricalSummaries,
types.ExecutionPayloadHeader, // new in ePBS
types.DepositRequestsStartIndex, // electra fields start here
types.DepositBalanceToConsume,
types.ExitBalanceToConsume,
types.EarliestExitEpoch,
types.ConsolidationBalanceToConsume,
types.EarliestConsolidationEpoch,
types.PendingBalanceDeposits,
types.PendingPartialWithdrawals,
types.PendingConsolidations,
types.LatestBlockHash, // ePBS fields start here
types.LatestFullSlot,
types.ExecutionPayloadHeader,
types.LastWithdrawalsRoot,
)
const (
phase0SharedFieldRefCount = 10
altairSharedFieldRefCount = 11
@@ -118,12 +139,14 @@ const (
capellaSharedFieldRefCount = 14
denebSharedFieldRefCount = 14
electraSharedFieldRefCount = 17
epbsSharedFieldRefCount = 17
experimentalStatePhase0SharedFieldRefCount = 5
experimentalStateAltairSharedFieldRefCount = 5
experimentalStateBellatrixSharedFieldRefCount = 6
experimentalStateCapellaSharedFieldRefCount = 8
experimentalStateDenebSharedFieldRefCount = 8
experimentalStateElectraSharedFieldRefCount = 11
experimentalStateEpbsSharedFieldRefCount = 11
)
// InitializeFromProtoPhase0 the beacon state from a protobuf representation.
@@ -155,6 +178,11 @@ func InitializeFromProtoElectra(st *ethpb.BeaconStateElectra) (state.BeaconState
return InitializeFromProtoUnsafeElectra(proto.Clone(st).(*ethpb.BeaconStateElectra))
}
// InitializeFromProtoEpbs initializes the beacon state from its protobuf representation.
func InitializeFromProtoEpbs(st *ethpb.BeaconStateEPBS) (state.BeaconState, error) {
return InitializeFromProtoUnsafeEpbs(proto.Clone(st).(*ethpb.BeaconStateEPBS))
}
// InitializeFromProtoUnsafePhase0 directly uses the beacon state protobuf fields
// and sets them as fields of the BeaconState type.
func InitializeFromProtoUnsafePhase0(st *ethpb.BeaconState) (state.BeaconState, error) {
@@ -851,6 +879,8 @@ func (b *BeaconState) Copy() state.BeaconState {
fieldCount = params.BeaconConfig().BeaconStateDenebFieldCount
case version.Electra:
fieldCount = params.BeaconConfig().BeaconStateElectraFieldCount
case version.EPBS:
fieldCount = params.BeaconConfig().BeaconStateEpbsFieldCount
}
dst := &BeaconState{
@@ -868,6 +898,9 @@ func (b *BeaconState) Copy() state.BeaconState {
earliestExitEpoch: b.earliestExitEpoch,
consolidationBalanceToConsume: b.consolidationBalanceToConsume,
earliestConsolidationEpoch: b.earliestConsolidationEpoch,
latestBlockHash: b.latestBlockHash,
latestFullSlot: b.latestFullSlot,
lastWithdrawalsRoot: b.lastWithdrawalsRoot,
// Large arrays, infrequently changed, constant size.
blockRoots: b.blockRoots,
@@ -911,6 +944,7 @@ func (b *BeaconState) Copy() state.BeaconState {
latestExecutionPayloadHeaderCapella: b.latestExecutionPayloadHeaderCapellaVal(),
latestExecutionPayloadHeaderDeneb: b.latestExecutionPayloadHeaderDenebVal(),
latestExecutionPayloadHeaderElectra: b.latestExecutionPayloadHeaderElectraVal(),
executionPayloadHeader: b.executionPayloadHeaderVal(),
id: types.Enumerator.Inc(),
@@ -949,6 +983,8 @@ func (b *BeaconState) Copy() state.BeaconState {
dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, experimentalStateDenebSharedFieldRefCount)
case version.Electra:
dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, experimentalStateElectraSharedFieldRefCount)
case version.EPBS:
dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, experimentalStateEpbsSharedFieldRefCount)
}
} else {
switch b.version {
@@ -964,6 +1000,8 @@ func (b *BeaconState) Copy() state.BeaconState {
dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, denebSharedFieldRefCount)
case version.Electra:
dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, electraSharedFieldRefCount)
case version.EPBS:
dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, epbsSharedFieldRefCount)
}
}
@@ -1058,6 +1096,8 @@ func (b *BeaconState) initializeMerkleLayers(ctx context.Context) error {
b.dirtyFields = make(map[types.FieldIndex]bool, params.BeaconConfig().BeaconStateDenebFieldCount)
case version.Electra:
b.dirtyFields = make(map[types.FieldIndex]bool, params.BeaconConfig().BeaconStateElectraFieldCount)
case version.EPBS:
b.dirtyFields = make(map[types.FieldIndex]bool, params.BeaconConfig().BeaconStateEpbsFieldCount)
default:
return fmt.Errorf("unknown state version (%s) when computing dirty fields in merklization", version.String(b.version))
}
@@ -1304,6 +1344,14 @@ 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.LatestBlockHash:
return b.latestBlockHash, nil
case types.LatestFullSlot:
return ssz.Uint64Root(uint64(b.latestFullSlot)), nil
case types.ExecutionPayloadHeader:
return b.executionPayloadHeader.HashTreeRoot()
case types.LastWithdrawalsRoot:
return b.lastWithdrawalsRoot, nil
}
return [32]byte{}, errors.New("invalid field index provided")
}

View File

@@ -0,0 +1,147 @@
package state_native
import (
"runtime"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state/fieldtrie"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native/types"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state/stateutil"
"github.com/prysmaticlabs/prysm/v5/config/features"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
)
// InitializeFromProtoUnsafeEpbs constructs a BeaconState from its protobuf representation.
func InitializeFromProtoUnsafeEpbs(st *ethpb.BeaconStateEPBS) (*BeaconState, error) {
if st == nil {
return nil, errors.New("received nil state")
}
// Process historical roots.
hRoots := make([][32]byte, len(st.HistoricalRoots))
for i, root := range st.HistoricalRoots {
hRoots[i] = bytesutil.ToBytes32(root)
}
// Define the number of fields to track changes.
fieldCount := params.BeaconConfig().BeaconStateEpbsFieldCount
b := &BeaconState{
version: version.EPBS,
genesisTime: st.GenesisTime,
genesisValidatorsRoot: bytesutil.ToBytes32(st.GenesisValidatorsRoot),
slot: st.Slot,
fork: st.Fork,
latestBlockHeader: st.LatestBlockHeader,
historicalRoots: hRoots,
eth1Data: st.Eth1Data,
eth1DataVotes: st.Eth1DataVotes,
eth1DepositIndex: st.Eth1DepositIndex,
slashings: st.Slashings,
previousEpochParticipation: st.PreviousEpochParticipation,
currentEpochParticipation: st.CurrentEpochParticipation,
justificationBits: st.JustificationBits,
previousJustifiedCheckpoint: st.PreviousJustifiedCheckpoint,
currentJustifiedCheckpoint: st.CurrentJustifiedCheckpoint,
finalizedCheckpoint: st.FinalizedCheckpoint,
currentSyncCommittee: st.CurrentSyncCommittee,
nextSyncCommittee: st.NextSyncCommittee,
nextWithdrawalIndex: st.NextWithdrawalIndex,
nextWithdrawalValidatorIndex: st.NextWithdrawalValidatorIndex,
historicalSummaries: st.HistoricalSummaries,
depositRequestsStartIndex: st.DepositRequestsStartIndex,
depositBalanceToConsume: st.DepositBalanceToConsume,
exitBalanceToConsume: st.ExitBalanceToConsume,
earliestExitEpoch: st.EarliestExitEpoch,
consolidationBalanceToConsume: st.ConsolidationBalanceToConsume,
earliestConsolidationEpoch: st.EarliestConsolidationEpoch,
pendingBalanceDeposits: st.PendingBalanceDeposits,
pendingPartialWithdrawals: st.PendingPartialWithdrawals,
pendingConsolidations: st.PendingConsolidations,
// ePBS fields
latestBlockHash: bytesutil.ToBytes32(st.LatestBlockHash),
latestFullSlot: st.LatestFullSlot,
executionPayloadHeader: st.LatestExecutionPayloadHeader,
lastWithdrawalsRoot: bytesutil.ToBytes32(st.LastWithdrawalsRoot),
dirtyFields: make(map[types.FieldIndex]bool, fieldCount),
dirtyIndices: make(map[types.FieldIndex][]uint64, fieldCount),
stateFieldLeaves: make(map[types.FieldIndex]*fieldtrie.FieldTrie, fieldCount),
rebuildTrie: make(map[types.FieldIndex]bool, fieldCount),
valMapHandler: stateutil.NewValMapHandler(st.Validators),
}
if features.Get().EnableExperimentalState {
b.blockRootsMultiValue = NewMultiValueBlockRoots(st.BlockRoots)
b.stateRootsMultiValue = NewMultiValueStateRoots(st.StateRoots)
b.randaoMixesMultiValue = NewMultiValueRandaoMixes(st.RandaoMixes)
b.balancesMultiValue = NewMultiValueBalances(st.Balances)
b.validatorsMultiValue = NewMultiValueValidators(st.Validators)
b.inactivityScoresMultiValue = NewMultiValueInactivityScores(st.InactivityScores)
b.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, experimentalStateEpbsSharedFieldRefCount)
} else {
bRoots := make([][32]byte, fieldparams.BlockRootsLength)
for i, r := range st.BlockRoots {
bRoots[i] = bytesutil.ToBytes32(r)
}
b.blockRoots = bRoots
sRoots := make([][32]byte, fieldparams.StateRootsLength)
for i, r := range st.StateRoots {
sRoots[i] = bytesutil.ToBytes32(r)
}
b.stateRoots = sRoots
mixes := make([][32]byte, fieldparams.RandaoMixesLength)
for i, m := range st.RandaoMixes {
mixes[i] = bytesutil.ToBytes32(m)
}
b.randaoMixes = mixes
b.balances = st.Balances
b.validators = st.Validators
b.inactivityScores = st.InactivityScores
b.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, epbsSharedFieldRefCount)
}
for _, f := range epbsFields {
b.dirtyFields[f] = true
b.rebuildTrie[f] = true
b.dirtyIndices[f] = []uint64{}
trie, err := fieldtrie.NewFieldTrie(f, types.BasicArray, nil, 0)
if err != nil {
return nil, err
}
b.stateFieldLeaves[f] = trie
}
// Initialize field reference tracking for shared data.
b.sharedFieldReferences[types.HistoricalRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[types.Eth1DataVotes] = stateutil.NewRef(1)
b.sharedFieldReferences[types.Slashings] = stateutil.NewRef(1)
b.sharedFieldReferences[types.PreviousEpochParticipationBits] = stateutil.NewRef(1)
b.sharedFieldReferences[types.CurrentEpochParticipationBits] = stateutil.NewRef(1)
b.sharedFieldReferences[types.HistoricalSummaries] = stateutil.NewRef(1)
b.sharedFieldReferences[types.PendingBalanceDeposits] = stateutil.NewRef(1)
b.sharedFieldReferences[types.PendingPartialWithdrawals] = stateutil.NewRef(1)
b.sharedFieldReferences[types.PendingConsolidations] = stateutil.NewRef(1)
if !features.Get().EnableExperimentalState {
b.sharedFieldReferences[types.BlockRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[types.StateRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[types.RandaoMixes] = stateutil.NewRef(1)
b.sharedFieldReferences[types.Balances] = stateutil.NewRef(1)
b.sharedFieldReferences[types.Validators] = stateutil.NewRef(1)
b.sharedFieldReferences[types.InactivityScores] = stateutil.NewRef(1)
}
state.Count.Inc()
// Finalizer runs when dst is being destroyed in garbage collection.
runtime.SetFinalizer(b, finalizerCleanup)
return b, nil
}

View File

@@ -0,0 +1,65 @@
package state_native
import (
"context"
"testing"
"github.com/prysmaticlabs/prysm/v5/testing/require"
"github.com/prysmaticlabs/prysm/v5/testing/util/random"
)
func Test_InitializeFromProtoEpbs(t *testing.T) {
st := random.BeaconState(t)
// Cache initial values to check against after initialization.
latestBlockHash := st.LatestBlockHash
latestFullSlot := st.LatestFullSlot
header := st.LatestExecutionPayloadHeader
lastWithdrawalsRoot := st.LastWithdrawalsRoot
s, err := InitializeFromProtoEpbs(st)
require.NoError(t, err)
// Assert that initial values match those in the new state.
gotLatestBlockHash := s.LatestBlockHash()
require.DeepEqual(t, latestBlockHash, gotLatestBlockHash)
gotLatestFullSlot := s.LatestFullSlot()
require.Equal(t, latestFullSlot, gotLatestFullSlot)
gotHeader := s.ExecutionPayloadHeader()
require.DeepEqual(t, header, gotHeader)
gotLastWithdrawalsRoot := s.LastWithdrawalsRoot()
require.DeepEqual(t, lastWithdrawalsRoot, gotLastWithdrawalsRoot)
}
func Test_CopyEpbs(t *testing.T) {
st := random.BeaconState(t)
s, err := InitializeFromProtoUnsafeEpbs(st)
require.NoError(t, err)
// Test shallow copy.
sNoCopy := s
require.DeepEqual(t, s.executionPayloadHeader, sNoCopy.executionPayloadHeader)
// Modify a field to check if it reflects in the shallow copy.
s.executionPayloadHeader.Slot = 100
require.Equal(t, s.executionPayloadHeader, sNoCopy.executionPayloadHeader)
// Copy the state
sCopy := s.Copy()
require.NoError(t, err)
header := sCopy.ExecutionPayloadHeader()
require.DeepEqual(t, s.executionPayloadHeader, header)
// Modify the original to check if the copied state is independent.
s.executionPayloadHeader.Slot = 200
require.DeepNotEqual(t, s.executionPayloadHeader, header)
}
func Test_HashTreeRootEpbs(t *testing.T) {
st := random.BeaconState(t)
s, err := InitializeFromProtoUnsafeEpbs(st)
require.NoError(t, err)
_, err = s.HashTreeRoot(context.Background())
require.NoError(t, err)
}

View File

@@ -114,6 +114,14 @@ func (f FieldIndex) String() string {
return "pendingPartialWithdrawals"
case PendingConsolidations:
return "pendingConsolidations"
case LatestBlockHash: // ePBS fields start here
return "LatestBlockHash"
case LatestFullSlot:
return "LatestFullSlot"
case ExecutionPayloadHeader:
return "ExecutionPayloadHeader"
case LastWithdrawalsRoot:
return "LastWithdrawalsRoot"
default:
return fmt.Sprintf("unknown field index number: %d", f)
}
@@ -171,7 +179,8 @@ func (f FieldIndex) RealPosition() int {
return 22
case NextSyncCommittee:
return 23
case LatestExecutionPayloadHeader, LatestExecutionPayloadHeaderCapella, LatestExecutionPayloadHeaderDeneb, LatestExecutionPayloadHeaderElectra:
// ExecutionPayloadHeader is from ePBS.
case LatestExecutionPayloadHeader, LatestExecutionPayloadHeaderCapella, LatestExecutionPayloadHeaderDeneb, LatestExecutionPayloadHeaderElectra, ExecutionPayloadHeader:
return 24
case NextWithdrawalIndex:
return 25
@@ -197,6 +206,12 @@ func (f FieldIndex) RealPosition() int {
return 35
case PendingConsolidations:
return 36
case LatestBlockHash: // ePBS fields start here
return 41
case LatestFullSlot:
return 42
case LastWithdrawalsRoot:
return 43
default:
return -1
}
@@ -250,6 +265,7 @@ const (
LatestExecutionPayloadHeaderCapella
LatestExecutionPayloadHeaderDeneb
LatestExecutionPayloadHeaderElectra
ExecutionPayloadHeader
NextWithdrawalIndex
NextWithdrawalValidatorIndex
HistoricalSummaries
@@ -262,6 +278,9 @@ const (
PendingBalanceDeposits // Electra: EIP-7251
PendingPartialWithdrawals // Electra: EIP-7251
PendingConsolidations // Electra: EIP-7251
LatestBlockHash // ePBS fields start here
LatestFullSlot
LastWithdrawalsRoot
)
// Enumerator keeps track of the number of states created since the node's start.

View File

@@ -16,7 +16,6 @@ import (
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"google.golang.org/protobuf/proto"
)
var errNilPubsubMessage = errors.New("nil pubsub message")
@@ -52,7 +51,7 @@ func (s *Service) decodePubsubMessage(msg *pubsub.Message) (ssz.Unmarshaler, err
if base == nil {
return nil, p2p.ErrMessageNotMapped
}
m, ok := proto.Clone(base).(ssz.Unmarshaler)
m, ok := base.(ssz.Unmarshaler)
if !ok {
return nil, errors.Errorf("message of %T does not support marshaller interface", base)
}

View File

@@ -403,6 +403,26 @@ func TestSidecarInclusionProven(t *testing.T) {
require.NotNil(t, v.results.result(RequireSidecarInclusionProven))
}
func TestSidecarInclusionProvenElectra(t *testing.T) {
// GenerateTestDenebBlockWithSidecar is supposed to generate valid inclusion proofs
_, blobs := util.GenerateTestElectraBlockWithSidecar(t, [32]byte{}, 1, 1)
b := blobs[0]
ini := Initializer{}
v := ini.NewBlobVerifier(b, GossipSidecarRequirements)
require.NoError(t, v.SidecarInclusionProven())
require.Equal(t, true, v.results.executed(RequireSidecarInclusionProven))
require.NoError(t, v.results.result(RequireSidecarInclusionProven))
// Invert bits of the first byte of the body root to mess up the proof
byte0 := b.SignedBlockHeader.Header.BodyRoot[0]
b.SignedBlockHeader.Header.BodyRoot[0] = byte0 ^ 255
v = ini.NewBlobVerifier(b, GossipSidecarRequirements)
require.ErrorIs(t, v.SidecarInclusionProven(), ErrSidecarInclusionProofInvalid)
require.Equal(t, true, v.results.executed(RequireSidecarInclusionProven))
require.NotNil(t, v.results.result(RequireSidecarInclusionProven))
}
func TestSidecarKzgProofVerified(t *testing.T) {
// GenerateTestDenebBlockWithSidecar is supposed to generate valid commitments
_, blobs := util.GenerateTestDenebBlockWithSidecar(t, [32]byte{}, 1, 1)

View File

@@ -212,6 +212,10 @@ func before(ctx *cli.Context) error {
return errors.Wrap(err, "failed to set max fd limits")
}
if err := features.ValidateNetworkFlags(ctx); err != nil {
return errors.Wrap(err, "provided multiple network flags")
}
return cmd.ValidateNoArgs(ctx)
}

View File

@@ -175,6 +175,9 @@ var Commands = []*cli.Command{
if err := cmd.LoadFlagsFromConfig(cliCtx, cliCtx.Command.Flags); err != nil {
return err
}
if err := features.ValidateNetworkFlags(cliCtx); err != nil {
return err
}
if err := tos.VerifyTosAcceptedOrPrompt(cliCtx); err != nil {
return err
}

View File

@@ -193,6 +193,10 @@ func main() {
return errors.Wrap(err, "failed to setup debug")
}
if err := features.ValidateNetworkFlags(ctx); err != nil {
return errors.Wrap(err, "provided multiple network flags")
}
return cmd.ValidateNoArgs(ctx)
},
After: func(ctx *cli.Context) error {

View File

@@ -20,6 +20,8 @@ The process for implementing new features using this package is as follows:
package features
import (
"fmt"
"strings"
"sync"
"time"
@@ -337,3 +339,25 @@ func logDisabled(flag cli.DocGenerationFlag) {
}
log.WithField(name, flag.GetUsage()).Warn(disabledFeatureFlag)
}
// ValidateNetworkFlags validates provided flags and
// prevents beacon node or validator to start
// if more than one network flag is provided
func ValidateNetworkFlags(ctx *cli.Context) error {
networkFlagsCount := 0
for _, flag := range NetworkFlags {
if ctx.IsSet(flag.Names()[0]) {
networkFlagsCount++
if networkFlagsCount > 1 {
// using a forLoop so future addition
// doesn't require changes in this function
var flagNames []string
for _, flag := range NetworkFlags {
flagNames = append(flagNames, "--"+flag.Names()[0])
}
return fmt.Errorf("cannot use more than one network flag at the same time. Possible network flags are: %s", strings.Join(flagNames, ", "))
}
}
}
return nil
}

View File

@@ -46,3 +46,50 @@ func TestConfigureBeaconConfig(t *testing.T) {
c := Get()
assert.Equal(t, true, c.EnableSlasher)
}
func TestValidateNetworkFlags(t *testing.T) {
// Define the test cases
tests := []struct {
name string
args []string
wantErr bool
}{
{
name: "No network flags",
args: []string{"command"},
wantErr: false,
},
{
name: "One network flag",
args: []string{"command", "--sepolia"},
wantErr: false,
},
{
name: "Two network flags",
args: []string{"command", "--sepolia", "--holesky"},
wantErr: true,
},
{
name: "All network flags",
args: []string{"command", "--sepolia", "--holesky", "--mainnet"},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Create a new CLI app with the ValidateNetworkFlags function as the Before action
app := &cli.App{
Before: ValidateNetworkFlags,
Action: func(c *cli.Context) error {
return nil
},
// Set the network flags for the app
Flags: NetworkFlags,
}
err := app.Run(tt.args)
if (err != nil) != tt.wantErr {
t.Errorf("ValidateNetworkFlags() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

View File

@@ -14,6 +14,7 @@ const (
CurrentEpochAttestationsLength = 4096 // MAX_ATTESTATIONS * SLOTS_PER_EPOCH
SlashingsLength = 8192 // EPOCHS_PER_SLASHINGS_VECTOR
SyncCommitteeLength = 512 // SYNC_COMMITTEE_SIZE
PTCSize = 512 // PTC_SIZE [New in ePBS]
RootLength = 32 // RootLength defines the byte length of a Merkle root.
BLSSignatureLength = 96 // BLSSignatureLength defines the byte length of a BLSSignature.
BLSPubkeyLength = 48 // BLSPubkeyLength defines the byte length of a BLSSignature.
@@ -28,6 +29,7 @@ const (
MaxWithdrawalsPerPayload = 16 // MaxWithdrawalsPerPayloadLength defines the maximum number of withdrawals that can be included in a payload.
MaxBlobsPerBlock = 6 // MaxBlobsPerBlock defines the maximum number of blobs with respect to consensus rule can be included in a block.
MaxBlobCommitmentsPerBlock = 4096 // MaxBlobCommitmentsPerBlock defines the theoretical limit of blobs can be included in a block.
MaxPayloadAttestationsPerBlock = 4 // MAX_PAYLOAD_ATTESTATIONS [New in ePBS]
LogMaxBlobCommitments = 12 // Log_2 of MaxBlobCommitmentsPerBlock
BlobLength = 131072 // BlobLength defines the byte length of a blob.
BlobSize = 131072 // defined to match blob.size in bazel ssz codegen

View File

@@ -14,6 +14,7 @@ const (
CurrentEpochAttestationsLength = 1024 // MAX_ATTESTATIONS * SLOTS_PER_EPOCH
SlashingsLength = 64 // EPOCHS_PER_SLASHINGS_VECTOR
SyncCommitteeLength = 32 // SYNC_COMMITTEE_SIZE
PTCSize = 32 // PTC_SIZE [New in ePBS]
RootLength = 32 // RootLength defines the byte length of a Merkle root.
BLSSignatureLength = 96 // BLSSignatureLength defines the byte length of a BLSSignature.
BLSPubkeyLength = 48 // BLSPubkeyLength defines the byte length of a BLSSignature.
@@ -28,6 +29,7 @@ const (
MaxWithdrawalsPerPayload = 4 // MaxWithdrawalsPerPayloadLength defines the maximum number of withdrawals that can be included in a payload.
MaxBlobsPerBlock = 6 // MaxBlobsPerBlock defines the maximum number of blobs with respect to consensus rule can be included in a block.
MaxBlobCommitmentsPerBlock = 16 // MaxBlobCommitmentsPerBlock defines the theoretical limit of blobs can be included in a block.
MaxPayloadAttestationsPerBlock = 4 // MAX_PAYLOAD_ATTESTATIONS [New in ePBS]
LogMaxBlobCommitments = 4 // Log_2 of MaxBlobCommitmentsPerBlock
BlobLength = 131072 // BlobLength defines the byte length of a blob.
BlobSize = 131072 // defined to match blob.size in bazel ssz codegen

View File

@@ -126,6 +126,8 @@ type BeaconChainConfig struct {
DomainApplicationBuilder [4]byte `yaml:"DOMAIN_APPLICATION_BUILDER" spec:"true"` // DomainApplicationBuilder defines the BLS signature domain for application builder.
DomainBLSToExecutionChange [4]byte `yaml:"DOMAIN_BLS_TO_EXECUTION_CHANGE" spec:"true"` // DomainBLSToExecutionChange defines the BLS signature domain to change withdrawal addresses to ETH1 prefix
DomainConsolidation [4]byte `yaml:"DOMAIN_CONSOLIDATION" spec:"true"`
DomainBeaconBuilder [4]byte `yaml:"DOMAIN_BEACON_BUILDER" spec:"false"` // DomainBeaconBuilder defines the BLS signature domain used by builders [New in ePBS]
DomainPTCAttester [4]byte `yaml:"DOMAIN_PTC_ATTESTER" spec:"false"` // DomainPTCAttester defines the BLS signature domain used by PTC members [New in ePBS]
// Prysm constants.
GweiPerEth uint64 // GweiPerEth is the amount of gwei corresponding to 1 eth.
@@ -146,6 +148,7 @@ type BeaconChainConfig struct {
BeaconStateCapellaFieldCount int // BeaconStateCapellaFieldCount defines how many fields are in beacon state post upgrade to Capella.
BeaconStateDenebFieldCount int // BeaconStateDenebFieldCount defines how many fields are in beacon state post upgrade to Deneb.
BeaconStateElectraFieldCount int // BeaconStateElectraFieldCount defines how many fields are in beacon state post upgrade to Electra.
BeaconStateEpbsFieldCount int // BeaconStateEpbsFieldCount defines how many fields are in beacon state post upgrade to ePBS.
// Slasher constants.
WeakSubjectivityPeriod primitives.Epoch // WeakSubjectivityPeriod defines the time period expressed in number of epochs were proof of stake network should validate block headers and attestations for slashable events.
@@ -166,6 +169,8 @@ type BeaconChainConfig struct {
DenebForkEpoch primitives.Epoch `yaml:"DENEB_FORK_EPOCH" spec:"true"` // DenebForkEpoch is used to represent the assigned fork epoch for deneb.
ElectraForkVersion []byte `yaml:"ELECTRA_FORK_VERSION" spec:"true"` // ElectraForkVersion is used to represent the fork version for deneb.
ElectraForkEpoch primitives.Epoch `yaml:"ELECTRA_FORK_EPOCH" spec:"true"` // ElectraForkEpoch is used to represent the assigned fork epoch for deneb.
EPBSForkVersion []byte // EPBSForkVersion is used to represent the fork version for ePBS.
EPBSForkEpoch primitives.Epoch // EPBSForkEpoch is used to represent the assigned fork epoch for ePBS.
ForkVersionSchedule map[[fieldparams.VersionLength]byte]primitives.Epoch // Schedule of fork epochs by version.
ForkVersionNames map[[fieldparams.VersionLength]byte]string // Human-readable names of fork versions.
@@ -313,6 +318,7 @@ func ConfigForkVersions(b *BeaconChainConfig) map[[fieldparams.VersionLength]byt
bytesutil.ToBytes4(b.CapellaForkVersion): version.Capella,
bytesutil.ToBytes4(b.DenebForkVersion): version.Deneb,
bytesutil.ToBytes4(b.ElectraForkVersion): version.Electra,
bytesutil.ToBytes4(b.EPBSForkVersion): version.EPBS,
}
}

View File

@@ -29,6 +29,8 @@ const (
mainnetDenebForkEpoch = 269568 // March 13, 2024, 13:55:35 UTC
// Electra Fork Epoch for mainnet config
mainnetElectraForkEpoch = math.MaxUint64 // Far future / to be defined
// ePBS Fork Epoch for mainnet config.
mainnetEPBSForkEpoch = math.MaxUint64
)
var mainnetNetworkConfig = &NetworkConfig{
@@ -194,6 +196,7 @@ var mainnetBeaconConfig = &BeaconChainConfig{
BeaconStateCapellaFieldCount: 28,
BeaconStateDenebFieldCount: 28,
BeaconStateElectraFieldCount: 37,
BeaconStateEpbsFieldCount: 44,
// Slasher related values.
WeakSubjectivityPeriod: 54000,
@@ -216,6 +219,8 @@ var mainnetBeaconConfig = &BeaconChainConfig{
DenebForkEpoch: mainnetDenebForkEpoch,
ElectraForkVersion: []byte{5, 0, 0, 0},
ElectraForkEpoch: mainnetElectraForkEpoch,
EPBSForkVersion: []byte{6, 0, 0, 0},
EPBSForkEpoch: mainnetEPBSForkEpoch,
// New values introduced in Altair hard fork 1.
// Participation flag indices.
@@ -335,6 +340,7 @@ func FillTestVersions(c *BeaconChainConfig, b byte) {
c.CapellaForkVersion = make([]byte, fieldparams.VersionLength)
c.DenebForkVersion = make([]byte, fieldparams.VersionLength)
c.ElectraForkVersion = make([]byte, fieldparams.VersionLength)
c.EPBSForkVersion = make([]byte, fieldparams.VersionLength)
c.GenesisForkVersion[fieldparams.VersionLength-1] = b
c.AltairForkVersion[fieldparams.VersionLength-1] = b
@@ -342,6 +348,7 @@ func FillTestVersions(c *BeaconChainConfig, b byte) {
c.CapellaForkVersion[fieldparams.VersionLength-1] = b
c.DenebForkVersion[fieldparams.VersionLength-1] = b
c.ElectraForkVersion[fieldparams.VersionLength-1] = b
c.EPBSForkVersion[fieldparams.VersionLength-1] = b
c.GenesisForkVersion[0] = 0
c.AltairForkVersion[0] = 1
@@ -349,4 +356,5 @@ func FillTestVersions(c *BeaconChainConfig, b byte) {
c.CapellaForkVersion[0] = 3
c.DenebForkVersion[0] = 4
c.ElectraForkVersion[0] = 5
c.EPBSForkVersion[0] = 6
}

View File

@@ -41,11 +41,14 @@ go_test(
srcs = [
"execution_test.go",
"factory_test.go",
"getters_epbs_test.go",
"getters_test.go",
"kzg_test.go",
"proto_epbs_test.go",
"proto_test.go",
"roblob_test.go",
"roblock_test.go",
"setters_test.go",
],
embed = [":go_default_library"],
deps = [

View File

@@ -74,6 +74,10 @@ func NewSignedBeaconBlock(i interface{}) (interfaces.SignedBeaconBlock, error) {
return initBlindedSignedBlockFromProtoElectra(b)
case *eth.GenericSignedBeaconBlock_BlindedElectra:
return initBlindedSignedBlockFromProtoElectra(b.BlindedElectra)
case *eth.GenericSignedBeaconBlock_Epbs:
return initSignedBlockFromProtoEPBS(b.Epbs)
case *eth.SignedBeaconBlockEpbs:
return initSignedBlockFromProtoEPBS(b)
default:
return nil, errors.Wrapf(ErrUnsupportedSignedBeaconBlock, "unable to create block from type %T", i)
}
@@ -124,6 +128,10 @@ func NewBeaconBlock(i interface{}) (interfaces.ReadOnlyBeaconBlock, error) {
return initBlindedBlockFromProtoElectra(b)
case *eth.GenericBeaconBlock_BlindedElectra:
return initBlindedBlockFromProtoElectra(b.BlindedElectra)
case *eth.GenericBeaconBlock_Epbs:
return initBlockFromProtoEpbs(b.Epbs)
case *eth.BeaconBlockEpbs:
return initBlockFromProtoEpbs(b)
default:
return nil, errors.Wrapf(errUnsupportedBeaconBlock, "unable to create block from type %T", i)
}
@@ -154,6 +162,8 @@ func NewBeaconBlockBody(i interface{}) (interfaces.ReadOnlyBeaconBlockBody, erro
return initBlockBodyFromProtoElectra(b)
case *eth.BlindedBeaconBlockBodyElectra:
return initBlindedBlockBodyFromProtoElectra(b)
case *eth.BeaconBlockBodyEpbs:
return initBlockBodyFromProtoEpbs(b)
default:
return nil, errors.Wrapf(errUnsupportedBeaconBlockBody, "unable to create block body from type %T", i)
}
@@ -233,6 +243,12 @@ func BuildSignedBeaconBlock(blk interfaces.ReadOnlyBeaconBlock, signature []byte
return nil, errIncorrectBlockVersion
}
return NewSignedBeaconBlock(&eth.SignedBeaconBlockElectra{Block: pb, Signature: signature})
case version.EPBS:
pb, ok := pb.(*eth.BeaconBlockEpbs)
if !ok {
return nil, errIncorrectBlockVersion
}
return NewSignedBeaconBlock(&eth.SignedBeaconBlockEpbs{Block: pb, Signature: signature})
default:
return nil, errUnsupportedBeaconBlock
}
@@ -247,6 +263,9 @@ func BuildSignedBeaconBlockFromExecutionPayload(blk interfaces.ReadOnlySignedBea
if !blk.IsBlinded() {
return nil, errNonBlindedSignedBeaconBlock
}
if blk.Version() >= version.EPBS {
return nil, errors.Wrap(errUnsupportedBeaconBlock, "post epbs blocks no longer need to be unblind")
}
b := blk.Block()
payloadHeader, err := b.Body().Execution()
if err != nil {

View File

@@ -161,6 +161,26 @@ func Test_NewSignedBeaconBlock(t *testing.T) {
assert.Equal(t, version.Deneb, b.Version())
assert.Equal(t, true, b.IsBlinded())
})
t.Run("GenericSignedBeaconBlock_Epbs", func(t *testing.T) {
pb := &eth.GenericSignedBeaconBlock_Epbs{
Epbs: &eth.SignedBeaconBlockEpbs{
Block: &eth.BeaconBlockEpbs{
Body: &eth.BeaconBlockBodyEpbs{},
},
},
}
b, err := NewSignedBeaconBlock(pb)
require.NoError(t, err)
assert.Equal(t, version.EPBS, b.Version())
})
t.Run("SignedBeaconBlockEpbs", func(t *testing.T) {
pb := &eth.SignedBeaconBlockEpbs{
Block: &eth.BeaconBlockEpbs{
Body: &eth.BeaconBlockBodyEpbs{}}}
b, err := NewSignedBeaconBlock(pb)
require.NoError(t, err)
assert.Equal(t, version.EPBS, b.Version())
})
t.Run("nil", func(t *testing.T) {
_, err := NewSignedBeaconBlock(nil)
assert.ErrorContains(t, "received nil object", err)
@@ -276,6 +296,18 @@ func Test_NewBeaconBlock(t *testing.T) {
assert.Equal(t, version.Deneb, b.Version())
assert.Equal(t, true, b.IsBlinded())
})
t.Run("GenericBeaconBlock_Epbs", func(t *testing.T) {
pb := &eth.GenericBeaconBlock_Epbs{Epbs: &eth.BeaconBlockEpbs{Body: &eth.BeaconBlockBodyEpbs{}}}
b, err := NewBeaconBlock(pb)
require.NoError(t, err)
assert.Equal(t, version.EPBS, b.Version())
})
t.Run("BeaconBlockEpbs", func(t *testing.T) {
pb := &eth.BeaconBlockEpbs{Body: &eth.BeaconBlockBodyEpbs{}}
b, err := NewBeaconBlock(pb)
require.NoError(t, err)
assert.Equal(t, version.EPBS, b.Version())
})
t.Run("nil", func(t *testing.T) {
_, err := NewBeaconBlock(nil)
assert.ErrorContains(t, "received nil object", err)
@@ -354,6 +386,14 @@ func Test_NewBeaconBlockBody(t *testing.T) {
assert.Equal(t, version.Deneb, b.version)
assert.Equal(t, true, b.IsBlinded())
})
t.Run("BeaconBlockBodyEpbs", func(t *testing.T) {
pb := &eth.BeaconBlockBodyEpbs{}
i, err := NewBeaconBlockBody(pb)
require.NoError(t, err)
b, ok := i.(*BeaconBlockBody)
require.Equal(t, true, ok)
assert.Equal(t, version.EPBS, b.version)
})
t.Run("nil", func(t *testing.T) {
_, err := NewBeaconBlockBody(nil)
assert.ErrorContains(t, "received nil object", err)
@@ -425,6 +465,13 @@ func Test_BuildSignedBeaconBlock(t *testing.T) {
assert.Equal(t, version.Deneb, sb.Version())
assert.Equal(t, true, sb.IsBlinded())
})
t.Run("Epbs", func(t *testing.T) {
b := &BeaconBlock{version: version.EPBS, body: &BeaconBlockBody{version: version.EPBS}}
sb, err := BuildSignedBeaconBlock(b, sig[:])
require.NoError(t, err)
assert.DeepEqual(t, sig, sb.Signature())
assert.Equal(t, version.EPBS, sb.Version())
})
}
func TestBuildSignedBeaconBlockFromExecutionPayload(t *testing.T) {

View File

@@ -15,6 +15,11 @@ import (
"github.com/prysmaticlabs/prysm/v5/runtime/version"
)
var (
// ErrAlreadyUnblinded is returned when trying to unblind a full block.
ErrAlreadyUnblinded = errors.New("cannot unblind if a full block")
)
// BeaconBlockIsNil checks if any composite field of input signed beacon block is nil.
// Access to these nil fields will result in run time panic,
// it is recommended to run these checks as first line of defense.
@@ -85,7 +90,9 @@ func (b *SignedBeaconBlock) Copy() (interfaces.SignedBeaconBlock, error) {
}
cp := eth.CopySignedBeaconBlockElectra(pb.(*eth.SignedBeaconBlockElectra))
return initSignedBlockFromProtoElectra(cp)
case version.EPBS:
cp := eth.CopySignedBeaconBlockEPBS(pb.(*eth.SignedBeaconBlockEpbs))
return initSignedBlockFromProtoEPBS(cp)
default:
return nil, errIncorrectBlockVersion
}
@@ -142,6 +149,10 @@ func (b *SignedBeaconBlock) PbGenericBlock() (*eth.GenericSignedBeaconBlock, err
return &eth.GenericSignedBeaconBlock{
Block: &eth.GenericSignedBeaconBlock_Electra{Electra: pb.(*eth.SignedBeaconBlockContentsElectra)},
}, nil
case version.EPBS:
return &eth.GenericSignedBeaconBlock{
Block: &eth.GenericSignedBeaconBlock_Epbs{Epbs: pb.(*eth.SignedBeaconBlockEpbs)},
}, nil
default:
return nil, errIncorrectBlockVersion
}
@@ -149,7 +160,7 @@ func (b *SignedBeaconBlock) PbGenericBlock() (*eth.GenericSignedBeaconBlock, err
// ToBlinded converts a non-blinded block to its blinded equivalent.
func (b *SignedBeaconBlock) ToBlinded() (interfaces.ReadOnlySignedBeaconBlock, error) {
if b.version < version.Bellatrix {
if b.version < version.Bellatrix || b.version >= version.EPBS {
return nil, ErrUnsupportedVersion
}
if b.IsBlinded() {
@@ -287,11 +298,11 @@ func (b *SignedBeaconBlock) ToBlinded() (interfaces.ReadOnlySignedBeaconBlock, e
}
func (b *SignedBeaconBlock) Unblind(e interfaces.ExecutionData) error {
if e.IsNil() {
if e == nil || e.IsNil() {
return errors.New("cannot unblind with nil execution data")
}
if !b.IsBlinded() {
return errors.New("cannot unblind if the block is already unblinded")
return ErrAlreadyUnblinded
}
payloadRoot, err := e.HashTreeRoot()
if err != nil {
@@ -321,7 +332,8 @@ func (b *SignedBeaconBlock) Version() int {
// IsBlinded metadata on whether a block is blinded
func (b *SignedBeaconBlock) IsBlinded() bool {
return b.version >= version.Bellatrix && b.block.body.executionPayload == nil
preEPBS := b.version < version.EPBS
return preEPBS && b.version >= version.Bellatrix && b.block.body.executionPayload == nil
}
// Header converts the underlying protobuf object from blinded block to header format.
@@ -377,6 +389,8 @@ func (b *SignedBeaconBlock) MarshalSSZ() ([]byte, error) {
return pb.(*eth.SignedBlindedBeaconBlockElectra).MarshalSSZ()
}
return pb.(*eth.SignedBeaconBlockElectra).MarshalSSZ()
case version.EPBS:
return pb.(*eth.SignedBeaconBlockEpbs).MarshalSSZ()
default:
return []byte{}, errIncorrectBlockVersion
}
@@ -414,6 +428,8 @@ func (b *SignedBeaconBlock) MarshalSSZTo(dst []byte) ([]byte, error) {
return pb.(*eth.SignedBlindedBeaconBlockElectra).MarshalSSZTo(dst)
}
return pb.(*eth.SignedBeaconBlockElectra).MarshalSSZTo(dst)
case version.EPBS:
return pb.(*eth.SignedBeaconBlockEpbs).MarshalSSZTo(dst)
default:
return []byte{}, errIncorrectBlockVersion
}
@@ -455,6 +471,8 @@ func (b *SignedBeaconBlock) SizeSSZ() int {
return pb.(*eth.SignedBlindedBeaconBlockElectra).SizeSSZ()
}
return pb.(*eth.SignedBeaconBlockElectra).SizeSSZ()
case version.EPBS:
return pb.(*eth.SignedBeaconBlockEpbs).SizeSSZ()
default:
panic(incorrectBlockVersion)
}
@@ -572,6 +590,16 @@ func (b *SignedBeaconBlock) UnmarshalSSZ(buf []byte) error {
return err
}
}
case version.EPBS:
pb := &eth.SignedBeaconBlockEpbs{}
if err := pb.UnmarshalSSZ(buf); err != nil {
return err
}
var err error
newBlock, err = initSignedBlockFromProtoEPBS(pb)
if err != nil {
return err
}
default:
return errIncorrectBlockVersion
}
@@ -611,7 +639,8 @@ func (b *BeaconBlock) IsNil() bool {
// IsBlinded checks if the beacon block is a blinded block.
func (b *BeaconBlock) IsBlinded() bool {
return b.version >= version.Bellatrix && b.body.executionPayload == nil
preEPBS := b.version < version.EPBS
return preEPBS && b.version >= version.Bellatrix && b.body.executionPayload == nil
}
// Version of the underlying protobuf object.
@@ -650,6 +679,8 @@ func (b *BeaconBlock) HashTreeRoot() ([field_params.RootLength]byte, error) {
return pb.(*eth.BlindedBeaconBlockElectra).HashTreeRoot()
}
return pb.(*eth.BeaconBlockElectra).HashTreeRoot()
case version.EPBS:
return pb.(*eth.BeaconBlockEpbs).HashTreeRoot()
default:
return [field_params.RootLength]byte{}, errIncorrectBlockVersion
}
@@ -686,6 +717,8 @@ func (b *BeaconBlock) HashTreeRootWith(h *ssz.Hasher) error {
return pb.(*eth.BlindedBeaconBlockElectra).HashTreeRootWith(h)
}
return pb.(*eth.BeaconBlockElectra).HashTreeRootWith(h)
case version.EPBS:
return pb.(*eth.BeaconBlockEpbs).HashTreeRootWith(h)
default:
return errIncorrectBlockVersion
}
@@ -723,6 +756,8 @@ func (b *BeaconBlock) MarshalSSZ() ([]byte, error) {
return pb.(*eth.BlindedBeaconBlockElectra).MarshalSSZ()
}
return pb.(*eth.BeaconBlockElectra).MarshalSSZ()
case version.EPBS:
return pb.(*eth.BeaconBlockEpbs).MarshalSSZ()
default:
return []byte{}, errIncorrectBlockVersion
}
@@ -760,6 +795,8 @@ func (b *BeaconBlock) MarshalSSZTo(dst []byte) ([]byte, error) {
return pb.(*eth.BlindedBeaconBlockElectra).MarshalSSZTo(dst)
}
return pb.(*eth.BeaconBlockElectra).MarshalSSZTo(dst)
case version.EPBS:
return pb.(*eth.BeaconBlockEpbs).MarshalSSZTo(dst)
default:
return []byte{}, errIncorrectBlockVersion
}
@@ -801,6 +838,8 @@ func (b *BeaconBlock) SizeSSZ() int {
return pb.(*eth.BlindedBeaconBlockElectra).SizeSSZ()
}
return pb.(*eth.BeaconBlockElectra).SizeSSZ()
case version.EPBS:
return pb.(*eth.BeaconBlockEpbs).SizeSSZ()
default:
panic(incorrectBodyVersion)
}
@@ -918,6 +957,16 @@ func (b *BeaconBlock) UnmarshalSSZ(buf []byte) error {
return err
}
}
case version.EPBS:
pb := &eth.BeaconBlockEpbs{}
if err := pb.UnmarshalSSZ(buf); err != nil {
return err
}
var err error
newBlock, err = initBlockFromProtoEpbs(pb)
if err != nil {
return err
}
default:
return errIncorrectBlockVersion
}
@@ -956,6 +1005,8 @@ func (b *BeaconBlock) AsSignRequestObject() (validatorpb.SignRequestObject, erro
return &validatorpb.SignRequest_BlindedBlockElectra{BlindedBlockElectra: pb.(*eth.BlindedBeaconBlockElectra)}, nil
}
return &validatorpb.SignRequest_BlockElectra{BlockElectra: pb.(*eth.BeaconBlockElectra)}, nil
case version.EPBS:
return &validatorpb.SignRequest_BlockEpbs{BlockEpbs: pb.(*eth.BeaconBlockEpbs)}, nil
default:
return nil, errIncorrectBlockVersion
}
@@ -1005,6 +1056,9 @@ func (b *BeaconBlock) Copy() (interfaces.ReadOnlyBeaconBlock, error) {
}
cp := eth.CopyBeaconBlockElectra(pb.(*eth.BeaconBlockElectra))
return initBlockFromProtoElectra(cp)
case version.EPBS:
cp := eth.CopyBeaconBlockEPBS(pb.(*eth.BeaconBlockEpbs))
return initBlockFromProtoEpbs(cp)
default:
return nil, errIncorrectBlockVersion
}
@@ -1102,7 +1156,7 @@ func (b *BeaconBlockBody) SyncAggregate() (*eth.SyncAggregate, error) {
// Execution returns the execution payload of the block body.
func (b *BeaconBlockBody) Execution() (interfaces.ExecutionData, error) {
switch b.version {
case version.Phase0, version.Altair:
case version.Phase0, version.Altair, version.EPBS:
return nil, consensus_types.ErrNotSupported("Execution", b.version)
default:
if b.IsBlinded() {
@@ -1131,6 +1185,16 @@ func (b *BeaconBlockBody) BlobKzgCommitments() ([][]byte, error) {
}
}
// PayloadAttestations returns the payload attestations in the block.
func (b *BeaconBlockBody) PayloadAttestations() []*eth.PayloadAttestation {
return b.payloadAttestations
}
// SignedExecutionPayloadHeader returns the signed execution payload header in the block.
func (b *BeaconBlockBody) SignedExecutionPayloadHeader() *enginev1.SignedExecutionPayloadHeader {
return b.signedExecutionPayloadHeader
}
// Version returns the version of the beacon block body
func (b *BeaconBlockBody) Version() int {
return b.version
@@ -1167,6 +1231,8 @@ func (b *BeaconBlockBody) HashTreeRoot() ([field_params.RootLength]byte, error)
return pb.(*eth.BlindedBeaconBlockBodyElectra).HashTreeRoot()
}
return pb.(*eth.BeaconBlockBodyElectra).HashTreeRoot()
case version.EPBS:
return pb.(*eth.BeaconBlockBodyEpbs).HashTreeRoot()
default:
return [field_params.RootLength]byte{}, errIncorrectBodyVersion
}
@@ -1174,5 +1240,6 @@ func (b *BeaconBlockBody) HashTreeRoot() ([field_params.RootLength]byte, error)
// IsBlinded checks if the beacon block body is a blinded block body.
func (b *BeaconBlockBody) IsBlinded() bool {
return b.version >= version.Bellatrix && b.executionPayload == nil
preEPBS := b.version < version.EPBS
return preEPBS && b.version >= version.Bellatrix && b.executionPayload == nil
}

View File

@@ -0,0 +1,95 @@
package blocks
import (
"testing"
"github.com/prysmaticlabs/go-bitfield"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
pb "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/prysmaticlabs/prysm/v5/testing/require"
)
func Test_EpbsBlock_Copy(t *testing.T) {
signedHeader := &pb.SignedExecutionPayloadHeader{
Message: &pb.ExecutionPayloadHeaderEPBS{
ParentBlockHash: bytesutil.PadTo([]byte("parentblockhash"), fieldparams.RootLength),
ParentBlockRoot: bytesutil.PadTo([]byte("parentblockroot"), fieldparams.RootLength),
BlockHash: bytesutil.PadTo([]byte("blockhash"), fieldparams.RootLength),
BuilderIndex: 1,
Slot: 2,
Value: 3,
BlobKzgCommitmentsRoot: bytesutil.PadTo([]byte("blobkzgcommitmentsroot"), fieldparams.RootLength),
GasLimit: 4,
},
Signature: bytesutil.PadTo([]byte("signature"), fieldparams.BLSSignatureLength),
}
aggregationBits := bitfield.NewBitvector512()
aggregationBits.SetBitAt(1, true)
aggregationBits.SetBitAt(2, true)
payloadAttestations := []*eth.PayloadAttestation{
{
AggregationBits: aggregationBits,
Data: &eth.PayloadAttestationData{
BeaconBlockRoot: []byte("beaconblockroot"),
Slot: 1,
PayloadStatus: 2,
},
Signature: []byte("signature"),
},
{
AggregationBits: aggregationBits,
Data: &eth.PayloadAttestationData{
BeaconBlockRoot: []byte("beaconblockroot"),
Slot: 1,
PayloadStatus: 1,
},
Signature: []byte("signature"),
},
}
epbsBlockProto := &eth.BeaconBlockEpbs{
Body: &eth.BeaconBlockBodyEpbs{
SignedExecutionPayloadHeader: signedHeader,
PayloadAttestations: payloadAttestations,
},
}
epbsBlock, err := NewBeaconBlock(epbsBlockProto)
require.NoError(t, err)
copiedEpbsBlock, err := epbsBlock.Copy()
require.NoError(t, err)
copiedBody, ok := copiedEpbsBlock.Body().(interfaces.ROBlockBodyEpbs)
require.Equal(t, true, ok)
require.DeepEqual(t, copiedBody.SignedExecutionPayloadHeader(), signedHeader)
copiedPayloadAtts := copiedBody.PayloadAttestations()
require.DeepEqual(t, copiedPayloadAtts, payloadAttestations)
}
func Test_EpbsBlock_ToBlinded(t *testing.T) {
b := &SignedBeaconBlock{version: version.EPBS}
_, err := b.ToBlinded()
require.ErrorIs(t, err, ErrUnsupportedVersion)
}
func Test_EpbsBlock_Unblind(t *testing.T) {
b := &SignedBeaconBlock{version: version.EPBS}
e, err := WrappedExecutionPayload(&pb.ExecutionPayload{})
require.NoError(t, err)
err = b.Unblind(e)
require.ErrorIs(t, err, ErrAlreadyUnblinded)
}
func Test_EpbsBlock_IsBlinded(t *testing.T) {
b := &SignedBeaconBlock{version: version.EPBS}
require.Equal(t, false, b.IsBlinded())
bb := &BeaconBlock{version: version.EPBS}
require.Equal(t, false, bb.IsBlinded())
bd := &BeaconBlockBody{version: version.EPBS}
require.Equal(t, false, bd.IsBlinded())
}

View File

@@ -464,6 +464,9 @@ func Test_BeaconBlockBody_Execution(t *testing.T) {
gas, err = eDenebHeader.ExcessBlobGas()
require.NoError(t, err)
require.DeepEqual(t, gas, uint64(223))
bb = &SignedBeaconBlock{version: version.EPBS, block: &BeaconBlock{version: version.EPBS, body: &BeaconBlockBody{version: version.EPBS}}}
require.ErrorContains(t, "Execution is not supported for epbs: unsupported getter", bb.SetExecution(nil))
}
func Test_BeaconBlockBody_HashTreeRoot(t *testing.T) {

View File

@@ -156,7 +156,12 @@ func topLevelRoots(body interfaces.ReadOnlyBeaconBlockBody) ([][]byte, error) {
// Attester slashings
as := body.AttesterSlashings()
root, err = ssz.MerkleizeListSSZ(as, params.BeaconConfig().MaxAttesterSlashings)
bodyVersion := body.Version()
if bodyVersion < version.Electra {
root, err = ssz.MerkleizeListSSZ(as, params.BeaconConfig().MaxAttesterSlashings)
} else {
root, err = ssz.MerkleizeListSSZ(as, params.BeaconConfig().MaxAttesterSlashingsElectra)
}
if err != nil {
return nil, err
}
@@ -164,7 +169,11 @@ func topLevelRoots(body interfaces.ReadOnlyBeaconBlockBody) ([][]byte, error) {
// Attestations
att := body.Attestations()
root, err = ssz.MerkleizeListSSZ(att, params.BeaconConfig().MaxAttestations)
if bodyVersion < version.Electra {
root, err = ssz.MerkleizeListSSZ(att, params.BeaconConfig().MaxAttestations)
} else {
root, err = ssz.MerkleizeListSSZ(att, params.BeaconConfig().MaxAttestationsElectra)
}
if err != nil {
return nil, err
}

View File

@@ -156,6 +156,16 @@ func (b *SignedBeaconBlock) Proto() (proto.Message, error) { // nolint:gocognit
Block: block,
Signature: b.signature[:],
}, nil
case version.EPBS:
block, ok := blockMessage.(*eth.BeaconBlockEpbs)
if !ok {
return nil, errIncorrectBlockVersion
}
return &eth.SignedBeaconBlockEpbs{
Block: block,
Signature: b.signature[:],
}, nil
default:
return nil, errors.New("unsupported signed beacon block version")
}
@@ -337,6 +347,18 @@ func (b *BeaconBlock) Proto() (proto.Message, error) { // nolint:gocognit
StateRoot: b.stateRoot[:],
Body: body,
}, nil
case version.EPBS:
body, ok := bodyMessage.(*eth.BeaconBlockBodyEpbs)
if !ok {
return nil, errIncorrectBodyVersion
}
return &eth.BeaconBlockEpbs{
Slot: b.slot,
ProposerIndex: b.proposerIndex,
ParentRoot: b.parentRoot[:],
StateRoot: b.stateRoot[:],
Body: body,
}, nil
default:
return nil, errors.New("unsupported beacon block version")
@@ -556,6 +578,21 @@ func (b *BeaconBlockBody) Proto() (proto.Message, error) {
BlobKzgCommitments: b.blobKzgCommitments,
}, nil
case version.EPBS:
return &eth.BeaconBlockBodyEpbs{
RandaoReveal: b.randaoReveal[:],
Eth1Data: b.eth1Data,
Graffiti: b.graffiti[:],
ProposerSlashings: b.proposerSlashings,
AttesterSlashings: b.attesterSlashings,
Attestations: b.attestations,
Deposits: b.deposits,
VoluntaryExits: b.voluntaryExits,
SyncAggregate: b.syncAggregate,
BlsToExecutionChanges: b.blsToExecutionChanges,
SignedExecutionPayloadHeader: b.signedExecutionPayloadHeader,
PayloadAttestations: b.payloadAttestations,
}, nil
default:
return nil, errors.New("unsupported beacon block body version")
}
@@ -663,6 +700,22 @@ func initSignedBlockFromProtoElectra(pb *eth.SignedBeaconBlockElectra) (*SignedB
return b, nil
}
func initSignedBlockFromProtoEPBS(pb *eth.SignedBeaconBlockEpbs) (*SignedBeaconBlock, error) {
if pb == nil {
return nil, errNilBlock
}
block, err := initBlockFromProtoEpbs(pb.Block)
if err != nil {
return nil, err
}
b := &SignedBeaconBlock{
version: version.EPBS,
block: block,
signature: bytesutil.ToBytes96(pb.Signature),
}
return b, nil
}
func initBlindedSignedBlockFromProtoBellatrix(pb *eth.SignedBlindedBeaconBlockBellatrix) (*SignedBeaconBlock, error) {
if pb == nil {
return nil, errNilBlock
@@ -855,7 +908,6 @@ func initBlockFromProtoElectra(pb *eth.BeaconBlockElectra) (*BeaconBlock, error)
if pb == nil {
return nil, errNilBlock
}
body, err := initBlockBodyFromProtoElectra(pb.Body)
if err != nil {
return nil, err
@@ -871,6 +923,25 @@ func initBlockFromProtoElectra(pb *eth.BeaconBlockElectra) (*BeaconBlock, error)
return b, nil
}
func initBlockFromProtoEpbs(pb *eth.BeaconBlockEpbs) (*BeaconBlock, error) {
if pb == nil {
return nil, errNilBlock
}
body, err := initBlockBodyFromProtoEpbs(pb.Body)
if err != nil {
return nil, err
}
b := &BeaconBlock{
version: version.EPBS,
slot: pb.Slot,
proposerIndex: pb.ProposerIndex,
parentRoot: bytesutil.ToBytes32(pb.ParentRoot),
stateRoot: bytesutil.ToBytes32(pb.StateRoot),
body: body,
}
return b, nil
}
func initBlindedBlockFromProtoCapella(pb *eth.BlindedBeaconBlockCapella) (*BeaconBlock, error) {
if pb == nil {
return nil, errNilBlock
@@ -1104,6 +1175,29 @@ func initBlockBodyFromProtoDeneb(pb *eth.BeaconBlockBodyDeneb) (*BeaconBlockBody
return b, nil
}
func initBlockBodyFromProtoEpbs(pb *eth.BeaconBlockBodyEpbs) (*BeaconBlockBody, error) {
if pb == nil {
return nil, errNilBlockBody
}
b := &BeaconBlockBody{
version: version.EPBS,
randaoReveal: bytesutil.ToBytes96(pb.RandaoReveal),
eth1Data: pb.Eth1Data,
graffiti: bytesutil.ToBytes32(pb.Graffiti),
proposerSlashings: pb.ProposerSlashings,
attesterSlashings: pb.AttesterSlashings,
attestations: pb.Attestations,
deposits: pb.Deposits,
voluntaryExits: pb.VoluntaryExits,
syncAggregate: pb.SyncAggregate,
blsToExecutionChanges: pb.BlsToExecutionChanges,
signedExecutionPayloadHeader: pb.SignedExecutionPayloadHeader,
payloadAttestations: pb.PayloadAttestations,
}
return b, nil
}
func initBlindedBlockBodyFromProtoDeneb(pb *eth.BlindedBeaconBlockBodyDeneb) (*BeaconBlockBody, error) {
if pb == nil {
return nil, errNilBlockBody

View File

@@ -0,0 +1,107 @@
package blocks
import (
"testing"
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/prysmaticlabs/prysm/v5/testing/assert"
"github.com/prysmaticlabs/prysm/v5/testing/require"
)
func Test_initSignedBlockFromProtoEpbs(t *testing.T) {
f := getFields()
expectedBlock := &eth.SignedBeaconBlockEpbs{
Block: &eth.BeaconBlockEpbs{
Slot: 128,
ProposerIndex: 128,
ParentRoot: f.root[:],
StateRoot: f.root[:],
Body: bodyPbEpbs(),
},
Signature: f.sig[:],
}
resultBlock, err := initSignedBlockFromProtoEPBS(expectedBlock)
require.NoError(t, err)
resultHTR, err := resultBlock.block.HashTreeRoot()
require.NoError(t, err)
expectedHTR, err := expectedBlock.Block.HashTreeRoot()
require.NoError(t, err)
assert.DeepEqual(t, expectedHTR, resultHTR)
assert.DeepEqual(t, expectedBlock.Signature, resultBlock.signature[:])
}
func Test_initBlockFromProtoEpbs(t *testing.T) {
f := getFields()
expectedBlock := &eth.BeaconBlockEpbs{
Slot: 128,
ProposerIndex: 128,
ParentRoot: f.root[:],
StateRoot: f.root[:],
Body: bodyPbEpbs(),
}
resultBlock, err := initBlockFromProtoEpbs(expectedBlock)
require.NoError(t, err)
resultHTR, err := resultBlock.HashTreeRoot()
require.NoError(t, err)
expectedHTR, err := expectedBlock.HashTreeRoot()
require.NoError(t, err)
assert.DeepEqual(t, expectedHTR, resultHTR)
}
func Test_initBlockBodyFromProtoEpbs(t *testing.T) {
expectedBody := bodyPbEpbs()
resultBody, err := initBlockBodyFromProtoEpbs(expectedBody)
require.NoError(t, err)
resultHTR, err := resultBody.HashTreeRoot()
require.NoError(t, err)
expectedHTR, err := expectedBody.HashTreeRoot()
require.NoError(t, err)
assert.DeepEqual(t, expectedHTR, resultHTR)
}
func bodyEpbs() *BeaconBlockBody {
f := getFields()
return &BeaconBlockBody{
version: version.EPBS,
randaoReveal: f.sig,
eth1Data: &eth.Eth1Data{
DepositRoot: f.root[:],
DepositCount: 128,
BlockHash: f.root[:],
},
graffiti: f.root,
proposerSlashings: f.proposerSlashings,
attesterSlashings: f.attesterSlashings,
attestations: f.atts,
deposits: f.deposits,
voluntaryExits: f.voluntaryExits,
syncAggregate: f.syncAggregate,
signedExecutionPayloadHeader: f.signedPayloadHeader,
blsToExecutionChanges: f.blsToExecutionChanges,
blobKzgCommitments: f.kzgCommitments,
payloadAttestations: f.payloadAttestation,
}
}
func bodyPbEpbs() *eth.BeaconBlockBodyEpbs {
f := getFields()
return &eth.BeaconBlockBodyEpbs{
RandaoReveal: f.sig[:],
Eth1Data: &eth.Eth1Data{
DepositRoot: f.root[:],
DepositCount: 128,
BlockHash: f.root[:],
},
Graffiti: f.root[:],
ProposerSlashings: f.proposerSlashings,
AttesterSlashings: f.attesterSlashings,
Attestations: f.atts,
Deposits: f.deposits,
VoluntaryExits: f.voluntaryExits,
SyncAggregate: f.syncAggregate,
BlsToExecutionChanges: f.blsToExecutionChanges,
SignedExecutionPayloadHeader: f.signedPayloadHeader,
PayloadAttestations: f.payloadAttestation,
}
}

View File

@@ -4,6 +4,8 @@ import (
"testing"
"github.com/prysmaticlabs/go-bitfield"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
@@ -27,8 +29,10 @@ type fields struct {
execPayloadHeaderCapella *enginev1.ExecutionPayloadHeaderCapella
execPayloadDeneb *enginev1.ExecutionPayloadDeneb
execPayloadHeaderDeneb *enginev1.ExecutionPayloadHeaderDeneb
signedPayloadHeader *enginev1.SignedExecutionPayloadHeader
blsToExecutionChanges []*eth.SignedBLSToExecutionChange
kzgCommitments [][]byte
payloadAttestation []*eth.PayloadAttestation
}
func Test_SignedBeaconBlock_Proto(t *testing.T) {
@@ -306,6 +310,42 @@ func Test_SignedBeaconBlock_Proto(t *testing.T) {
require.NoError(t, err)
assert.DeepEqual(t, expectedHTR, resultHTR)
})
t.Run("ePBS", func(t *testing.T) {
slot := primitives.Slot(12345)
proposerIndex := primitives.ValidatorIndex(23434)
expectedBlock := &eth.SignedBeaconBlockEpbs{
Block: &eth.BeaconBlockEpbs{
Slot: slot,
ProposerIndex: proposerIndex,
ParentRoot: f.root[:],
StateRoot: f.root[:],
Body: bodyPbEpbs(),
},
Signature: f.sig[:],
}
block := &SignedBeaconBlock{
version: version.EPBS,
block: &BeaconBlock{
version: version.EPBS,
slot: slot,
proposerIndex: proposerIndex,
parentRoot: f.root,
stateRoot: f.root,
body: bodyEpbs(),
},
signature: f.sig,
}
result, err := block.Proto()
require.NoError(t, err)
resultBlock, ok := result.(*eth.SignedBeaconBlockEpbs)
require.Equal(t, true, ok)
resultHTR, err := resultBlock.HashTreeRoot()
require.NoError(t, err)
expectedHTR, err := expectedBlock.HashTreeRoot()
require.NoError(t, err)
assert.DeepEqual(t, expectedHTR, resultHTR)
})
}
func Test_BeaconBlock_Proto(t *testing.T) {
@@ -527,6 +567,34 @@ func Test_BeaconBlock_Proto(t *testing.T) {
require.NoError(t, err)
assert.DeepEqual(t, expectedHTR, resultHTR)
})
t.Run("ePBS", func(t *testing.T) {
expectedBlock := &eth.BeaconBlockEpbs{
Slot: 128,
ProposerIndex: 128,
ParentRoot: f.root[:],
StateRoot: f.root[:],
Body: bodyPbEpbs(),
}
block := &BeaconBlock{
version: version.EPBS,
slot: 128,
proposerIndex: 128,
parentRoot: f.root,
stateRoot: f.root,
body: bodyEpbs(),
}
result, err := block.Proto()
require.NoError(t, err)
resultBlock, ok := result.(*eth.BeaconBlockEpbs)
require.Equal(t, true, ok)
resultHTR, err := resultBlock.HashTreeRoot()
require.NoError(t, err)
expectedHTR, err := expectedBlock.HashTreeRoot()
require.NoError(t, err)
assert.DeepEqual(t, expectedHTR, resultHTR)
})
}
func Test_BeaconBlockBody_Proto(t *testing.T) {
@@ -671,6 +739,19 @@ func Test_BeaconBlockBody_Proto(t *testing.T) {
_, err := body.Proto()
require.ErrorIs(t, err, errPayloadHeaderWrongType)
})
t.Run("epbs", func(t *testing.T) {
expectedBody := bodyPbEpbs()
body := bodyEpbs()
result, err := body.Proto()
require.NoError(t, err)
resultBlock, ok := result.(*eth.BeaconBlockBodyEpbs)
require.Equal(t, true, ok)
resultHTR, err := resultBlock.HashTreeRoot()
require.NoError(t, err)
expectedHTR, err := expectedBody.HashTreeRoot()
require.NoError(t, err)
assert.DeepEqual(t, expectedHTR, resultHTR)
})
}
func Test_initSignedBlockFromProtoPhase0(t *testing.T) {
@@ -1681,6 +1762,19 @@ func getFields() fields {
BlobGasUsed: 128,
ExcessBlobGas: 128,
}
signedExecutionPayloadHeader := &enginev1.SignedExecutionPayloadHeader{
Message: &enginev1.ExecutionPayloadHeaderEPBS{
ParentBlockHash: bytesutil.PadTo([]byte("parentblockhash"), fieldparams.RootLength),
ParentBlockRoot: bytesutil.PadTo([]byte("parentblockroot"), fieldparams.RootLength),
BlockHash: bytesutil.PadTo([]byte("blockhash"), fieldparams.RootLength),
BuilderIndex: 1,
Slot: 2,
Value: 3,
BlobKzgCommitmentsRoot: bytesutil.PadTo([]byte("blobkzgcommitmentsroot"), fieldparams.RootLength),
GasLimit: 4,
},
Signature: bytesutil.PadTo([]byte("signature"), fieldparams.BLSSignatureLength),
}
kzgCommitments := [][]byte{
bytesutil.PadTo([]byte{123}, 48),
@@ -1689,6 +1783,18 @@ func getFields() fields {
bytesutil.PadTo([]byte{143}, 48),
}
payloadAttestation := []*eth.PayloadAttestation{
{
AggregationBits: bitfield.NewBitvector512(),
Data: &eth.PayloadAttestationData{
BeaconBlockRoot: bytesutil.PadTo([]byte{123}, 32),
Slot: 1,
PayloadStatus: 2,
},
Signature: bytesutil.PadTo([]byte("signature"), fieldparams.BLSSignatureLength),
},
}
return fields{
root: root,
sig: sig,
@@ -1704,7 +1810,9 @@ func getFields() fields {
execPayloadHeaderCapella: execPayloadHeaderCapella,
execPayloadDeneb: execPayloadDeneb,
execPayloadHeaderDeneb: execPayloadHeaderDeneb,
signedPayloadHeader: signedExecutionPayloadHeader,
blsToExecutionChanges: blsToExecutionChanges,
kzgCommitments: kzgCommitments,
payloadAttestation: payloadAttestation,
}
}

View File

@@ -6,6 +6,7 @@ import (
consensus_types "github.com/prysmaticlabs/prysm/v5/consensus-types"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
)
@@ -143,7 +144,7 @@ func (b *SignedBeaconBlock) SetSyncAggregate(s *eth.SyncAggregate) error {
// SetExecution sets the execution payload of the block body.
// This function is not thread safe, it is only used during block creation.
func (b *SignedBeaconBlock) SetExecution(e interfaces.ExecutionData) error {
if b.version == version.Phase0 || b.version == version.Altair {
if b.version >= version.EPBS || b.version < version.Bellatrix {
return consensus_types.ErrNotSupported("Execution", b.version)
}
if e.IsBlinded() {
@@ -172,3 +173,21 @@ func (b *SignedBeaconBlock) SetBlobKzgCommitments(c [][]byte) error {
b.block.body.blobKzgCommitments = c
return nil
}
// SetPayloadAttestations sets the payload attestations in the block.
func (b *SignedBeaconBlock) SetPayloadAttestations(p []*eth.PayloadAttestation) error {
if b.version < version.EPBS {
return consensus_types.ErrNotSupported("PayloadAttestations", b.version)
}
b.block.body.payloadAttestations = p
return nil
}
// SetSignedExecutionPayloadHeader sets the signed execution payload header of the block body.
func (b *SignedBeaconBlock) SetSignedExecutionPayloadHeader(h *enginev1.SignedExecutionPayloadHeader) error {
if b.version < version.EPBS {
return consensus_types.ErrNotSupported("SetSignedExecutionPayloadHeader", b.version)
}
b.block.body.signedExecutionPayloadHeader = h
return nil
}

View File

@@ -0,0 +1,71 @@
package blocks
import (
"testing"
"github.com/prysmaticlabs/go-bitfield"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
consensus_types "github.com/prysmaticlabs/prysm/v5/consensus-types"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/prysmaticlabs/prysm/v5/testing/require"
)
func Test_EpbsBlock_SetPayloadAttestations(t *testing.T) {
b := &SignedBeaconBlock{version: version.Deneb}
require.ErrorIs(t, b.SetPayloadAttestations(nil), consensus_types.ErrUnsupportedField)
b = &SignedBeaconBlock{version: version.EPBS,
block: &BeaconBlock{version: version.EPBS,
body: &BeaconBlockBody{version: version.EPBS}}}
aggregationBits := bitfield.NewBitvector512()
aggregationBits.SetBitAt(0, true)
payloadAttestation := []*eth.PayloadAttestation{
{
AggregationBits: aggregationBits,
Data: &eth.PayloadAttestationData{
BeaconBlockRoot: bytesutil.PadTo([]byte{123}, 32),
Slot: 1,
PayloadStatus: 2,
},
Signature: bytesutil.PadTo([]byte("signature"), fieldparams.BLSSignatureLength),
},
{
AggregationBits: aggregationBits,
Data: &eth.PayloadAttestationData{
BeaconBlockRoot: bytesutil.PadTo([]byte{123}, 32),
Slot: 1,
PayloadStatus: 3,
},
},
}
require.NoError(t, b.SetPayloadAttestations(payloadAttestation))
require.DeepEqual(t, b.block.body.PayloadAttestations(), payloadAttestation)
}
func Test_EpbsBlock_SetSignedExecutionPayloadHeader(t *testing.T) {
b := &SignedBeaconBlock{version: version.Deneb}
require.ErrorIs(t, b.SetSignedExecutionPayloadHeader(nil), consensus_types.ErrUnsupportedField)
b = &SignedBeaconBlock{version: version.EPBS,
block: &BeaconBlock{version: version.EPBS,
body: &BeaconBlockBody{version: version.EPBS}}}
signedExecutionPayloadHeader := &enginev1.SignedExecutionPayloadHeader{
Message: &enginev1.ExecutionPayloadHeaderEPBS{
ParentBlockHash: []byte("parentBlockHash"),
ParentBlockRoot: []byte("parentBlockRoot"),
BlockHash: []byte("blockHash"),
BuilderIndex: 1,
Slot: 2,
Value: 3,
BlobKzgCommitmentsRoot: []byte("blobKzgCommitmentsRoot"),
GasLimit: 4,
},
Signature: []byte("signature"),
}
require.NoError(t, b.SetSignedExecutionPayloadHeader(signedExecutionPayloadHeader))
require.DeepEqual(t, b.block.body.SignedExecutionPayloadHeader(), signedExecutionPayloadHeader)
}

View File

@@ -5,6 +5,7 @@ import (
field_params "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
)
@@ -38,22 +39,24 @@ var (
// BeaconBlockBody is the main beacon block body structure. It can represent any block type.
type BeaconBlockBody struct {
version int
randaoReveal [field_params.BLSSignatureLength]byte
eth1Data *eth.Eth1Data
graffiti [field_params.RootLength]byte
proposerSlashings []*eth.ProposerSlashing
attesterSlashings []*eth.AttesterSlashing
attesterSlashingsElectra []*eth.AttesterSlashingElectra
attestations []*eth.Attestation
attestationsElectra []*eth.AttestationElectra
deposits []*eth.Deposit
voluntaryExits []*eth.SignedVoluntaryExit
syncAggregate *eth.SyncAggregate
executionPayload interfaces.ExecutionData
executionPayloadHeader interfaces.ExecutionData
blsToExecutionChanges []*eth.SignedBLSToExecutionChange
blobKzgCommitments [][]byte
version int
randaoReveal [field_params.BLSSignatureLength]byte
eth1Data *eth.Eth1Data
graffiti [field_params.RootLength]byte
proposerSlashings []*eth.ProposerSlashing
attesterSlashings []*eth.AttesterSlashing
attesterSlashingsElectra []*eth.AttesterSlashingElectra
attestations []*eth.Attestation
attestationsElectra []*eth.AttestationElectra
deposits []*eth.Deposit
voluntaryExits []*eth.SignedVoluntaryExit
syncAggregate *eth.SyncAggregate
executionPayload interfaces.ExecutionData
executionPayloadHeader interfaces.ExecutionData
blsToExecutionChanges []*eth.SignedBLSToExecutionChange
blobKzgCommitments [][]byte
signedExecutionPayloadHeader *enginev1.SignedExecutionPayloadHeader
payloadAttestations []*eth.PayloadAttestation
}
var _ interfaces.ReadOnlyBeaconBlockBody = &BeaconBlockBody{}

View File

@@ -71,6 +71,12 @@ type ReadOnlyBeaconBlockBody interface {
BlobKzgCommitments() ([][]byte, error)
}
type ROBlockBodyEpbs interface {
ReadOnlyBeaconBlockBody
PayloadAttestations() []*ethpb.PayloadAttestation
SignedExecutionPayloadHeader() *enginev1.SignedExecutionPayloadHeader
}
type SignedBeaconBlock interface {
ReadOnlySignedBeaconBlock
SetExecution(ExecutionData) error
@@ -91,6 +97,8 @@ type SignedBeaconBlock interface {
SetSlot(slot primitives.Slot)
SetSignature(sig []byte)
Unblind(e ExecutionData) error
SetSignedExecutionPayloadHeader(h *enginev1.SignedExecutionPayloadHeader) error
SetPayloadAttestations([]*ethpb.PayloadAttestation) error
}
// ExecutionData represents execution layer information that is contained

View File

@@ -9,6 +9,7 @@ go_library(
"//config/fieldparams:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//consensus-types/primitives:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/eth/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/validator-client:go_default_library",

View File

@@ -5,6 +5,7 @@ import (
field_params "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/eth/v1"
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
validatorpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1/validator-client"
@@ -280,6 +281,14 @@ func (b *BeaconBlockBody) Version() int {
panic("implement me")
}
func (b *BeaconBlockBody) PayloadAttestations() ([]*eth.PayloadAttestation, error) {
panic("implement me")
}
func (b *BeaconBlockBody) SignedExecutionPayloadHeader() (*enginev1.SignedExecutionPayloadHeader, error) {
panic("implement me")
}
var _ interfaces.ReadOnlySignedBeaconBlock = &SignedBeaconBlock{}
var _ interfaces.ReadOnlyBeaconBlock = &BeaconBlock{}
var _ interfaces.ReadOnlyBeaconBlockBody = &BeaconBlockBody{}

View File

@@ -10,6 +10,7 @@ go_library(
"epoch.go",
"execution_address.go",
"payload_id.go",
"ptc_status.go",
"randao.go",
"slot.go",
"sszbytes.go",

View File

@@ -0,0 +1,71 @@
package primitives
import (
"fmt"
"math"
fssz "github.com/prysmaticlabs/fastssz"
)
var _ fssz.HashRoot = (PTCStatus)(0)
var _ fssz.Marshaler = (*PTCStatus)(nil)
var _ fssz.Unmarshaler = (*PTCStatus)(nil)
// PTCStatus represents a single payload status. These are the
// possible votes that the Payload Timeliness Committee can cast
// in ePBS when attesting for an execution payload.
type PTCStatus uint64
// Defined constants
const (
PAYLOAD_ABSENT PTCStatus = 0
PAYLOAD_PRESENT PTCStatus = 1
PAYLOAD_WITHHELD PTCStatus = 2
PAYLOAD_INVALID_STATUS PTCStatus = 3
)
// HashTreeRoot --
func (s PTCStatus) HashTreeRoot() ([32]byte, error) {
return fssz.HashWithDefaultHasher(s)
}
// HashTreeRootWith --
func (s PTCStatus) HashTreeRootWith(hh *fssz.Hasher) error {
if s > math.MaxUint8 {
return fmt.Errorf("expected uint8 value, received %d", uint64(s))
}
hh.PutUint8(uint8(s))
return nil
}
// UnmarshalSSZ --
func (s *PTCStatus) UnmarshalSSZ(buf []byte) error {
if len(buf) != s.SizeSSZ() {
return fmt.Errorf("expected buffer of length %d received %d", s.SizeSSZ(), len(buf))
}
*s = PTCStatus(fssz.UnmarshallUint8(buf))
return nil
}
// MarshalSSZTo --
func (s *PTCStatus) MarshalSSZTo(dst []byte) ([]byte, error) {
marshalled, err := s.MarshalSSZ()
if err != nil {
return nil, err
}
return append(dst, marshalled...), nil
}
// MarshalSSZ --
func (s *PTCStatus) MarshalSSZ() ([]byte, error) {
if *s > math.MaxUint8 {
return nil, fmt.Errorf("expected uint8 value, received %d", uint64(*s))
}
marshalled := fssz.MarshalUint8([]byte{}, uint8(*s))
return marshalled, nil
}
// SizeSSZ --
func (s *PTCStatus) SizeSSZ() int {
return 1
}

View File

@@ -116,6 +116,21 @@ func PowerOf2(n uint64) uint64 {
return 1 << n
}
// LargestPowerOfTwo returns the largest power of 2 that is lower or equal than
// the parameter
func LargestPowerOfTwo(n uint64) uint64 {
if n == 0 {
return 0
}
n |= n >> 1
n |= n >> 2
n |= n >> 4
n |= n >> 8
n |= n >> 16
n |= n >> 32
return n - (n >> 1)
}
// Max returns the larger integer of the two
// given ones.This is used over the Max function
// in the standard math library because that max function

View File

@@ -549,3 +549,27 @@ func TestAddInt(t *testing.T) {
})
}
}
func TestLargestPowerOfTwo(t *testing.T) {
testCases := []struct {
name string
input uint64
expected uint64
}{
{"Zero", 0, 0},
{"One", 1, 1},
{"Just below power of two", 14, 8},
{"Power of two", 16, 16},
{"Large number", 123456789, 67108864},
{"Max uint64", 18446744073709551615, 9223372036854775808},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
result := math.LargestPowerOfTwo(tc.input)
if result != tc.expected {
t.Errorf("For input %d, expected %d but got %d", tc.input, tc.expected, result)
}
})
}
}

View File

@@ -44,6 +44,13 @@ ssz_gen_marshal(
"ExecutionPayloadDeneb",
"ExecutionPayloadHeaderElectra",
"ExecutionPayloadElectra",
"PayloadAttestationData",
"PayloadAttestation",
"PayloadAttestationMessage",
"ExecutionPayloadHeaderEPBS",
"ExecutionPayloadEnvelope",
"SignedExecutionPayloadHeader",
"SignedExecutionPayloadEnvelope",
"BlindedBlobsBundle",
"BlobsBundle",
"Withdrawal",
@@ -56,7 +63,7 @@ ssz_gen_marshal(
go_proto_library(
name = "go_proto",
compilers = [
"@com_github_prysmaticlabs_protoc_gen_go_cast//:go_cast_grpc",
"@com_github_prysmaticlabs_protoc_gen_go_cast//:go_cast_grpc",
],
importpath = "github.com/prysmaticlabs/prysm/v5/proto/engine/v1",
proto = ":proto",
@@ -66,6 +73,7 @@ go_proto_library(
"//proto/eth/ext:go_default_library",
"@com_github_golang_protobuf//proto:go_default_library",
"@googleapis//google/api:annotations_go_proto",
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
"@io_bazel_rules_go//proto/wkt:descriptor_go_proto",
"@org_golang_google_protobuf//reflect/protoreflect:go_default_library",
"@org_golang_google_protobuf//runtime/protoimpl:go_default_library",
@@ -99,6 +107,7 @@ go_library(
"@com_github_sirupsen_logrus//:go_default_library",
"@googleapis//google/api:annotations_go_proto",
"@io_bazel_rules_go//proto/wkt:descriptor_go_proto",
"@com_github_prysmaticlabs_go_bitfield//:go_default_library", # keep
"@io_bazel_rules_go//proto/wkt:timestamp_go_proto",
"@org_golang_google_protobuf//encoding/protojson:go_default_library",
"@org_golang_google_protobuf//reflect/protoreflect:go_default_library",
@@ -110,6 +119,7 @@ ssz_proto_files(
name = "ssz_proto_files",
srcs = [
"execution_engine.proto",
"epbs.proto",
],
config = select({
"//conditions:default": "mainnet",

View File

@@ -1,5 +1,5 @@
// Code generated by fastssz. DO NOT EDIT.
// Hash: d1cee811bee5b5cfcedf5be00dfff21d5e6caf432cd8fc42f551264f7b8e296c
// Hash: 267522f5fc96f69efb25124116e9f3ed9853b6ff1f9be9868875ddb26ef0c20b
package enginev1
import (
@@ -7,6 +7,563 @@ import (
github_com_prysmaticlabs_prysm_v5_consensus_types_primitives "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
)
// MarshalSSZ ssz marshals the ExecutionPayloadHeaderEPBS object
func (e *ExecutionPayloadHeaderEPBS) MarshalSSZ() ([]byte, error) {
return ssz.MarshalSSZ(e)
}
// MarshalSSZTo ssz marshals the ExecutionPayloadHeaderEPBS object to a target array
func (e *ExecutionPayloadHeaderEPBS) MarshalSSZTo(buf []byte) (dst []byte, err error) {
dst = buf
// Field (0) 'ParentBlockHash'
if size := len(e.ParentBlockHash); size != 32 {
err = ssz.ErrBytesLengthFn("--.ParentBlockHash", size, 32)
return
}
dst = append(dst, e.ParentBlockHash...)
// Field (1) 'ParentBlockRoot'
if size := len(e.ParentBlockRoot); size != 32 {
err = ssz.ErrBytesLengthFn("--.ParentBlockRoot", size, 32)
return
}
dst = append(dst, e.ParentBlockRoot...)
// Field (2) 'BlockHash'
if size := len(e.BlockHash); size != 32 {
err = ssz.ErrBytesLengthFn("--.BlockHash", size, 32)
return
}
dst = append(dst, e.BlockHash...)
// Field (3) 'GasLimit'
dst = ssz.MarshalUint64(dst, e.GasLimit)
// Field (4) 'BuilderIndex'
dst = ssz.MarshalUint64(dst, uint64(e.BuilderIndex))
// Field (5) 'Slot'
dst = ssz.MarshalUint64(dst, uint64(e.Slot))
// Field (6) 'Value'
dst = ssz.MarshalUint64(dst, e.Value)
// Field (7) 'BlobKzgCommitmentsRoot'
if size := len(e.BlobKzgCommitmentsRoot); size != 32 {
err = ssz.ErrBytesLengthFn("--.BlobKzgCommitmentsRoot", size, 32)
return
}
dst = append(dst, e.BlobKzgCommitmentsRoot...)
return
}
// UnmarshalSSZ ssz unmarshals the ExecutionPayloadHeaderEPBS object
func (e *ExecutionPayloadHeaderEPBS) UnmarshalSSZ(buf []byte) error {
var err error
size := uint64(len(buf))
if size != 160 {
return ssz.ErrSize
}
// Field (0) 'ParentBlockHash'
if cap(e.ParentBlockHash) == 0 {
e.ParentBlockHash = make([]byte, 0, len(buf[0:32]))
}
e.ParentBlockHash = append(e.ParentBlockHash, buf[0:32]...)
// Field (1) 'ParentBlockRoot'
if cap(e.ParentBlockRoot) == 0 {
e.ParentBlockRoot = make([]byte, 0, len(buf[32:64]))
}
e.ParentBlockRoot = append(e.ParentBlockRoot, buf[32:64]...)
// Field (2) 'BlockHash'
if cap(e.BlockHash) == 0 {
e.BlockHash = make([]byte, 0, len(buf[64:96]))
}
e.BlockHash = append(e.BlockHash, buf[64:96]...)
// Field (3) 'GasLimit'
e.GasLimit = ssz.UnmarshallUint64(buf[96:104])
// Field (4) 'BuilderIndex'
e.BuilderIndex = github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.ValidatorIndex(ssz.UnmarshallUint64(buf[104:112]))
// Field (5) 'Slot'
e.Slot = github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.Slot(ssz.UnmarshallUint64(buf[112:120]))
// Field (6) 'Value'
e.Value = ssz.UnmarshallUint64(buf[120:128])
// Field (7) 'BlobKzgCommitmentsRoot'
if cap(e.BlobKzgCommitmentsRoot) == 0 {
e.BlobKzgCommitmentsRoot = make([]byte, 0, len(buf[128:160]))
}
e.BlobKzgCommitmentsRoot = append(e.BlobKzgCommitmentsRoot, buf[128:160]...)
return err
}
// SizeSSZ returns the ssz encoded size in bytes for the ExecutionPayloadHeaderEPBS object
func (e *ExecutionPayloadHeaderEPBS) SizeSSZ() (size int) {
size = 160
return
}
// HashTreeRoot ssz hashes the ExecutionPayloadHeaderEPBS object
func (e *ExecutionPayloadHeaderEPBS) HashTreeRoot() ([32]byte, error) {
return ssz.HashWithDefaultHasher(e)
}
// HashTreeRootWith ssz hashes the ExecutionPayloadHeaderEPBS object with a hasher
func (e *ExecutionPayloadHeaderEPBS) HashTreeRootWith(hh *ssz.Hasher) (err error) {
indx := hh.Index()
// Field (0) 'ParentBlockHash'
if size := len(e.ParentBlockHash); size != 32 {
err = ssz.ErrBytesLengthFn("--.ParentBlockHash", size, 32)
return
}
hh.PutBytes(e.ParentBlockHash)
// Field (1) 'ParentBlockRoot'
if size := len(e.ParentBlockRoot); size != 32 {
err = ssz.ErrBytesLengthFn("--.ParentBlockRoot", size, 32)
return
}
hh.PutBytes(e.ParentBlockRoot)
// Field (2) 'BlockHash'
if size := len(e.BlockHash); size != 32 {
err = ssz.ErrBytesLengthFn("--.BlockHash", size, 32)
return
}
hh.PutBytes(e.BlockHash)
// Field (3) 'GasLimit'
hh.PutUint64(e.GasLimit)
// Field (4) 'BuilderIndex'
hh.PutUint64(uint64(e.BuilderIndex))
// Field (5) 'Slot'
hh.PutUint64(uint64(e.Slot))
// Field (6) 'Value'
hh.PutUint64(e.Value)
// Field (7) 'BlobKzgCommitmentsRoot'
if size := len(e.BlobKzgCommitmentsRoot); size != 32 {
err = ssz.ErrBytesLengthFn("--.BlobKzgCommitmentsRoot", size, 32)
return
}
hh.PutBytes(e.BlobKzgCommitmentsRoot)
hh.Merkleize(indx)
return
}
// MarshalSSZ ssz marshals the SignedExecutionPayloadHeader object
func (s *SignedExecutionPayloadHeader) MarshalSSZ() ([]byte, error) {
return ssz.MarshalSSZ(s)
}
// MarshalSSZTo ssz marshals the SignedExecutionPayloadHeader object to a target array
func (s *SignedExecutionPayloadHeader) MarshalSSZTo(buf []byte) (dst []byte, err error) {
dst = buf
// Field (0) 'Message'
if s.Message == nil {
s.Message = new(ExecutionPayloadHeaderEPBS)
}
if dst, err = s.Message.MarshalSSZTo(dst); err != nil {
return
}
// Field (1) 'Signature'
if size := len(s.Signature); size != 96 {
err = ssz.ErrBytesLengthFn("--.Signature", size, 96)
return
}
dst = append(dst, s.Signature...)
return
}
// UnmarshalSSZ ssz unmarshals the SignedExecutionPayloadHeader object
func (s *SignedExecutionPayloadHeader) UnmarshalSSZ(buf []byte) error {
var err error
size := uint64(len(buf))
if size != 256 {
return ssz.ErrSize
}
// Field (0) 'Message'
if s.Message == nil {
s.Message = new(ExecutionPayloadHeaderEPBS)
}
if err = s.Message.UnmarshalSSZ(buf[0:160]); err != nil {
return err
}
// Field (1) 'Signature'
if cap(s.Signature) == 0 {
s.Signature = make([]byte, 0, len(buf[160:256]))
}
s.Signature = append(s.Signature, buf[160:256]...)
return err
}
// SizeSSZ returns the ssz encoded size in bytes for the SignedExecutionPayloadHeader object
func (s *SignedExecutionPayloadHeader) SizeSSZ() (size int) {
size = 256
return
}
// HashTreeRoot ssz hashes the SignedExecutionPayloadHeader object
func (s *SignedExecutionPayloadHeader) HashTreeRoot() ([32]byte, error) {
return ssz.HashWithDefaultHasher(s)
}
// HashTreeRootWith ssz hashes the SignedExecutionPayloadHeader object with a hasher
func (s *SignedExecutionPayloadHeader) HashTreeRootWith(hh *ssz.Hasher) (err error) {
indx := hh.Index()
// Field (0) 'Message'
if err = s.Message.HashTreeRootWith(hh); err != nil {
return
}
// Field (1) 'Signature'
if size := len(s.Signature); size != 96 {
err = ssz.ErrBytesLengthFn("--.Signature", size, 96)
return
}
hh.PutBytes(s.Signature)
hh.Merkleize(indx)
return
}
// MarshalSSZ ssz marshals the ExecutionPayloadEnvelope object
func (e *ExecutionPayloadEnvelope) MarshalSSZ() ([]byte, error) {
return ssz.MarshalSSZ(e)
}
// MarshalSSZTo ssz marshals the ExecutionPayloadEnvelope object to a target array
func (e *ExecutionPayloadEnvelope) MarshalSSZTo(buf []byte) (dst []byte, err error) {
dst = buf
offset := int(81)
// Offset (0) 'Payload'
dst = ssz.WriteOffset(dst, offset)
if e.Payload == nil {
e.Payload = new(ExecutionPayloadElectra)
}
offset += e.Payload.SizeSSZ()
// Field (1) 'BuilderIndex'
dst = ssz.MarshalUint64(dst, uint64(e.BuilderIndex))
// Field (2) 'BeaconBlockRoot'
if size := len(e.BeaconBlockRoot); size != 32 {
err = ssz.ErrBytesLengthFn("--.BeaconBlockRoot", size, 32)
return
}
dst = append(dst, e.BeaconBlockRoot...)
// Offset (3) 'BlobKzgCommitments'
dst = ssz.WriteOffset(dst, offset)
offset += len(e.BlobKzgCommitments) * 48
// Field (4) 'PayloadWithheld'
dst = ssz.MarshalBool(dst, e.PayloadWithheld)
// Field (5) 'StateRoot'
if size := len(e.StateRoot); size != 32 {
err = ssz.ErrBytesLengthFn("--.StateRoot", size, 32)
return
}
dst = append(dst, e.StateRoot...)
// Field (0) 'Payload'
if dst, err = e.Payload.MarshalSSZTo(dst); err != nil {
return
}
// Field (3) 'BlobKzgCommitments'
if size := len(e.BlobKzgCommitments); size > 4096 {
err = ssz.ErrListTooBigFn("--.BlobKzgCommitments", size, 4096)
return
}
for ii := 0; ii < len(e.BlobKzgCommitments); ii++ {
if size := len(e.BlobKzgCommitments[ii]); size != 48 {
err = ssz.ErrBytesLengthFn("--.BlobKzgCommitments[ii]", size, 48)
return
}
dst = append(dst, e.BlobKzgCommitments[ii]...)
}
return
}
// UnmarshalSSZ ssz unmarshals the ExecutionPayloadEnvelope object
func (e *ExecutionPayloadEnvelope) UnmarshalSSZ(buf []byte) error {
var err error
size := uint64(len(buf))
if size < 81 {
return ssz.ErrSize
}
tail := buf
var o0, o3 uint64
// Offset (0) 'Payload'
if o0 = ssz.ReadOffset(buf[0:4]); o0 > size {
return ssz.ErrOffset
}
if o0 != 81 {
return ssz.ErrInvalidVariableOffset
}
// Field (1) 'BuilderIndex'
e.BuilderIndex = github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.ValidatorIndex(ssz.UnmarshallUint64(buf[4:12]))
// Field (2) 'BeaconBlockRoot'
if cap(e.BeaconBlockRoot) == 0 {
e.BeaconBlockRoot = make([]byte, 0, len(buf[12:44]))
}
e.BeaconBlockRoot = append(e.BeaconBlockRoot, buf[12:44]...)
// Offset (3) 'BlobKzgCommitments'
if o3 = ssz.ReadOffset(buf[44:48]); o3 > size || o0 > o3 {
return ssz.ErrOffset
}
// Field (4) 'PayloadWithheld'
e.PayloadWithheld = ssz.UnmarshalBool(buf[48:49])
// Field (5) 'StateRoot'
if cap(e.StateRoot) == 0 {
e.StateRoot = make([]byte, 0, len(buf[49:81]))
}
e.StateRoot = append(e.StateRoot, buf[49:81]...)
// Field (0) 'Payload'
{
buf = tail[o0:o3]
if e.Payload == nil {
e.Payload = new(ExecutionPayloadElectra)
}
if err = e.Payload.UnmarshalSSZ(buf); err != nil {
return err
}
}
// Field (3) 'BlobKzgCommitments'
{
buf = tail[o3:]
num, err := ssz.DivideInt2(len(buf), 48, 4096)
if err != nil {
return err
}
e.BlobKzgCommitments = make([][]byte, num)
for ii := 0; ii < num; ii++ {
if cap(e.BlobKzgCommitments[ii]) == 0 {
e.BlobKzgCommitments[ii] = make([]byte, 0, len(buf[ii*48:(ii+1)*48]))
}
e.BlobKzgCommitments[ii] = append(e.BlobKzgCommitments[ii], buf[ii*48:(ii+1)*48]...)
}
}
return err
}
// SizeSSZ returns the ssz encoded size in bytes for the ExecutionPayloadEnvelope object
func (e *ExecutionPayloadEnvelope) SizeSSZ() (size int) {
size = 81
// Field (0) 'Payload'
if e.Payload == nil {
e.Payload = new(ExecutionPayloadElectra)
}
size += e.Payload.SizeSSZ()
// Field (3) 'BlobKzgCommitments'
size += len(e.BlobKzgCommitments) * 48
return
}
// HashTreeRoot ssz hashes the ExecutionPayloadEnvelope object
func (e *ExecutionPayloadEnvelope) HashTreeRoot() ([32]byte, error) {
return ssz.HashWithDefaultHasher(e)
}
// HashTreeRootWith ssz hashes the ExecutionPayloadEnvelope object with a hasher
func (e *ExecutionPayloadEnvelope) HashTreeRootWith(hh *ssz.Hasher) (err error) {
indx := hh.Index()
// Field (0) 'Payload'
if err = e.Payload.HashTreeRootWith(hh); err != nil {
return
}
// Field (1) 'BuilderIndex'
hh.PutUint64(uint64(e.BuilderIndex))
// Field (2) 'BeaconBlockRoot'
if size := len(e.BeaconBlockRoot); size != 32 {
err = ssz.ErrBytesLengthFn("--.BeaconBlockRoot", size, 32)
return
}
hh.PutBytes(e.BeaconBlockRoot)
// Field (3) 'BlobKzgCommitments'
{
if size := len(e.BlobKzgCommitments); size > 4096 {
err = ssz.ErrListTooBigFn("--.BlobKzgCommitments", size, 4096)
return
}
subIndx := hh.Index()
for _, i := range e.BlobKzgCommitments {
if len(i) != 48 {
err = ssz.ErrBytesLength
return
}
hh.PutBytes(i)
}
numItems := uint64(len(e.BlobKzgCommitments))
hh.MerkleizeWithMixin(subIndx, numItems, 4096)
}
// Field (4) 'PayloadWithheld'
hh.PutBool(e.PayloadWithheld)
// Field (5) 'StateRoot'
if size := len(e.StateRoot); size != 32 {
err = ssz.ErrBytesLengthFn("--.StateRoot", size, 32)
return
}
hh.PutBytes(e.StateRoot)
hh.Merkleize(indx)
return
}
// MarshalSSZ ssz marshals the SignedExecutionPayloadEnvelope object
func (s *SignedExecutionPayloadEnvelope) MarshalSSZ() ([]byte, error) {
return ssz.MarshalSSZ(s)
}
// MarshalSSZTo ssz marshals the SignedExecutionPayloadEnvelope object to a target array
func (s *SignedExecutionPayloadEnvelope) MarshalSSZTo(buf []byte) (dst []byte, err error) {
dst = buf
offset := int(100)
// Offset (0) 'Message'
dst = ssz.WriteOffset(dst, offset)
if s.Message == nil {
s.Message = new(ExecutionPayloadEnvelope)
}
offset += s.Message.SizeSSZ()
// Field (1) 'Signature'
if size := len(s.Signature); size != 96 {
err = ssz.ErrBytesLengthFn("--.Signature", size, 96)
return
}
dst = append(dst, s.Signature...)
// Field (0) 'Message'
if dst, err = s.Message.MarshalSSZTo(dst); err != nil {
return
}
return
}
// UnmarshalSSZ ssz unmarshals the SignedExecutionPayloadEnvelope object
func (s *SignedExecutionPayloadEnvelope) UnmarshalSSZ(buf []byte) error {
var err error
size := uint64(len(buf))
if size < 100 {
return ssz.ErrSize
}
tail := buf
var o0 uint64
// Offset (0) 'Message'
if o0 = ssz.ReadOffset(buf[0:4]); o0 > size {
return ssz.ErrOffset
}
if o0 != 100 {
return ssz.ErrInvalidVariableOffset
}
// Field (1) 'Signature'
if cap(s.Signature) == 0 {
s.Signature = make([]byte, 0, len(buf[4:100]))
}
s.Signature = append(s.Signature, buf[4:100]...)
// Field (0) 'Message'
{
buf = tail[o0:]
if s.Message == nil {
s.Message = new(ExecutionPayloadEnvelope)
}
if err = s.Message.UnmarshalSSZ(buf); err != nil {
return err
}
}
return err
}
// SizeSSZ returns the ssz encoded size in bytes for the SignedExecutionPayloadEnvelope object
func (s *SignedExecutionPayloadEnvelope) SizeSSZ() (size int) {
size = 100
// Field (0) 'Message'
if s.Message == nil {
s.Message = new(ExecutionPayloadEnvelope)
}
size += s.Message.SizeSSZ()
return
}
// HashTreeRoot ssz hashes the SignedExecutionPayloadEnvelope object
func (s *SignedExecutionPayloadEnvelope) HashTreeRoot() ([32]byte, error) {
return ssz.HashWithDefaultHasher(s)
}
// HashTreeRootWith ssz hashes the SignedExecutionPayloadEnvelope object with a hasher
func (s *SignedExecutionPayloadEnvelope) HashTreeRootWith(hh *ssz.Hasher) (err error) {
indx := hh.Index()
// Field (0) 'Message'
if err = s.Message.HashTreeRootWith(hh); err != nil {
return
}
// Field (1) 'Signature'
if size := len(s.Signature); size != 96 {
err = ssz.ErrBytesLengthFn("--.Signature", size, 96)
return
}
hh.PutBytes(s.Signature)
hh.Merkleize(indx)
return
}
// MarshalSSZ ssz marshals the ExecutionPayload object
func (e *ExecutionPayload) MarshalSSZ() ([]byte, error) {
return ssz.MarshalSSZ(e)

530
proto/engine/v1/epbs.pb.go generated Executable file
View File

@@ -0,0 +1,530 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.31.0
// protoc v4.25.1
// source: proto/engine/v1/epbs.proto
package enginev1
import (
reflect "reflect"
sync "sync"
github_com_prysmaticlabs_prysm_v5_consensus_types_primitives "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
_ "github.com/prysmaticlabs/prysm/v5/proto/eth/ext"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type ExecutionPayloadHeaderEPBS struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
ParentBlockHash []byte `protobuf:"bytes,1,opt,name=parent_block_hash,json=parentBlockHash,proto3" json:"parent_block_hash,omitempty" ssz-size:"32"`
ParentBlockRoot []byte `protobuf:"bytes,2,opt,name=parent_block_root,json=parentBlockRoot,proto3" json:"parent_block_root,omitempty" ssz-size:"32"`
BlockHash []byte `protobuf:"bytes,3,opt,name=block_hash,json=blockHash,proto3" json:"block_hash,omitempty" ssz-size:"32"`
GasLimit uint64 `protobuf:"varint,4,opt,name=gas_limit,json=gasLimit,proto3" json:"gas_limit,omitempty"`
BuilderIndex github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.ValidatorIndex `protobuf:"varint,5,opt,name=builder_index,json=builderIndex,proto3" json:"builder_index,omitempty" cast-type:"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives.ValidatorIndex"`
Slot github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.Slot `protobuf:"varint,6,opt,name=slot,proto3" json:"slot,omitempty" cast-type:"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives.Slot"`
Value uint64 `protobuf:"varint,7,opt,name=value,proto3" json:"value,omitempty"`
BlobKzgCommitmentsRoot []byte `protobuf:"bytes,8,opt,name=blob_kzg_commitments_root,json=blobKzgCommitmentsRoot,proto3" json:"blob_kzg_commitments_root,omitempty" ssz-size:"32"`
}
func (x *ExecutionPayloadHeaderEPBS) Reset() {
*x = ExecutionPayloadHeaderEPBS{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_engine_v1_epbs_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ExecutionPayloadHeaderEPBS) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ExecutionPayloadHeaderEPBS) ProtoMessage() {}
func (x *ExecutionPayloadHeaderEPBS) ProtoReflect() protoreflect.Message {
mi := &file_proto_engine_v1_epbs_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ExecutionPayloadHeaderEPBS.ProtoReflect.Descriptor instead.
func (*ExecutionPayloadHeaderEPBS) Descriptor() ([]byte, []int) {
return file_proto_engine_v1_epbs_proto_rawDescGZIP(), []int{0}
}
func (x *ExecutionPayloadHeaderEPBS) GetParentBlockHash() []byte {
if x != nil {
return x.ParentBlockHash
}
return nil
}
func (x *ExecutionPayloadHeaderEPBS) GetParentBlockRoot() []byte {
if x != nil {
return x.ParentBlockRoot
}
return nil
}
func (x *ExecutionPayloadHeaderEPBS) GetBlockHash() []byte {
if x != nil {
return x.BlockHash
}
return nil
}
func (x *ExecutionPayloadHeaderEPBS) GetGasLimit() uint64 {
if x != nil {
return x.GasLimit
}
return 0
}
func (x *ExecutionPayloadHeaderEPBS) GetBuilderIndex() github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.ValidatorIndex {
if x != nil {
return x.BuilderIndex
}
return github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.ValidatorIndex(0)
}
func (x *ExecutionPayloadHeaderEPBS) GetSlot() github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.Slot {
if x != nil {
return x.Slot
}
return github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.Slot(0)
}
func (x *ExecutionPayloadHeaderEPBS) GetValue() uint64 {
if x != nil {
return x.Value
}
return 0
}
func (x *ExecutionPayloadHeaderEPBS) GetBlobKzgCommitmentsRoot() []byte {
if x != nil {
return x.BlobKzgCommitmentsRoot
}
return nil
}
type SignedExecutionPayloadHeader struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Message *ExecutionPayloadHeaderEPBS `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
Signature []byte `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty" ssz-size:"96"`
}
func (x *SignedExecutionPayloadHeader) Reset() {
*x = SignedExecutionPayloadHeader{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_engine_v1_epbs_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SignedExecutionPayloadHeader) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SignedExecutionPayloadHeader) ProtoMessage() {}
func (x *SignedExecutionPayloadHeader) ProtoReflect() protoreflect.Message {
mi := &file_proto_engine_v1_epbs_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SignedExecutionPayloadHeader.ProtoReflect.Descriptor instead.
func (*SignedExecutionPayloadHeader) Descriptor() ([]byte, []int) {
return file_proto_engine_v1_epbs_proto_rawDescGZIP(), []int{1}
}
func (x *SignedExecutionPayloadHeader) GetMessage() *ExecutionPayloadHeaderEPBS {
if x != nil {
return x.Message
}
return nil
}
func (x *SignedExecutionPayloadHeader) GetSignature() []byte {
if x != nil {
return x.Signature
}
return nil
}
type ExecutionPayloadEnvelope struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Payload *ExecutionPayloadElectra `protobuf:"bytes,1,opt,name=payload,proto3" json:"payload,omitempty"`
BuilderIndex github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.ValidatorIndex `protobuf:"varint,2,opt,name=builder_index,json=builderIndex,proto3" json:"builder_index,omitempty" cast-type:"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives.ValidatorIndex"`
BeaconBlockRoot []byte `protobuf:"bytes,3,opt,name=beacon_block_root,json=beaconBlockRoot,proto3" json:"beacon_block_root,omitempty" ssz-size:"32"`
BlobKzgCommitments [][]byte `protobuf:"bytes,4,rep,name=blob_kzg_commitments,json=blobKzgCommitments,proto3" json:"blob_kzg_commitments,omitempty" ssz-max:"4096" ssz-size:"?,48"`
PayloadWithheld bool `protobuf:"varint,8,opt,name=payload_withheld,json=payloadWithheld,proto3" json:"payload_withheld,omitempty"`
StateRoot []byte `protobuf:"bytes,9,opt,name=state_root,json=stateRoot,proto3" json:"state_root,omitempty" ssz-size:"32"`
}
func (x *ExecutionPayloadEnvelope) Reset() {
*x = ExecutionPayloadEnvelope{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_engine_v1_epbs_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ExecutionPayloadEnvelope) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ExecutionPayloadEnvelope) ProtoMessage() {}
func (x *ExecutionPayloadEnvelope) ProtoReflect() protoreflect.Message {
mi := &file_proto_engine_v1_epbs_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ExecutionPayloadEnvelope.ProtoReflect.Descriptor instead.
func (*ExecutionPayloadEnvelope) Descriptor() ([]byte, []int) {
return file_proto_engine_v1_epbs_proto_rawDescGZIP(), []int{2}
}
func (x *ExecutionPayloadEnvelope) GetPayload() *ExecutionPayloadElectra {
if x != nil {
return x.Payload
}
return nil
}
func (x *ExecutionPayloadEnvelope) GetBuilderIndex() github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.ValidatorIndex {
if x != nil {
return x.BuilderIndex
}
return github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.ValidatorIndex(0)
}
func (x *ExecutionPayloadEnvelope) GetBeaconBlockRoot() []byte {
if x != nil {
return x.BeaconBlockRoot
}
return nil
}
func (x *ExecutionPayloadEnvelope) GetBlobKzgCommitments() [][]byte {
if x != nil {
return x.BlobKzgCommitments
}
return nil
}
func (x *ExecutionPayloadEnvelope) GetPayloadWithheld() bool {
if x != nil {
return x.PayloadWithheld
}
return false
}
func (x *ExecutionPayloadEnvelope) GetStateRoot() []byte {
if x != nil {
return x.StateRoot
}
return nil
}
type SignedExecutionPayloadEnvelope struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Message *ExecutionPayloadEnvelope `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
Signature []byte `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty" ssz-size:"96"`
}
func (x *SignedExecutionPayloadEnvelope) Reset() {
*x = SignedExecutionPayloadEnvelope{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_engine_v1_epbs_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SignedExecutionPayloadEnvelope) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SignedExecutionPayloadEnvelope) ProtoMessage() {}
func (x *SignedExecutionPayloadEnvelope) ProtoReflect() protoreflect.Message {
mi := &file_proto_engine_v1_epbs_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SignedExecutionPayloadEnvelope.ProtoReflect.Descriptor instead.
func (*SignedExecutionPayloadEnvelope) Descriptor() ([]byte, []int) {
return file_proto_engine_v1_epbs_proto_rawDescGZIP(), []int{3}
}
func (x *SignedExecutionPayloadEnvelope) GetMessage() *ExecutionPayloadEnvelope {
if x != nil {
return x.Message
}
return nil
}
func (x *SignedExecutionPayloadEnvelope) GetSignature() []byte {
if x != nil {
return x.Signature
}
return nil
}
var File_proto_engine_v1_epbs_proto protoreflect.FileDescriptor
var file_proto_engine_v1_epbs_proto_rawDesc = []byte{
0x0a, 0x1a, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x2f, 0x76,
0x31, 0x2f, 0x65, 0x70, 0x62, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x65, 0x74,
0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31,
0x1a, 0x1b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x74, 0x68, 0x2f, 0x65, 0x78, 0x74, 0x2f,
0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x26, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x65,
0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf2, 0x03, 0x0a, 0x1a, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74,
0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72,
0x45, 0x50, 0x42, 0x53, 0x12, 0x32, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x62,
0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42,
0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42,
0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x12, 0x32, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65,
0x6e, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x02, 0x20,
0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x0f, 0x70, 0x61, 0x72,
0x65, 0x6e, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x25, 0x0a, 0x0a,
0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c,
0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48,
0x61, 0x73, 0x68, 0x12, 0x1b, 0x0a, 0x09, 0x67, 0x61, 0x73, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74,
0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x67, 0x61, 0x73, 0x4c, 0x69, 0x6d, 0x69, 0x74,
0x12, 0x74, 0x0a, 0x0d, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x64, 0x65,
0x78, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x42, 0x4f, 0x82, 0xb5, 0x18, 0x4b, 0x67, 0x69, 0x74,
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x61, 0x74, 0x69,
0x63, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x35, 0x2f, 0x63,
0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70,
0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61,
0x74, 0x6f, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65,
0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x59, 0x0a, 0x04, 0x73, 0x6c, 0x6f, 0x74, 0x18, 0x06,
0x20, 0x01, 0x28, 0x04, 0x42, 0x45, 0x82, 0xb5, 0x18, 0x41, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x6c, 0x61,
0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x35, 0x2f, 0x63, 0x6f, 0x6e, 0x73,
0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d,
0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x53, 0x6c, 0x6f, 0x74, 0x52, 0x04, 0x73, 0x6c, 0x6f,
0x74, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04,
0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x41, 0x0a, 0x19, 0x62, 0x6c, 0x6f, 0x62, 0x5f,
0x6b, 0x7a, 0x67, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x5f,
0x72, 0x6f, 0x6f, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02,
0x33, 0x32, 0x52, 0x16, 0x62, 0x6c, 0x6f, 0x62, 0x4b, 0x7a, 0x67, 0x43, 0x6f, 0x6d, 0x6d, 0x69,
0x74, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x8e, 0x01, 0x0a, 0x1c, 0x53,
0x69, 0x67, 0x6e, 0x65, 0x64, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61,
0x79, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x48, 0x0a, 0x07, 0x6d,
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x65,
0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x2e, 0x76,
0x31, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f,
0x61, 0x64, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x45, 0x50, 0x42, 0x53, 0x52, 0x07, 0x6d, 0x65,
0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x24, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75,
0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x39, 0x36,
0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0xa1, 0x03, 0x0a, 0x18,
0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64,
0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x45, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c,
0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x65, 0x74, 0x68, 0x65,
0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45,
0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x45,
0x6c, 0x65, 0x63, 0x74, 0x72, 0x61, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12,
0x74, 0x0a, 0x0d, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78,
0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42, 0x4f, 0x82, 0xb5, 0x18, 0x4b, 0x67, 0x69, 0x74, 0x68,
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x61, 0x74, 0x69, 0x63,
0x6c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x35, 0x2f, 0x63, 0x6f,
0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70, 0x72,
0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74,
0x6f, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72,
0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x32, 0x0a, 0x11, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x5f,
0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c,
0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x0f, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e,
0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x42, 0x0a, 0x14, 0x62, 0x6c, 0x6f,
0x62, 0x5f, 0x6b, 0x7a, 0x67, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74,
0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0c, 0x42, 0x10, 0x8a, 0xb5, 0x18, 0x04, 0x3f, 0x2c, 0x34,
0x38, 0x92, 0xb5, 0x18, 0x04, 0x34, 0x30, 0x39, 0x36, 0x52, 0x12, 0x62, 0x6c, 0x6f, 0x62, 0x4b,
0x7a, 0x67, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x29, 0x0a,
0x10, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x68, 0x65, 0x6c,
0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64,
0x57, 0x69, 0x74, 0x68, 0x68, 0x65, 0x6c, 0x64, 0x12, 0x25, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74,
0x65, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5,
0x18, 0x02, 0x33, 0x32, 0x52, 0x09, 0x73, 0x74, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x22,
0x8e, 0x01, 0x0a, 0x1e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74,
0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f,
0x70, 0x65, 0x12, 0x46, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65,
0x6e, 0x67, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69,
0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70,
0x65, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x24, 0x0a, 0x09, 0x73, 0x69,
0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a,
0xb5, 0x18, 0x02, 0x39, 0x36, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65,
0x42, 0x96, 0x01, 0x0a, 0x16, 0x6f, 0x72, 0x67, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75,
0x6d, 0x2e, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x42, 0x14, 0x45, 0x78, 0x65,
0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x50, 0x72, 0x6f, 0x74,
0x6f, 0x50, 0x01, 0x5a, 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
0x70, 0x72, 0x79, 0x73, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72,
0x79, 0x73, 0x6d, 0x2f, 0x76, 0x35, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x6e, 0x67,
0x69, 0x6e, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x76, 0x31, 0xaa,
0x02, 0x12, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x45, 0x6e, 0x67, 0x69, 0x6e,
0x65, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x12, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x5c,
0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x5c, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
}
var (
file_proto_engine_v1_epbs_proto_rawDescOnce sync.Once
file_proto_engine_v1_epbs_proto_rawDescData = file_proto_engine_v1_epbs_proto_rawDesc
)
func file_proto_engine_v1_epbs_proto_rawDescGZIP() []byte {
file_proto_engine_v1_epbs_proto_rawDescOnce.Do(func() {
file_proto_engine_v1_epbs_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_engine_v1_epbs_proto_rawDescData)
})
return file_proto_engine_v1_epbs_proto_rawDescData
}
var file_proto_engine_v1_epbs_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_proto_engine_v1_epbs_proto_goTypes = []interface{}{
(*ExecutionPayloadHeaderEPBS)(nil), // 0: ethereum.engine.v1.ExecutionPayloadHeaderEPBS
(*SignedExecutionPayloadHeader)(nil), // 1: ethereum.engine.v1.SignedExecutionPayloadHeader
(*ExecutionPayloadEnvelope)(nil), // 2: ethereum.engine.v1.ExecutionPayloadEnvelope
(*SignedExecutionPayloadEnvelope)(nil), // 3: ethereum.engine.v1.SignedExecutionPayloadEnvelope
(*ExecutionPayloadElectra)(nil), // 4: ethereum.engine.v1.ExecutionPayloadElectra
}
var file_proto_engine_v1_epbs_proto_depIdxs = []int32{
0, // 0: ethereum.engine.v1.SignedExecutionPayloadHeader.message:type_name -> ethereum.engine.v1.ExecutionPayloadHeaderEPBS
4, // 1: ethereum.engine.v1.ExecutionPayloadEnvelope.payload:type_name -> ethereum.engine.v1.ExecutionPayloadElectra
2, // 2: ethereum.engine.v1.SignedExecutionPayloadEnvelope.message:type_name -> ethereum.engine.v1.ExecutionPayloadEnvelope
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_proto_engine_v1_epbs_proto_init() }
func file_proto_engine_v1_epbs_proto_init() {
if File_proto_engine_v1_epbs_proto != nil {
return
}
file_proto_engine_v1_execution_engine_proto_init()
if !protoimpl.UnsafeEnabled {
file_proto_engine_v1_epbs_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ExecutionPayloadHeaderEPBS); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proto_engine_v1_epbs_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SignedExecutionPayloadHeader); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proto_engine_v1_epbs_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ExecutionPayloadEnvelope); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proto_engine_v1_epbs_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SignedExecutionPayloadEnvelope); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proto_engine_v1_epbs_proto_rawDesc,
NumEnums: 0,
NumMessages: 4,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_proto_engine_v1_epbs_proto_goTypes,
DependencyIndexes: file_proto_engine_v1_epbs_proto_depIdxs,
MessageInfos: file_proto_engine_v1_epbs_proto_msgTypes,
}.Build()
File_proto_engine_v1_epbs_proto = out.File
file_proto_engine_v1_epbs_proto_rawDesc = nil
file_proto_engine_v1_epbs_proto_goTypes = nil
file_proto_engine_v1_epbs_proto_depIdxs = nil
}

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