mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 21:38:05 -05:00
Compare commits
12 Commits
v5.1.0
...
hashtree_h
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1c85703a9 | ||
|
|
f43383a3fb | ||
|
|
22f6f787e1 | ||
|
|
44b3986025 | ||
|
|
6cb845660a | ||
|
|
de2c866707 | ||
|
|
74ddb84e0a | ||
|
|
0c6a068fd5 | ||
|
|
fad92472d8 | ||
|
|
2a44e8e6ec | ||
|
|
e3d27f29c7 | ||
|
|
e011f05403 |
10
WORKSPACE
10
WORKSPACE
@@ -227,7 +227,7 @@ filegroup(
|
||||
url = "https://github.com/ethereum/EIPs/archive/5480440fe51742ed23342b68cf106cefd427e39d.tar.gz",
|
||||
)
|
||||
|
||||
consensus_spec_version = "v1.5.0-alpha.3"
|
||||
consensus_spec_version = "v1.5.0-alpha.4"
|
||||
|
||||
bls_test_version = "v0.1.1"
|
||||
|
||||
@@ -243,7 +243,7 @@ filegroup(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
integrity = "sha256-+byv+GUOQytex5GgtjBGVoNDseJZbiBdAjEtlgCbjEo=",
|
||||
integrity = "sha256-sSw6c9IR/ZiWjyk1cbfVGC/aUkId4r7+eSl3haWsq0E=",
|
||||
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/general.tar.gz" % consensus_spec_version,
|
||||
)
|
||||
|
||||
@@ -259,7 +259,7 @@ filegroup(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
integrity = "sha256-JJUy/jT1h3kGQkinTuzL7gMOA1+qgmPgJXVrYuH63Cg=",
|
||||
integrity = "sha256-OGlKhbA6TjTP0p1ojXVCJPzLEHJzewKkhAa+PQggoiU=",
|
||||
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/minimal.tar.gz" % consensus_spec_version,
|
||||
)
|
||||
|
||||
@@ -275,7 +275,7 @@ filegroup(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
integrity = "sha256-T2VM4Qd0SwgGnTjWxjOX297DqEsovO9Ueij1UEJy48Y=",
|
||||
integrity = "sha256-ah2Gj4ci5hw5vQgpUWkNjEQutoBCepg5jcpTi0DKVB0=",
|
||||
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/mainnet.tar.gz" % consensus_spec_version,
|
||||
)
|
||||
|
||||
@@ -290,7 +290,7 @@ filegroup(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
integrity = "sha256-OP9BCBcQ7i+93bwj7ktY8pZ5uWsGjgTe4XTp7BDhX+I=",
|
||||
integrity = "sha256-I+llAsIF6lPP8RUtZ2DFsJqtCs4UPh+st3hFs12FWpY=",
|
||||
strip_prefix = "consensus-specs-" + consensus_spec_version[1:],
|
||||
url = "https://github.com/ethereum/consensus-specs/archive/refs/tags/%s.tar.gz" % consensus_spec_version,
|
||||
)
|
||||
|
||||
@@ -2044,7 +2044,11 @@ func TestOnBlock_HandleBlockAttestations(t *testing.T) {
|
||||
|
||||
st, err = service.HeadState(ctx)
|
||||
require.NoError(t, err)
|
||||
b, err := util.GenerateFullBlockElectra(st, keys, util.DefaultBlockGenConfig(), 1)
|
||||
defaultConfig := util.DefaultBlockGenConfig()
|
||||
defaultConfig.NumWithdrawalRequests = 1
|
||||
defaultConfig.NumDepositRequests = 2
|
||||
defaultConfig.NumConsolidationRequests = 1
|
||||
b, err := util.GenerateFullBlockElectra(st, keys, defaultConfig, 1)
|
||||
require.NoError(t, err)
|
||||
wsb, err := consensusblocks.NewSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
@@ -2059,7 +2063,7 @@ func TestOnBlock_HandleBlockAttestations(t *testing.T) {
|
||||
|
||||
st, err = service.HeadState(ctx)
|
||||
require.NoError(t, err)
|
||||
b, err = util.GenerateFullBlockElectra(st, keys, util.DefaultBlockGenConfig(), 2)
|
||||
b, err = util.GenerateFullBlockElectra(st, keys, defaultConfig, 2)
|
||||
require.NoError(t, err)
|
||||
wsb, err = consensusblocks.NewSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
@@ -2067,7 +2071,7 @@ func TestOnBlock_HandleBlockAttestations(t *testing.T) {
|
||||
// prepare another block that is not inserted
|
||||
st3, err := transition.ExecuteStateTransition(ctx, st, wsb)
|
||||
require.NoError(t, err)
|
||||
b3, err := util.GenerateFullBlockElectra(st3, keys, util.DefaultBlockGenConfig(), 3)
|
||||
b3, err := util.GenerateFullBlockElectra(st3, keys, defaultConfig, 3)
|
||||
require.NoError(t, err)
|
||||
wsb3, err := consensusblocks.NewSignedBeaconBlock(b3)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
"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/time/slots"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.opencensus.io/trace"
|
||||
@@ -190,13 +191,26 @@ func (s *Service) processAttestations(ctx context.Context, disparity time.Durati
|
||||
}
|
||||
|
||||
if err := s.receiveAttestationNoPubsub(ctx, a, disparity); err != nil {
|
||||
log.WithFields(logrus.Fields{
|
||||
"slot": a.GetData().Slot,
|
||||
"committeeIndex": a.GetData().CommitteeIndex,
|
||||
"beaconBlockRoot": fmt.Sprintf("%#x", bytesutil.Trunc(a.GetData().BeaconBlockRoot)),
|
||||
"targetRoot": fmt.Sprintf("%#x", bytesutil.Trunc(a.GetData().Target.Root)),
|
||||
"aggregationCount": a.GetAggregationBits().Count(),
|
||||
}).WithError(err).Warn("Could not process attestation for fork choice")
|
||||
var fields logrus.Fields
|
||||
if a.Version() >= version.Electra {
|
||||
fields = logrus.Fields{
|
||||
"slot": a.GetData().Slot,
|
||||
"committeeCount": a.CommitteeBitsVal().Count(),
|
||||
"committeeIndices": a.CommitteeBitsVal().BitIndices(),
|
||||
"beaconBlockRoot": fmt.Sprintf("%#x", bytesutil.Trunc(a.GetData().BeaconBlockRoot)),
|
||||
"targetRoot": fmt.Sprintf("%#x", bytesutil.Trunc(a.GetData().Target.Root)),
|
||||
"aggregatedCount": a.GetAggregationBits().Count(),
|
||||
}
|
||||
} else {
|
||||
fields = logrus.Fields{
|
||||
"slot": a.GetData().Slot,
|
||||
"committeeIndex": a.GetData().CommitteeIndex,
|
||||
"beaconBlockRoot": fmt.Sprintf("%#x", bytesutil.Trunc(a.GetData().BeaconBlockRoot)),
|
||||
"targetRoot": fmt.Sprintf("%#x", bytesutil.Trunc(a.GetData().Target.Root)),
|
||||
"aggregatedCount": a.GetAggregationBits().Count(),
|
||||
}
|
||||
}
|
||||
log.WithFields(fields).WithError(err).Warn("Could not process attestation for fork choice")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,25 +110,7 @@ func VerifyAttestationNoVerifySignature(
|
||||
|
||||
var indexedAtt ethpb.IndexedAtt
|
||||
|
||||
if att.Version() < version.Electra {
|
||||
if uint64(att.GetData().CommitteeIndex) >= c {
|
||||
return fmt.Errorf("committee index %d >= committee count %d", att.GetData().CommitteeIndex, c)
|
||||
}
|
||||
|
||||
if err = helpers.VerifyAttestationBitfieldLengths(ctx, beaconState, att); err != nil {
|
||||
return errors.Wrap(err, "could not verify attestation bitfields")
|
||||
}
|
||||
|
||||
// Verify attesting indices are correct.
|
||||
committee, err := helpers.BeaconCommitteeFromState(ctx, beaconState, att.GetData().Slot, att.GetData().CommitteeIndex)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
indexedAtt, err = attestation.ConvertToIndexed(ctx, att, committee)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if att.Version() >= version.Electra {
|
||||
if att.GetData().CommitteeIndex != 0 {
|
||||
return errors.New("committee index must be 0 post-Electra")
|
||||
}
|
||||
@@ -154,6 +136,29 @@ func VerifyAttestationNoVerifySignature(
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if uint64(att.GetData().CommitteeIndex) >= c {
|
||||
return fmt.Errorf("committee index %d >= committee count %d", att.GetData().CommitteeIndex, c)
|
||||
}
|
||||
|
||||
// Verify attesting indices are correct.
|
||||
committee, err := helpers.BeaconCommitteeFromState(ctx, beaconState, att.GetData().Slot, att.GetData().CommitteeIndex)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if committee == nil {
|
||||
return errors.New("no committee exist for this attestation")
|
||||
}
|
||||
|
||||
if err := helpers.VerifyBitfieldLength(att.GetAggregationBits(), uint64(len(committee))); err != nil {
|
||||
return errors.Wrap(err, "failed to verify aggregation bitfield")
|
||||
}
|
||||
|
||||
indexedAtt, err = attestation.ConvertToIndexed(ctx, att, committee)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return attestation.IsValidAttestationIndices(ctx, indexedAtt)
|
||||
|
||||
@@ -49,7 +49,7 @@ func ProcessPendingConsolidations(ctx context.Context, st state.BeaconState) err
|
||||
return errors.New("nil state")
|
||||
}
|
||||
|
||||
currentEpoch := slots.ToEpoch(st.Slot())
|
||||
nextEpoch := slots.ToEpoch(st.Slot()) + 1
|
||||
|
||||
var nextPendingConsolidation uint64
|
||||
pendingConsolidations, err := st.PendingConsolidations()
|
||||
@@ -66,7 +66,7 @@ func ProcessPendingConsolidations(ctx context.Context, st state.BeaconState) err
|
||||
nextPendingConsolidation++
|
||||
continue
|
||||
}
|
||||
if sourceValidator.WithdrawableEpoch > currentEpoch {
|
||||
if sourceValidator.WithdrawableEpoch > nextEpoch {
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
@@ -248,7 +248,7 @@ func ProcessPendingBalanceDeposits(ctx context.Context, st state.BeaconState, ac
|
||||
|
||||
// constants
|
||||
ffe := params.BeaconConfig().FarFutureEpoch
|
||||
curEpoch := slots.ToEpoch(st.Slot())
|
||||
nextEpoch := slots.ToEpoch(st.Slot()) + 1
|
||||
|
||||
for _, balanceDeposit := range deposits {
|
||||
v, err := st.ValidatorAtIndexReadOnly(balanceDeposit.Index)
|
||||
@@ -259,7 +259,7 @@ func ProcessPendingBalanceDeposits(ctx context.Context, st state.BeaconState, ac
|
||||
// If the validator is currently exiting, postpone the deposit until after the withdrawable
|
||||
// epoch.
|
||||
if v.ExitEpoch() < ffe {
|
||||
if curEpoch <= v.WithdrawableEpoch() {
|
||||
if nextEpoch <= v.WithdrawableEpoch() {
|
||||
depositsToPostpone = append(depositsToPostpone, balanceDeposit)
|
||||
} else {
|
||||
// The deposited balance will never become active. Therefore, we increase the balance but do
|
||||
|
||||
@@ -22,7 +22,6 @@ go_library(
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//math:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//proto/prysm/v1alpha1/attestation:go_default_library",
|
||||
"//runtime/version:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
],
|
||||
@@ -53,7 +52,6 @@ go_test(
|
||||
"//testing/util:go_default_library",
|
||||
"@com_github_google_go_cmp//cmp:go_default_library",
|
||||
"@com_github_google_gofuzz//:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -20,32 +20,9 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v5/math"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1/attestation"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
)
|
||||
|
||||
// AttestingBalance returns the total balance from all the attesting indices.
|
||||
//
|
||||
// WARNING: This method allocates a new copy of the attesting validator indices set and is
|
||||
// considered to be very memory expensive. Avoid using this unless you really
|
||||
// need to get attesting balance from attestations.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
//
|
||||
// def get_attesting_balance(state: BeaconState, attestations: Sequence[PendingAttestation]) -> Gwei:
|
||||
// """
|
||||
// Return the combined effective balance of the set of unslashed validators participating in ``attestations``.
|
||||
// Note: ``get_total_balance`` returns ``EFFECTIVE_BALANCE_INCREMENT`` Gwei minimum to avoid divisions by zero.
|
||||
// """
|
||||
// return get_total_balance(state, get_unslashed_attesting_indices(state, attestations))
|
||||
func AttestingBalance(ctx context.Context, state state.ReadOnlyBeaconState, atts []*ethpb.PendingAttestation) (uint64, error) {
|
||||
indices, err := UnslashedAttestingIndices(ctx, state, atts)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "could not get attesting indices")
|
||||
}
|
||||
return helpers.TotalBalance(state, indices), nil
|
||||
}
|
||||
|
||||
// ProcessRegistryUpdates rotates validators in and out of active pool.
|
||||
// the amount to rotate is determined churn limit.
|
||||
//
|
||||
@@ -455,51 +432,3 @@ func ProcessFinalUpdates(state state.BeaconState) (state.BeaconState, error) {
|
||||
|
||||
return state, nil
|
||||
}
|
||||
|
||||
// UnslashedAttestingIndices returns all the attesting indices from a list of attestations,
|
||||
// it sorts the indices and filters out the slashed ones.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
//
|
||||
// def get_unslashed_attesting_indices(state: BeaconState,
|
||||
// attestations: Sequence[PendingAttestation]) -> Set[ValidatorIndex]:
|
||||
// output = set() # type: Set[ValidatorIndex]
|
||||
// for a in attestations:
|
||||
// output = output.union(get_attesting_indices(state, a.data, a.aggregation_bits))
|
||||
// return set(filter(lambda index: not state.validators[index].slashed, output))
|
||||
func UnslashedAttestingIndices(ctx context.Context, state state.ReadOnlyBeaconState, atts []*ethpb.PendingAttestation) ([]primitives.ValidatorIndex, error) {
|
||||
var setIndices []primitives.ValidatorIndex
|
||||
seen := make(map[uint64]bool)
|
||||
|
||||
for _, att := range atts {
|
||||
committee, err := helpers.BeaconCommitteeFromState(ctx, state, att.GetData().Slot, att.GetData().CommitteeIndex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
attestingIndices, err := attestation.AttestingIndices(att, committee)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Create a set for attesting indices
|
||||
for _, index := range attestingIndices {
|
||||
if !seen[index] {
|
||||
setIndices = append(setIndices, primitives.ValidatorIndex(index))
|
||||
}
|
||||
seen[index] = true
|
||||
}
|
||||
}
|
||||
// Sort the attesting set indices by increasing order.
|
||||
sort.Slice(setIndices, func(i, j int) bool { return setIndices[i] < setIndices[j] })
|
||||
// Remove the slashed validator indices.
|
||||
for i := 0; i < len(setIndices); i++ {
|
||||
v, err := state.ValidatorAtIndexReadOnly(setIndices[i])
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to look up validator")
|
||||
}
|
||||
if !v.IsNil() && v.Slashed() {
|
||||
setIndices = append(setIndices[:i], setIndices[i+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
return setIndices, nil
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/epoch"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time"
|
||||
@@ -24,131 +23,6 @@ import (
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func TestUnslashedAttestingIndices_CanSortAndFilter(t *testing.T) {
|
||||
// Generate 2 attestations.
|
||||
atts := make([]*ethpb.PendingAttestation, 2)
|
||||
for i := 0; i < len(atts); i++ {
|
||||
atts[i] = ðpb.PendingAttestation{
|
||||
Data: ðpb.AttestationData{Source: ðpb.Checkpoint{Root: make([]byte, fieldparams.RootLength)},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, fieldparams.RootLength)},
|
||||
},
|
||||
AggregationBits: bitfield.Bitlist{0x00, 0xFF, 0xFF, 0xFF},
|
||||
}
|
||||
}
|
||||
|
||||
// Generate validators and state for the 2 attestations.
|
||||
validatorCount := 1000
|
||||
validators := make([]*ethpb.Validator, validatorCount)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = ðpb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
base := ðpb.BeaconState{
|
||||
Validators: validators,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
}
|
||||
beaconState, err := state_native.InitializeFromProtoPhase0(base)
|
||||
require.NoError(t, err)
|
||||
|
||||
indices, err := epoch.UnslashedAttestingIndices(context.Background(), beaconState, atts)
|
||||
require.NoError(t, err)
|
||||
for i := 0; i < len(indices)-1; i++ {
|
||||
if indices[i] >= indices[i+1] {
|
||||
t.Error("sorted indices not sorted or duplicated")
|
||||
}
|
||||
}
|
||||
|
||||
// Verify the slashed validator is filtered.
|
||||
slashedValidator := indices[0]
|
||||
validators = beaconState.Validators()
|
||||
validators[slashedValidator].Slashed = true
|
||||
require.NoError(t, beaconState.SetValidators(validators))
|
||||
indices, err = epoch.UnslashedAttestingIndices(context.Background(), beaconState, atts)
|
||||
require.NoError(t, err)
|
||||
for i := 0; i < len(indices); i++ {
|
||||
assert.NotEqual(t, slashedValidator, indices[i], "Slashed validator %d is not filtered", slashedValidator)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnslashedAttestingIndices_DuplicatedAttestations(t *testing.T) {
|
||||
// Generate 5 of the same attestations.
|
||||
atts := make([]*ethpb.PendingAttestation, 5)
|
||||
for i := 0; i < len(atts); i++ {
|
||||
atts[i] = ðpb.PendingAttestation{
|
||||
Data: ðpb.AttestationData{Source: ðpb.Checkpoint{Root: make([]byte, fieldparams.RootLength)},
|
||||
Target: ðpb.Checkpoint{Epoch: 0}},
|
||||
AggregationBits: bitfield.Bitlist{0x00, 0xFF, 0xFF, 0xFF},
|
||||
}
|
||||
}
|
||||
|
||||
// Generate validators and state for the 5 attestations.
|
||||
validatorCount := 1000
|
||||
validators := make([]*ethpb.Validator, validatorCount)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = ðpb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
base := ðpb.BeaconState{
|
||||
Validators: validators,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
}
|
||||
beaconState, err := state_native.InitializeFromProtoPhase0(base)
|
||||
require.NoError(t, err)
|
||||
|
||||
indices, err := epoch.UnslashedAttestingIndices(context.Background(), beaconState, atts)
|
||||
require.NoError(t, err)
|
||||
|
||||
for i := 0; i < len(indices)-1; i++ {
|
||||
if indices[i] >= indices[i+1] {
|
||||
t.Error("sorted indices not sorted or duplicated")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttestingBalance_CorrectBalance(t *testing.T) {
|
||||
helpers.ClearCache()
|
||||
// Generate 2 attestations.
|
||||
atts := make([]*ethpb.PendingAttestation, 2)
|
||||
for i := 0; i < len(atts); i++ {
|
||||
atts[i] = ðpb.PendingAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{Root: make([]byte, fieldparams.RootLength)},
|
||||
Source: ðpb.Checkpoint{Root: make([]byte, fieldparams.RootLength)},
|
||||
Slot: primitives.Slot(i),
|
||||
},
|
||||
AggregationBits: bitfield.Bitlist{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01},
|
||||
}
|
||||
}
|
||||
|
||||
// Generate validators with balances and state for the 2 attestations.
|
||||
validators := make([]*ethpb.Validator, params.BeaconConfig().MinGenesisActiveValidatorCount)
|
||||
balances := make([]uint64, params.BeaconConfig().MinGenesisActiveValidatorCount)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = ðpb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
||||
}
|
||||
balances[i] = params.BeaconConfig().MaxEffectiveBalance
|
||||
}
|
||||
base := ðpb.BeaconState{
|
||||
Slot: 2,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
|
||||
Validators: validators,
|
||||
Balances: balances,
|
||||
}
|
||||
beaconState, err := state_native.InitializeFromProtoPhase0(base)
|
||||
require.NoError(t, err)
|
||||
|
||||
balance, err := epoch.AttestingBalance(context.Background(), beaconState, atts)
|
||||
require.NoError(t, err)
|
||||
wanted := 256 * params.BeaconConfig().MaxEffectiveBalance
|
||||
assert.Equal(t, wanted, balance)
|
||||
}
|
||||
|
||||
func TestProcessSlashings_NotSlashed(t *testing.T) {
|
||||
base := ðpb.BeaconState{
|
||||
Slot: 0,
|
||||
|
||||
@@ -47,7 +47,6 @@ go_test(
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//beacon-chain/core/altair:go_default_library",
|
||||
"//beacon-chain/core/epoch:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/time:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/epoch"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
@@ -59,90 +58,6 @@ func TestProcessRewardsAndPenaltiesPrecompute(t *testing.T) {
|
||||
assert.Equal(t, wanted, beaconState.Balances()[0], "Unexpected balance")
|
||||
}
|
||||
|
||||
func TestAttestationDeltaPrecompute(t *testing.T) {
|
||||
e := params.BeaconConfig().SlotsPerEpoch
|
||||
validatorCount := uint64(2048)
|
||||
base := buildState(e+2, validatorCount)
|
||||
atts := make([]*ethpb.PendingAttestation, 3)
|
||||
var emptyRoot [32]byte
|
||||
for i := 0; i < len(atts); i++ {
|
||||
atts[i] = ðpb.PendingAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{
|
||||
Root: emptyRoot[:],
|
||||
},
|
||||
Source: ðpb.Checkpoint{
|
||||
Root: emptyRoot[:],
|
||||
},
|
||||
BeaconBlockRoot: emptyRoot[:],
|
||||
},
|
||||
AggregationBits: bitfield.Bitlist{0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x01},
|
||||
InclusionDelay: 1,
|
||||
}
|
||||
}
|
||||
base.PreviousEpochAttestations = atts
|
||||
beaconState, err := state_native.InitializeFromProtoPhase0(base)
|
||||
require.NoError(t, err)
|
||||
slashedAttestedIndices := []primitives.ValidatorIndex{1413}
|
||||
for _, i := range slashedAttestedIndices {
|
||||
vs := beaconState.Validators()
|
||||
vs[i].Slashed = true
|
||||
require.Equal(t, nil, beaconState.SetValidators(vs))
|
||||
}
|
||||
|
||||
vp, bp, err := New(context.Background(), beaconState)
|
||||
require.NoError(t, err)
|
||||
vp, bp, err = ProcessAttestations(context.Background(), beaconState, vp, bp)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Add some variances to target and head balances.
|
||||
// See: https://github.com/prysmaticlabs/prysm/issues/5593
|
||||
bp.PrevEpochTargetAttested /= 2
|
||||
bp.PrevEpochHeadAttested = bp.PrevEpochHeadAttested * 2 / 3
|
||||
rewards, penalties, err := AttestationsDelta(beaconState, bp, vp)
|
||||
require.NoError(t, err)
|
||||
attestedBalance, err := epoch.AttestingBalance(context.Background(), beaconState, atts)
|
||||
require.NoError(t, err)
|
||||
totalBalance, err := helpers.TotalActiveBalance(beaconState)
|
||||
require.NoError(t, err)
|
||||
|
||||
attestedIndices := []primitives.ValidatorIndex{55, 1339, 1746, 1811, 1569}
|
||||
for _, i := range attestedIndices {
|
||||
base, err := baseReward(beaconState, i)
|
||||
require.NoError(t, err, "Could not get base reward")
|
||||
|
||||
// Base rewards for getting source right
|
||||
wanted := attestedBalance*base/totalBalance +
|
||||
bp.PrevEpochTargetAttested*base/totalBalance +
|
||||
bp.PrevEpochHeadAttested*base/totalBalance
|
||||
// Base rewards for proposer and attesters working together getting attestation
|
||||
// on chain in the fatest manner
|
||||
proposerReward := base / params.BeaconConfig().ProposerRewardQuotient
|
||||
wanted += (base-proposerReward)*uint64(params.BeaconConfig().MinAttestationInclusionDelay) - 1
|
||||
assert.Equal(t, wanted, rewards[i], "Unexpected reward balance for validator with index %d", i)
|
||||
// Since all these validators attested, they shouldn't get penalized.
|
||||
assert.Equal(t, uint64(0), penalties[i], "Unexpected penalty balance")
|
||||
}
|
||||
|
||||
for _, i := range slashedAttestedIndices {
|
||||
base, err := baseReward(beaconState, i)
|
||||
assert.NoError(t, err, "Could not get base reward")
|
||||
assert.Equal(t, uint64(0), rewards[i], "Unexpected slashed indices reward balance")
|
||||
assert.Equal(t, 3*base, penalties[i], "Unexpected slashed indices penalty balance")
|
||||
}
|
||||
|
||||
nonAttestedIndices := []primitives.ValidatorIndex{434, 677, 872, 791}
|
||||
for _, i := range nonAttestedIndices {
|
||||
base, err := baseReward(beaconState, i)
|
||||
assert.NoError(t, err, "Could not get base reward")
|
||||
wanted := 3 * base
|
||||
// Since all these validators did not attest, they shouldn't get rewarded.
|
||||
assert.Equal(t, uint64(0), rewards[i], "Unexpected reward balance")
|
||||
// Base penalties for not attesting.
|
||||
assert.Equal(t, wanted, penalties[i], "Unexpected penalty balance")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttestationDeltas_ZeroEpoch(t *testing.T) {
|
||||
e := params.BeaconConfig().SlotsPerEpoch
|
||||
validatorCount := uint64(2048)
|
||||
|
||||
@@ -337,24 +337,6 @@ func VerifyBitfieldLength(bf bitfield.Bitfield, committeeSize uint64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// VerifyAttestationBitfieldLengths verifies that an attestations aggregation bitfields is
|
||||
// a valid length matching the size of the committee.
|
||||
func VerifyAttestationBitfieldLengths(ctx context.Context, state state.ReadOnlyBeaconState, att ethpb.Att) error {
|
||||
committee, err := BeaconCommitteeFromState(ctx, state, att.GetData().Slot, att.GetData().CommitteeIndex)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not retrieve beacon committees")
|
||||
}
|
||||
|
||||
if committee == nil {
|
||||
return errors.New("no committee exist for this attestation")
|
||||
}
|
||||
|
||||
if err := VerifyBitfieldLength(att.GetAggregationBits(), uint64(len(committee))); err != nil {
|
||||
return errors.Wrap(err, "failed to verify aggregation bitfield")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ShuffledIndices uses input beacon state and returns the shuffled indices of the input epoch,
|
||||
// the shuffled indices then can be used to break up into committees.
|
||||
func ShuffledIndices(s state.ReadOnlyBeaconState, epoch primitives.Epoch) ([]primitives.ValidatorIndex, error) {
|
||||
|
||||
@@ -403,7 +403,12 @@ func TestVerifyAttestationBitfieldLengths_OK(t *testing.T) {
|
||||
helpers.ClearCache()
|
||||
|
||||
require.NoError(t, state.SetSlot(tt.stateSlot))
|
||||
err := helpers.VerifyAttestationBitfieldLengths(context.Background(), state, tt.attestation)
|
||||
att := tt.attestation
|
||||
// Verify attesting indices are correct.
|
||||
committee, err := helpers.BeaconCommitteeFromState(context.Background(), state, att.GetData().Slot, att.GetData().CommitteeIndex)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, committee)
|
||||
err = helpers.VerifyBitfieldLength(att.GetAggregationBits(), uint64(len(committee)))
|
||||
if tt.verificationFailure {
|
||||
assert.NotNil(t, err, "Verification succeeded when it was supposed to fail")
|
||||
} else {
|
||||
|
||||
@@ -16,6 +16,11 @@ import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
MockRawPeerId0 = "16Uiu2HAkyWZ4Ni1TpvDS8dPxsozmHY85KaiFjodQuV6Tz5tkHVeR"
|
||||
MockRawPeerId1 = "16Uiu2HAm4HgJ9N1o222xK61o7LSgToYWoAy1wNTJRkh9gLZapVAy"
|
||||
)
|
||||
|
||||
// MockPeersProvider implements PeersProvider for testing.
|
||||
type MockPeersProvider struct {
|
||||
lock sync.Mutex
|
||||
@@ -50,7 +55,7 @@ func (m *MockPeersProvider) Peers() *peers.Status {
|
||||
},
|
||||
})
|
||||
// Pretend we are connected to two peers
|
||||
id0, err := peer.Decode("16Uiu2HAkyWZ4Ni1TpvDS8dPxsozmHY85KaiFjodQuV6Tz5tkHVeR")
|
||||
id0, err := peer.Decode(MockRawPeerId0)
|
||||
if err != nil {
|
||||
log.WithError(err).Debug("Cannot decode")
|
||||
}
|
||||
@@ -61,7 +66,7 @@ func (m *MockPeersProvider) Peers() *peers.Status {
|
||||
m.peers.Add(createENR(), id0, ma0, network.DirInbound)
|
||||
m.peers.SetConnectionState(id0, peers.PeerConnected)
|
||||
m.peers.SetChainState(id0, &pb.Status{FinalizedEpoch: 10})
|
||||
id1, err := peer.Decode("16Uiu2HAm4HgJ9N1o222xK61o7LSgToYWoAy1wNTJRkh9gLZapVAy")
|
||||
id1, err := peer.Decode(MockRawPeerId1)
|
||||
if err != nil {
|
||||
log.WithError(err).Debug("Cannot decode")
|
||||
}
|
||||
|
||||
@@ -128,13 +128,12 @@ func TestNodeServer_GetPeer(t *testing.T) {
|
||||
}
|
||||
ethpb.RegisterNodeServer(server, ns)
|
||||
reflection.Register(server)
|
||||
firstPeer := peersProvider.Peers().All()[0]
|
||||
|
||||
res, err := ns.GetPeer(context.Background(), ðpb.PeerRequest{PeerId: firstPeer.String()})
|
||||
res, err := ns.GetPeer(context.Background(), ðpb.PeerRequest{PeerId: mockP2p.MockRawPeerId0})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, firstPeer.String(), res.PeerId, "Unexpected peer ID")
|
||||
assert.Equal(t, "16Uiu2HAkyWZ4Ni1TpvDS8dPxsozmHY85KaiFjodQuV6Tz5tkHVeR" /* first peer's raw id */, res.PeerId, "Unexpected peer ID")
|
||||
assert.Equal(t, int(ethpb.PeerDirection_INBOUND), int(res.Direction), "Expected 1st peer to be an inbound connection")
|
||||
assert.Equal(t, ethpb.ConnectionState_CONNECTED, res.ConnectionState, "Expected peer to be connected")
|
||||
assert.Equal(t, int(ethpb.ConnectionState_CONNECTED), int(res.ConnectionState), "Expected peer to be connected")
|
||||
}
|
||||
|
||||
func TestNodeServer_ListPeers(t *testing.T) {
|
||||
@@ -149,8 +148,25 @@ func TestNodeServer_ListPeers(t *testing.T) {
|
||||
res, err := ns.ListPeers(context.Background(), &emptypb.Empty{})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 2, len(res.Peers))
|
||||
assert.Equal(t, int(ethpb.PeerDirection_INBOUND), int(res.Peers[0].Direction))
|
||||
assert.Equal(t, ethpb.PeerDirection_OUTBOUND, res.Peers[1].Direction)
|
||||
|
||||
var (
|
||||
firstPeer *ethpb.Peer
|
||||
secondPeer *ethpb.Peer
|
||||
)
|
||||
|
||||
for _, p := range res.Peers {
|
||||
if p.PeerId == mockP2p.MockRawPeerId0 {
|
||||
firstPeer = p
|
||||
}
|
||||
if p.PeerId == mockP2p.MockRawPeerId1 {
|
||||
secondPeer = p
|
||||
}
|
||||
}
|
||||
|
||||
assert.NotNil(t, firstPeer)
|
||||
assert.NotNil(t, secondPeer)
|
||||
assert.Equal(t, int(ethpb.PeerDirection_INBOUND), int(firstPeer.Direction))
|
||||
assert.Equal(t, int(ethpb.PeerDirection_OUTBOUND), int(secondPeer.Direction))
|
||||
}
|
||||
|
||||
func TestNodeServer_GetETH1ConnectionStatus(t *testing.T) {
|
||||
|
||||
@@ -66,18 +66,12 @@ func (vs *Server) ProposeAttestationElectra(ctx context.Context, att *ethpb.Atte
|
||||
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")
|
||||
committeeIndex, err := att.GetCommitteeIndex()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := vs.proposeAtt(ctx, att, committeeIndices[0])
|
||||
resp, err := vs.proposeAtt(ctx, att, committeeIndex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ func TestProposeAttestation(t *testing.T) {
|
||||
CommitteeBits: cb,
|
||||
}
|
||||
_, err = attesterServer.ProposeAttestationElectra(context.Background(), req)
|
||||
assert.ErrorContains(t, "Committee index must be set to 0", err)
|
||||
assert.ErrorContains(t, "attestation data's committee index must be 0 but was 1", err)
|
||||
})
|
||||
t.Run("Electra - no committee bit set", func(t *testing.T) {
|
||||
state, err := util.NewBeaconStateElectra()
|
||||
@@ -131,7 +131,7 @@ func TestProposeAttestation(t *testing.T) {
|
||||
CommitteeBits: primitives.NewAttestationCommitteeBits(),
|
||||
}
|
||||
_, err = attesterServer.ProposeAttestationElectra(context.Background(), req)
|
||||
assert.ErrorContains(t, "Committee bits has no bit set", err)
|
||||
assert.ErrorContains(t, "exactly 1 committee index must be set but 0 were set", err)
|
||||
})
|
||||
t.Run("Electra - multiple committee bits set", func(t *testing.T) {
|
||||
state, err := util.NewBeaconStateElectra()
|
||||
@@ -152,7 +152,7 @@ func TestProposeAttestation(t *testing.T) {
|
||||
CommitteeBits: cb,
|
||||
}
|
||||
_, err = attesterServer.ProposeAttestationElectra(context.Background(), req)
|
||||
assert.ErrorContains(t, "Committee bits has more than one bit set", err)
|
||||
assert.ErrorContains(t, "exactly 1 committee index must be set but 2 were set", err)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -242,6 +242,15 @@ func (vs *Server) getPayloadHeaderFromBuilder(ctx context.Context, slot primitiv
|
||||
return nil, fmt.Errorf("incorrect parent hash %#x != %#x", header.ParentHash(), h.BlockHash())
|
||||
}
|
||||
|
||||
reg, err := vs.BlockBuilder.RegistrationByValidatorID(ctx, idx)
|
||||
if err != nil {
|
||||
log.WithError(err).Warn("Proposer: failed to get registration by validator ID, could not check gas limit")
|
||||
} else {
|
||||
if reg.GasLimit != header.GasLimit() {
|
||||
return nil, fmt.Errorf("incorrect header gas limit %d != %d", reg.GasLimit, header.GasLimit())
|
||||
}
|
||||
}
|
||||
|
||||
t, err := slots.ToTime(uint64(vs.TimeFetcher.GenesisTime().Unix()), slot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -720,6 +720,29 @@ func TestServer_getPayloadHeader(t *testing.T) {
|
||||
Signature: sk.Sign(srCapella[:]).Marshal(),
|
||||
}
|
||||
|
||||
incorrectGasLimitBid := ðpb.BuilderBid{
|
||||
Header: &v1.ExecutionPayloadHeader{
|
||||
FeeRecipient: make([]byte, fieldparams.FeeRecipientLength),
|
||||
StateRoot: make([]byte, fieldparams.RootLength),
|
||||
ReceiptsRoot: make([]byte, fieldparams.RootLength),
|
||||
LogsBloom: make([]byte, fieldparams.LogsBloomLength),
|
||||
PrevRandao: make([]byte, fieldparams.RootLength),
|
||||
BaseFeePerGas: make([]byte, fieldparams.RootLength),
|
||||
BlockHash: make([]byte, fieldparams.RootLength),
|
||||
TransactionsRoot: bytesutil.PadTo([]byte{1}, fieldparams.RootLength),
|
||||
ParentHash: params.BeaconConfig().ZeroHash[:],
|
||||
Timestamp: uint64(tiCapella.Unix()),
|
||||
GasLimit: 100,
|
||||
},
|
||||
Pubkey: sk.PublicKey().Marshal(),
|
||||
Value: bytesutil.PadTo([]byte{1, 2, 3}, 32),
|
||||
}
|
||||
signedIncorrectGasLimitBid :=
|
||||
ðpb.SignedBuilderBid{
|
||||
Message: incorrectGasLimitBid,
|
||||
Signature: sk.Sign(srCapella[:]).Marshal(),
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -832,6 +855,21 @@ func TestServer_getPayloadHeader(t *testing.T) {
|
||||
},
|
||||
err: "is different from head block version",
|
||||
},
|
||||
{
|
||||
name: "incorrect gas limit",
|
||||
mock: &builderTest.MockBuilderService{
|
||||
Bid: signedIncorrectGasLimitBid,
|
||||
},
|
||||
fetcher: &blockchainTest.ChainService{
|
||||
Block: func() interfaces.ReadOnlySignedBeaconBlock {
|
||||
wb, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlockBellatrix())
|
||||
require.NoError(t, err)
|
||||
wb.SetSlot(primitives.Slot(params.BeaconConfig().BellatrixForkEpoch) * params.BeaconConfig().SlotsPerEpoch)
|
||||
return wb
|
||||
}(),
|
||||
},
|
||||
err: "incorrect header gas limit 0 != 100",
|
||||
},
|
||||
{
|
||||
name: "different bid version during hard fork",
|
||||
mock: &builderTest.MockBuilderService{
|
||||
@@ -850,9 +888,18 @@ func TestServer_getPayloadHeader(t *testing.T) {
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
vs := &Server{BlockBuilder: tc.mock, HeadFetcher: tc.fetcher, TimeFetcher: &blockchainTest.ChainService{
|
||||
vs := &Server{BeaconDB: dbTest.SetupDB(t), BlockBuilder: tc.mock, HeadFetcher: tc.fetcher, TimeFetcher: &blockchainTest.ChainService{
|
||||
Genesis: genesis,
|
||||
}}
|
||||
regCache := cache.NewRegistrationCache()
|
||||
regCache.UpdateIndexToRegisteredMap(context.Background(), map[primitives.ValidatorIndex]*ethpb.ValidatorRegistrationV1{
|
||||
0: {
|
||||
GasLimit: 0,
|
||||
FeeRecipient: make([]byte, 20),
|
||||
Pubkey: make([]byte, 48),
|
||||
},
|
||||
})
|
||||
tc.mock.RegistrationCache = regCache
|
||||
hb, err := vs.HeadFetcher.HeadBlock(context.Background())
|
||||
require.NoError(t, err)
|
||||
bid, err := vs.getPayloadHeaderFromBuilder(context.Background(), hb.Block().Slot(), 0)
|
||||
|
||||
@@ -59,14 +59,26 @@ func (vs *Server) getLocalPayload(ctx context.Context, blk interfaces.ReadOnlyBe
|
||||
slot := blk.Slot()
|
||||
vIdx := blk.ProposerIndex()
|
||||
headRoot := blk.ParentRoot()
|
||||
logFields := logrus.Fields{
|
||||
"validatorIndex": vIdx,
|
||||
"slot": slot,
|
||||
"headRoot": fmt.Sprintf("%#x", headRoot),
|
||||
}
|
||||
payloadId, ok := vs.PayloadIDCache.PayloadID(slot, headRoot)
|
||||
|
||||
val, tracked := vs.TrackedValidatorsCache.Validator(vIdx)
|
||||
return vs.getLocalPayloadFromEngine(ctx, st, headRoot, slot, vIdx)
|
||||
}
|
||||
|
||||
// This returns the local execution payload of a slot, proposer ID, and parent root assuming payload Is cached.
|
||||
// If the payload ID is not cached, the function will prepare a new payload through local EL engine and return it by using the head state.
|
||||
func (vs *Server) getLocalPayloadFromEngine(
|
||||
ctx context.Context,
|
||||
st state.BeaconState,
|
||||
parentRoot [32]byte,
|
||||
slot primitives.Slot,
|
||||
proposerId primitives.ValidatorIndex) (*consensusblocks.GetPayloadResponse, error) {
|
||||
logFields := logrus.Fields{
|
||||
"validatorIndex": proposerId,
|
||||
"slot": slot,
|
||||
"headRoot": fmt.Sprintf("%#x", parentRoot),
|
||||
}
|
||||
payloadId, ok := vs.PayloadIDCache.PayloadID(slot, parentRoot)
|
||||
|
||||
val, tracked := vs.TrackedValidatorsCache.Validator(proposerId)
|
||||
if !tracked {
|
||||
logrus.WithFields(logFields).Warn("could not find tracked proposer index")
|
||||
}
|
||||
@@ -135,7 +147,7 @@ func (vs *Server) getLocalPayload(ctx context.Context, blk interfaces.ReadOnlyBe
|
||||
PrevRandao: random,
|
||||
SuggestedFeeRecipient: val.FeeRecipient[:],
|
||||
Withdrawals: withdrawals,
|
||||
ParentBeaconBlockRoot: headRoot[:],
|
||||
ParentBeaconBlockRoot: parentRoot[:],
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -3,8 +3,7 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"beacon_state_mainnet.go",
|
||||
"beacon_state_minimal.go", # keep
|
||||
"beacon_state.go",
|
||||
"doc.go",
|
||||
"error.go",
|
||||
"getters_attestation.go",
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
//go:build minimal
|
||||
|
||||
package state_native
|
||||
|
||||
import (
|
||||
@@ -1,203 +0,0 @@
|
||||
//go:build !minimal
|
||||
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"sync"
|
||||
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state/fieldtrie"
|
||||
customtypes "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native/custom-types"
|
||||
"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"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
// BeaconState defines a struct containing utilities for the Ethereum Beacon Chain state, defining
|
||||
// getters and setters for its respective values and helpful functions such as HashTreeRoot().
|
||||
type BeaconState struct {
|
||||
version int
|
||||
genesisTime uint64
|
||||
genesisValidatorsRoot [32]byte
|
||||
slot primitives.Slot
|
||||
fork *ethpb.Fork
|
||||
latestBlockHeader *ethpb.BeaconBlockHeader
|
||||
blockRoots customtypes.BlockRoots
|
||||
blockRootsMultiValue *MultiValueBlockRoots
|
||||
stateRoots customtypes.StateRoots
|
||||
stateRootsMultiValue *MultiValueStateRoots
|
||||
historicalRoots customtypes.HistoricalRoots
|
||||
historicalSummaries []*ethpb.HistoricalSummary
|
||||
eth1Data *ethpb.Eth1Data
|
||||
eth1DataVotes []*ethpb.Eth1Data
|
||||
eth1DepositIndex uint64
|
||||
validators []*ethpb.Validator
|
||||
validatorsMultiValue *MultiValueValidators
|
||||
balances []uint64
|
||||
balancesMultiValue *MultiValueBalances
|
||||
randaoMixes customtypes.RandaoMixes
|
||||
randaoMixesMultiValue *MultiValueRandaoMixes
|
||||
slashings []uint64
|
||||
previousEpochAttestations []*ethpb.PendingAttestation
|
||||
currentEpochAttestations []*ethpb.PendingAttestation
|
||||
previousEpochParticipation []byte
|
||||
currentEpochParticipation []byte
|
||||
justificationBits bitfield.Bitvector4
|
||||
previousJustifiedCheckpoint *ethpb.Checkpoint
|
||||
currentJustifiedCheckpoint *ethpb.Checkpoint
|
||||
finalizedCheckpoint *ethpb.Checkpoint
|
||||
inactivityScores []uint64
|
||||
inactivityScoresMultiValue *MultiValueInactivityScores
|
||||
currentSyncCommittee *ethpb.SyncCommittee
|
||||
nextSyncCommittee *ethpb.SyncCommittee
|
||||
latestExecutionPayloadHeader *enginev1.ExecutionPayloadHeader
|
||||
latestExecutionPayloadHeaderCapella *enginev1.ExecutionPayloadHeaderCapella
|
||||
latestExecutionPayloadHeaderDeneb *enginev1.ExecutionPayloadHeaderDeneb
|
||||
latestExecutionPayloadHeaderElectra *enginev1.ExecutionPayloadHeaderElectra
|
||||
nextWithdrawalIndex uint64
|
||||
nextWithdrawalValidatorIndex primitives.ValidatorIndex
|
||||
|
||||
// Electra fields
|
||||
depositRequestsStartIndex uint64
|
||||
depositBalanceToConsume primitives.Gwei
|
||||
exitBalanceToConsume primitives.Gwei
|
||||
earliestExitEpoch primitives.Epoch
|
||||
consolidationBalanceToConsume primitives.Gwei
|
||||
earliestConsolidationEpoch primitives.Epoch
|
||||
pendingBalanceDeposits []*ethpb.PendingBalanceDeposit // pending_balance_deposits: List[PendingBalanceDeposit, PENDING_BALANCE_DEPOSITS_LIMIT]
|
||||
pendingPartialWithdrawals []*ethpb.PendingPartialWithdrawal // pending_partial_withdrawals: List[PartialWithdrawal, PENDING_PARTIAL_WITHDRAWALS_LIMIT]
|
||||
pendingConsolidations []*ethpb.PendingConsolidation // pending_consolidations: List[PendingConsolidation, PENDING_CONSOLIDATIONS_LIMIT]
|
||||
|
||||
id uint64
|
||||
lock sync.RWMutex
|
||||
dirtyFields map[types.FieldIndex]bool
|
||||
dirtyIndices map[types.FieldIndex][]uint64
|
||||
stateFieldLeaves map[types.FieldIndex]*fieldtrie.FieldTrie
|
||||
rebuildTrie map[types.FieldIndex]bool
|
||||
valMapHandler *stateutil.ValidatorMapHandler
|
||||
validatorIndexCache *finalizedValidatorIndexCache
|
||||
merkleLayers [][][]byte
|
||||
sharedFieldReferences map[types.FieldIndex]*stateutil.Reference
|
||||
}
|
||||
|
||||
type beaconStateMarshalable struct {
|
||||
Version int `json:"version" yaml:"version"`
|
||||
GenesisTime uint64 `json:"genesis_time" yaml:"genesis_time"`
|
||||
GenesisValidatorsRoot [32]byte `json:"genesis_validators_root" yaml:"genesis_validators_root"`
|
||||
Slot primitives.Slot `json:"slot" yaml:"slot"`
|
||||
Fork *ethpb.Fork `json:"fork" yaml:"fork"`
|
||||
LatestBlockHeader *ethpb.BeaconBlockHeader `json:"latest_block_header" yaml:"latest_block_header"`
|
||||
BlockRoots customtypes.BlockRoots `json:"block_roots" yaml:"block_roots"`
|
||||
StateRoots customtypes.StateRoots `json:"state_roots" yaml:"state_roots"`
|
||||
HistoricalRoots customtypes.HistoricalRoots `json:"historical_roots" yaml:"historical_roots"`
|
||||
HistoricalSummaries []*ethpb.HistoricalSummary `json:"historical_summaries" yaml:"historical_summaries"`
|
||||
Eth1Data *ethpb.Eth1Data `json:"eth_1_data" yaml:"eth_1_data"`
|
||||
Eth1DataVotes []*ethpb.Eth1Data `json:"eth_1_data_votes" yaml:"eth_1_data_votes"`
|
||||
Eth1DepositIndex uint64 `json:"eth_1_deposit_index" yaml:"eth_1_deposit_index"`
|
||||
Validators []*ethpb.Validator `json:"validators" yaml:"validators"`
|
||||
Balances []uint64 `json:"balances" yaml:"balances"`
|
||||
RandaoMixes customtypes.RandaoMixes `json:"randao_mixes" yaml:"randao_mixes"`
|
||||
Slashings []uint64 `json:"slashings" yaml:"slashings"`
|
||||
PreviousEpochAttestations []*ethpb.PendingAttestation `json:"previous_epoch_attestations" yaml:"previous_epoch_attestations"`
|
||||
CurrentEpochAttestations []*ethpb.PendingAttestation `json:"current_epoch_attestations" yaml:"current_epoch_attestations"`
|
||||
PreviousEpochParticipation []byte `json:"previous_epoch_participation" yaml:"previous_epoch_participation"`
|
||||
CurrentEpochParticipation []byte `json:"current_epoch_participation" yaml:"current_epoch_participation"`
|
||||
JustificationBits bitfield.Bitvector4 `json:"justification_bits" yaml:"justification_bits"`
|
||||
PreviousJustifiedCheckpoint *ethpb.Checkpoint `json:"previous_justified_checkpoint" yaml:"previous_justified_checkpoint"`
|
||||
CurrentJustifiedCheckpoint *ethpb.Checkpoint `json:"current_justified_checkpoint" yaml:"current_justified_checkpoint"`
|
||||
FinalizedCheckpoint *ethpb.Checkpoint `json:"finalized_checkpoint" yaml:"finalized_checkpoint"`
|
||||
InactivityScores []uint64 `json:"inactivity_scores" yaml:"inactivity_scores"`
|
||||
CurrentSyncCommittee *ethpb.SyncCommittee `json:"current_sync_committee" yaml:"current_sync_committee"`
|
||||
NextSyncCommittee *ethpb.SyncCommittee `json:"next_sync_committee" yaml:"next_sync_committee"`
|
||||
LatestExecutionPayloadHeader *enginev1.ExecutionPayloadHeader `json:"latest_execution_payload_header" yaml:"latest_execution_payload_header"`
|
||||
LatestExecutionPayloadHeaderCapella *enginev1.ExecutionPayloadHeaderCapella `json:"latest_execution_payload_header_capella" yaml:"latest_execution_payload_header_capella"`
|
||||
LatestExecutionPayloadHeaderDeneb *enginev1.ExecutionPayloadHeaderDeneb `json:"latest_execution_payload_header_deneb" yaml:"latest_execution_payload_header_deneb"`
|
||||
LatestExecutionPayloadHeaderElectra *enginev1.ExecutionPayloadHeaderElectra `json:"latest_execution_payload_header_electra" yaml:"latest_execution_payload_header_electra"`
|
||||
NextWithdrawalIndex uint64 `json:"next_withdrawal_index" yaml:"next_withdrawal_index"`
|
||||
NextWithdrawalValidatorIndex primitives.ValidatorIndex `json:"next_withdrawal_validator_index" yaml:"next_withdrawal_validator_index"`
|
||||
DepositRequestsStartIndex uint64 `json:"deposit_requests_start_index" yaml:"deposit_requests_start_index"`
|
||||
DepositBalanceToConsume primitives.Gwei `json:"deposit_balance_to_consume" yaml:"deposit_balance_to_consume"`
|
||||
ExitBalanceToConsume primitives.Gwei `json:"exit_balance_to_consume" yaml:"exit_balance_to_consume"`
|
||||
EarliestExitEpoch primitives.Epoch `json:"earliest_exit_epoch" yaml:"earliest_exit_epoch"`
|
||||
ConsolidationBalanceToConsume primitives.Gwei `json:"consolidation_balance_to_consume" yaml:"consolidation_balance_to_consume"`
|
||||
EarliestConsolidationEpoch primitives.Epoch `json:"earliest_consolidation_epoch" yaml:"earliest_consolidation_epoch"`
|
||||
PendingBalanceDeposits []*ethpb.PendingBalanceDeposit `json:"pending_balance_deposits" yaml:"pending_balance_deposits"`
|
||||
PendingPartialWithdrawals []*ethpb.PendingPartialWithdrawal `json:"pending_partial_withdrawals" yaml:"pending_partial_withdrawals"`
|
||||
PendingConsolidations []*ethpb.PendingConsolidation `json:"pending_consolidations" yaml:"pending_consolidations"`
|
||||
}
|
||||
|
||||
func (b *BeaconState) MarshalJSON() ([]byte, error) {
|
||||
var bRoots customtypes.BlockRoots
|
||||
var sRoots customtypes.StateRoots
|
||||
var mixes customtypes.RandaoMixes
|
||||
var balances []uint64
|
||||
var inactivityScores []uint64
|
||||
var vals []*ethpb.Validator
|
||||
|
||||
if features.Get().EnableExperimentalState {
|
||||
bRoots = b.blockRootsMultiValue.Value(b)
|
||||
sRoots = b.stateRootsMultiValue.Value(b)
|
||||
mixes = b.randaoMixesMultiValue.Value(b)
|
||||
balances = b.balancesMultiValue.Value(b)
|
||||
inactivityScores = b.inactivityScoresMultiValue.Value(b)
|
||||
vals = b.validatorsMultiValue.Value(b)
|
||||
} else {
|
||||
bRoots = b.blockRoots
|
||||
sRoots = b.stateRoots
|
||||
mixes = b.randaoMixes
|
||||
balances = b.balances
|
||||
inactivityScores = b.inactivityScores
|
||||
vals = b.validators
|
||||
}
|
||||
|
||||
marshalable := &beaconStateMarshalable{
|
||||
Version: b.version,
|
||||
GenesisTime: b.genesisTime,
|
||||
GenesisValidatorsRoot: b.genesisValidatorsRoot,
|
||||
Slot: b.slot,
|
||||
Fork: b.fork,
|
||||
LatestBlockHeader: b.latestBlockHeader,
|
||||
BlockRoots: bRoots,
|
||||
StateRoots: sRoots,
|
||||
HistoricalRoots: b.historicalRoots,
|
||||
HistoricalSummaries: b.historicalSummaries,
|
||||
Eth1Data: b.eth1Data,
|
||||
Eth1DataVotes: b.eth1DataVotes,
|
||||
Eth1DepositIndex: b.eth1DepositIndex,
|
||||
Validators: vals,
|
||||
Balances: balances,
|
||||
RandaoMixes: mixes,
|
||||
Slashings: b.slashings,
|
||||
PreviousEpochAttestations: b.previousEpochAttestations,
|
||||
CurrentEpochAttestations: b.currentEpochAttestations,
|
||||
PreviousEpochParticipation: b.previousEpochParticipation,
|
||||
CurrentEpochParticipation: b.currentEpochParticipation,
|
||||
JustificationBits: b.justificationBits,
|
||||
PreviousJustifiedCheckpoint: b.previousJustifiedCheckpoint,
|
||||
CurrentJustifiedCheckpoint: b.currentJustifiedCheckpoint,
|
||||
FinalizedCheckpoint: b.finalizedCheckpoint,
|
||||
InactivityScores: inactivityScores,
|
||||
CurrentSyncCommittee: b.currentSyncCommittee,
|
||||
NextSyncCommittee: b.nextSyncCommittee,
|
||||
LatestExecutionPayloadHeader: b.latestExecutionPayloadHeader,
|
||||
LatestExecutionPayloadHeaderCapella: b.latestExecutionPayloadHeaderCapella,
|
||||
LatestExecutionPayloadHeaderDeneb: b.latestExecutionPayloadHeaderDeneb,
|
||||
LatestExecutionPayloadHeaderElectra: b.latestExecutionPayloadHeaderElectra,
|
||||
NextWithdrawalIndex: b.nextWithdrawalIndex,
|
||||
NextWithdrawalValidatorIndex: b.nextWithdrawalValidatorIndex,
|
||||
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,
|
||||
}
|
||||
return json.Marshal(marshalable)
|
||||
}
|
||||
@@ -30,8 +30,8 @@ func newFinalizedValidatorIndexCache() *finalizedValidatorIndexCache {
|
||||
// If the public key is not found in the cache, it searches through the state starting from the last finalized index.
|
||||
func (b *BeaconState) getValidatorIndex(pubKey [fieldparams.BLSPubkeyLength]byte) (primitives.ValidatorIndex, bool) {
|
||||
b.validatorIndexCache.RLock()
|
||||
defer b.validatorIndexCache.RUnlock()
|
||||
index, found := b.validatorIndexCache.indexMap[pubKey]
|
||||
b.validatorIndexCache.RUnlock()
|
||||
if found {
|
||||
return index, true
|
||||
}
|
||||
|
||||
@@ -25,7 +25,11 @@ func (s *Service) committeeIndexBeaconAttestationSubscriber(_ context.Context, m
|
||||
if data == nil {
|
||||
return errors.New("nil attestation")
|
||||
}
|
||||
s.setSeenCommitteeIndicesSlot(data.Slot, data.CommitteeIndex, a.GetAggregationBits())
|
||||
committeeIndex, err := a.GetCommitteeIndex()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "committeeIndexBeaconAttestationSubscriber failed to get committee index")
|
||||
}
|
||||
s.setSeenCommitteeIndicesSlot(data.Slot, committeeIndex, a.GetAggregationBits())
|
||||
|
||||
exists, err := s.cfg.attPool.HasAggregatedAttestation(a)
|
||||
if err != nil {
|
||||
|
||||
@@ -167,39 +167,32 @@ func (s *Service) validateAggregatedAtt(ctx context.Context, signed ethpb.Signed
|
||||
return pubsub.ValidationIgnore, err
|
||||
}
|
||||
|
||||
committeeIndex, _, result, err := s.validateCommitteeIndexAndCount(ctx, aggregate, bs)
|
||||
if result != pubsub.ValidationAccept {
|
||||
wrappedErr := errors.Wrapf(err, "could not validate committee index")
|
||||
tracing.AnnotateError(span, wrappedErr)
|
||||
return result, err
|
||||
}
|
||||
|
||||
committee, result, err := s.validateBitLength(ctx, bs, aggregate.GetData().Slot, committeeIndex, aggregate.GetAggregationBits())
|
||||
if result != pubsub.ValidationAccept {
|
||||
return result, err
|
||||
}
|
||||
|
||||
// Verify validator index is within the beacon committee.
|
||||
result, err := s.validateIndexInCommittee(ctx, bs, aggregate, aggregatorIndex)
|
||||
result, err = s.validateIndexInCommittee(ctx, aggregate, aggregatorIndex, committee)
|
||||
if result != pubsub.ValidationAccept {
|
||||
wrappedErr := errors.Wrapf(err, "could not validate index in committee")
|
||||
tracing.AnnotateError(span, wrappedErr)
|
||||
return result, wrappedErr
|
||||
}
|
||||
|
||||
var committeeIndex primitives.CommitteeIndex
|
||||
if signed.Version() >= version.Electra {
|
||||
a, ok := aggregate.(*ethpb.AttestationElectra)
|
||||
// This will never fail in practice because we asserted the version
|
||||
if !ok {
|
||||
err := fmt.Errorf("aggregate attestation has wrong type (expected %T, got %T)", ðpb.AttestationElectra{}, aggregate)
|
||||
tracing.AnnotateError(span, err)
|
||||
return pubsub.ValidationIgnore, err
|
||||
}
|
||||
committeeIndex, result, err = validateCommitteeIndexElectra(ctx, a)
|
||||
if result != pubsub.ValidationAccept {
|
||||
wrappedErr := errors.Wrapf(err, "could not validate committee index for Electra version")
|
||||
tracing.AnnotateError(span, wrappedErr)
|
||||
return result, wrappedErr
|
||||
}
|
||||
} else {
|
||||
committeeIndex = data.CommitteeIndex
|
||||
}
|
||||
|
||||
// Verify selection proof reflects to the right validator.
|
||||
selectionSigSet, err := validateSelectionIndex(
|
||||
ctx,
|
||||
bs,
|
||||
data.Slot,
|
||||
committeeIndex,
|
||||
committee,
|
||||
aggregatorIndex,
|
||||
aggregateAndProof.GetSelectionProof(),
|
||||
)
|
||||
@@ -266,20 +259,10 @@ func (s *Service) setAggregatorIndexEpochSeen(epoch primitives.Epoch, aggregator
|
||||
// - [REJECT] The aggregate attestation has participants -- that is, len(get_attesting_indices(state, aggregate.data, aggregate.aggregation_bits)) >= 1.
|
||||
// - [REJECT] The aggregator's validator index is within the committee --
|
||||
// i.e. `aggregate_and_proof.aggregator_index in get_beacon_committee(state, aggregate.data.slot, aggregate.data.index)`.
|
||||
func (s *Service) validateIndexInCommittee(ctx context.Context, bs state.ReadOnlyBeaconState, a ethpb.Att, validatorIndex primitives.ValidatorIndex) (pubsub.ValidationResult, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "sync.validateIndexInCommittee")
|
||||
func (s *Service) validateIndexInCommittee(ctx context.Context, a ethpb.Att, validatorIndex primitives.ValidatorIndex, committee []primitives.ValidatorIndex) (pubsub.ValidationResult, error) {
|
||||
_, span := trace.StartSpan(ctx, "sync.validateIndexInCommittee")
|
||||
defer span.End()
|
||||
|
||||
_, result, err := s.validateCommitteeIndex(ctx, a, bs)
|
||||
if result != pubsub.ValidationAccept {
|
||||
return result, err
|
||||
}
|
||||
|
||||
committee, result, err := s.validateBitLength(ctx, bs, a.GetData().Slot, a.GetData().CommitteeIndex, a.GetAggregationBits())
|
||||
if result != pubsub.ValidationAccept {
|
||||
return result, err
|
||||
}
|
||||
|
||||
if a.GetAggregationBits().Count() == 0 {
|
||||
return pubsub.ValidationReject, errors.New("no attesting indices")
|
||||
}
|
||||
@@ -304,17 +287,13 @@ func validateSelectionIndex(
|
||||
ctx context.Context,
|
||||
bs state.ReadOnlyBeaconState,
|
||||
slot primitives.Slot,
|
||||
committeeIndex primitives.CommitteeIndex,
|
||||
committee []primitives.ValidatorIndex,
|
||||
validatorIndex primitives.ValidatorIndex,
|
||||
proof []byte,
|
||||
) (*bls.SignatureBatch, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "sync.validateSelectionIndex")
|
||||
_, span := trace.StartSpan(ctx, "sync.validateSelectionIndex")
|
||||
defer span.End()
|
||||
|
||||
committee, err := helpers.BeaconCommitteeFromState(ctx, bs, slot, committeeIndex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aggregator, err := helpers.IsAggregator(uint64(len(committee)), proof)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -44,20 +44,19 @@ func TestVerifyIndexInCommittee_CanVerify(t *testing.T) {
|
||||
|
||||
bf := bitfield.NewBitlist(validators / uint64(params.BeaconConfig().SlotsPerEpoch))
|
||||
bf.SetBitAt(0, true)
|
||||
att := ðpb.Attestation{Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{Epoch: 0}},
|
||||
AggregationBits: bf}
|
||||
att := ðpb.Attestation{Data: ðpb.AttestationData{}, AggregationBits: bf}
|
||||
|
||||
committee, err := helpers.BeaconCommitteeFromState(context.Background(), s, att.Data.Slot, att.Data.CommitteeIndex)
|
||||
assert.NoError(t, err)
|
||||
indices, err := attestation.AttestingIndices(att, committee)
|
||||
require.NoError(t, err)
|
||||
result, err := service.validateIndexInCommittee(ctx, s, att, primitives.ValidatorIndex(indices[0]))
|
||||
|
||||
result, err := service.validateIndexInCommittee(ctx, att, primitives.ValidatorIndex(indices[0]), committee)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, pubsub.ValidationAccept, result)
|
||||
|
||||
wanted := "validator index 1000 is not within the committee"
|
||||
result, err = service.validateIndexInCommittee(ctx, s, att, 1000)
|
||||
result, err = service.validateIndexInCommittee(ctx, att, 1000, committee)
|
||||
assert.ErrorContains(t, wanted, err)
|
||||
assert.Equal(t, pubsub.ValidationReject, result)
|
||||
}
|
||||
@@ -71,8 +70,7 @@ func TestVerifyIndexInCommittee_ExistsInBeaconCommittee(t *testing.T) {
|
||||
s, _ := util.DeterministicGenesisState(t, validators)
|
||||
require.NoError(t, s.SetSlot(params.BeaconConfig().SlotsPerEpoch))
|
||||
|
||||
att := ðpb.Attestation{Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{Epoch: 0}}}
|
||||
att := ðpb.Attestation{Data: ðpb.AttestationData{}}
|
||||
|
||||
committee, err := helpers.BeaconCommitteeFromState(context.Background(), s, att.Data.Slot, att.Data.CommitteeIndex)
|
||||
require.NoError(t, err)
|
||||
@@ -81,32 +79,52 @@ func TestVerifyIndexInCommittee_ExistsInBeaconCommittee(t *testing.T) {
|
||||
att.AggregationBits = bl
|
||||
|
||||
service := &Service{}
|
||||
result, err := service.validateIndexInCommittee(ctx, s, att, committee[0])
|
||||
result, err := service.validateIndexInCommittee(ctx, att, committee[0], committee)
|
||||
require.ErrorContains(t, "no attesting indices", err)
|
||||
assert.Equal(t, pubsub.ValidationReject, result)
|
||||
|
||||
att.AggregationBits.SetBitAt(0, true)
|
||||
|
||||
result, err = service.validateIndexInCommittee(ctx, s, att, committee[0])
|
||||
result, err = service.validateIndexInCommittee(ctx, att, committee[0], committee)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, pubsub.ValidationAccept, result)
|
||||
|
||||
wanted := "validator index 1000 is not within the committee"
|
||||
result, err = service.validateIndexInCommittee(ctx, s, att, 1000)
|
||||
result, err = service.validateIndexInCommittee(ctx, att, 1000, committee)
|
||||
assert.ErrorContains(t, wanted, err)
|
||||
assert.Equal(t, pubsub.ValidationReject, result)
|
||||
|
||||
att.AggregationBits = bitfield.NewBitlist(1)
|
||||
result, err = service.validateIndexInCommittee(ctx, s, att, committee[0])
|
||||
committeeIndex, err := att.GetCommitteeIndex()
|
||||
require.NoError(t, err)
|
||||
_, result, err = service.validateBitLength(ctx, s, att.Data.Slot, committeeIndex, att.AggregationBits)
|
||||
require.ErrorContains(t, "wanted participants bitfield length 4, got: 1", err)
|
||||
assert.Equal(t, pubsub.ValidationReject, result)
|
||||
|
||||
att.Data.CommitteeIndex = 10000
|
||||
result, err = service.validateIndexInCommittee(ctx, s, att, committee[0])
|
||||
_, _, result, err = service.validateCommitteeIndexAndCount(ctx, att, s)
|
||||
require.ErrorContains(t, "committee index 10000 > 2", err)
|
||||
assert.Equal(t, pubsub.ValidationReject, result)
|
||||
}
|
||||
|
||||
func TestVerifyIndexInCommittee_Electra(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
s, _ := util.DeterministicGenesisStateElectra(t, 64)
|
||||
service := &Service{}
|
||||
cb := primitives.NewAttestationCommitteeBits()
|
||||
cb.SetBitAt(0, true)
|
||||
att := ðpb.AttestationElectra{Data: ðpb.AttestationData{}, CommitteeBits: cb}
|
||||
committee, err := helpers.BeaconCommitteeFromState(context.Background(), s, att.Data.Slot, att.Data.CommitteeIndex)
|
||||
require.NoError(t, err)
|
||||
bl := bitfield.NewBitlist(uint64(len(committee)))
|
||||
bl.SetBitAt(0, true)
|
||||
att.AggregationBits = bl
|
||||
|
||||
result, err := service.validateIndexInCommittee(ctx, att, committee[0], committee)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, pubsub.ValidationAccept, result)
|
||||
}
|
||||
|
||||
func TestVerifySelection_NotAnAggregator(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
params.SetupTestConfigCleanup(t)
|
||||
@@ -116,8 +134,9 @@ func TestVerifySelection_NotAnAggregator(t *testing.T) {
|
||||
|
||||
sig := privKeys[0].Sign([]byte{'A'})
|
||||
data := util.HydrateAttestationData(ðpb.AttestationData{})
|
||||
|
||||
_, err := validateSelectionIndex(ctx, beaconState, data.Slot, data.CommitteeIndex, 0, sig.Marshal())
|
||||
committee, err := helpers.BeaconCommitteeFromState(ctx, beaconState, data.Slot, data.CommitteeIndex)
|
||||
require.NoError(t, err)
|
||||
_, err = validateSelectionIndex(ctx, beaconState, data.Slot, committee, 0, sig.Marshal())
|
||||
wanted := "validator is not an aggregator for slot"
|
||||
assert.ErrorContains(t, wanted, err)
|
||||
}
|
||||
|
||||
@@ -94,28 +94,16 @@ func (s *Service) validateCommitteeIndexBeaconAttestation(ctx context.Context, p
|
||||
|
||||
var validationRes pubsub.ValidationResult
|
||||
|
||||
var committeeIndex primitives.CommitteeIndex
|
||||
if att.Version() >= version.Electra {
|
||||
a, ok := att.(*eth.AttestationElectra)
|
||||
// This will never fail in practice because we asserted the version
|
||||
if !ok {
|
||||
err := fmt.Errorf("attestation has wrong type (expected %T, got %T)", ð.AttestationElectra{}, att)
|
||||
tracing.AnnotateError(span, err)
|
||||
return pubsub.ValidationIgnore, err
|
||||
}
|
||||
committeeIndex, validationRes, err = validateCommitteeIndexElectra(ctx, a)
|
||||
if validationRes != pubsub.ValidationAccept {
|
||||
wrappedErr := errors.Wrapf(err, "could not validate committee index for Electra version")
|
||||
tracing.AnnotateError(span, wrappedErr)
|
||||
return validationRes, wrappedErr
|
||||
}
|
||||
} else {
|
||||
committeeIndex = data.CommitteeIndex
|
||||
committeeIndex, result, err := s.validateCommitteeIndex(ctx, att)
|
||||
if result != pubsub.ValidationAccept {
|
||||
wrappedErr := errors.Wrapf(err, "could not validate committee index for %s version", version.String(att.Version()))
|
||||
tracing.AnnotateError(span, wrappedErr)
|
||||
return result, wrappedErr
|
||||
}
|
||||
|
||||
if !features.Get().EnableSlasher {
|
||||
// Verify this the first attestation received for the participating validator for the slot.
|
||||
if s.hasSeenCommitteeIndicesSlot(data.Slot, data.CommitteeIndex, att.GetAggregationBits()) {
|
||||
if s.hasSeenCommitteeIndicesSlot(data.Slot, committeeIndex, att.GetAggregationBits()) {
|
||||
return pubsub.ValidationIgnore, nil
|
||||
}
|
||||
|
||||
@@ -205,7 +193,7 @@ func (s *Service) validateCommitteeIndexBeaconAttestation(ctx context.Context, p
|
||||
}()
|
||||
}
|
||||
|
||||
s.setSeenCommitteeIndicesSlot(data.Slot, data.CommitteeIndex, att.GetAggregationBits())
|
||||
s.setSeenCommitteeIndicesSlot(data.Slot, committeeIndex, att.GetAggregationBits())
|
||||
|
||||
msg.ValidatorData = att
|
||||
|
||||
@@ -217,7 +205,7 @@ func (s *Service) validateUnaggregatedAttTopic(ctx context.Context, a eth.Att, b
|
||||
ctx, span := trace.StartSpan(ctx, "sync.validateUnaggregatedAttTopic")
|
||||
defer span.End()
|
||||
|
||||
valCount, result, err := s.validateCommitteeIndex(ctx, a, bs)
|
||||
_, valCount, result, err := s.validateCommitteeIndexAndCount(ctx, a, bs)
|
||||
if result != pubsub.ValidationAccept {
|
||||
return result, err
|
||||
}
|
||||
@@ -235,16 +223,31 @@ func (s *Service) validateUnaggregatedAttTopic(ctx context.Context, a eth.Att, b
|
||||
return pubsub.ValidationAccept, nil
|
||||
}
|
||||
|
||||
func (s *Service) validateCommitteeIndex(ctx context.Context, a eth.Att, bs state.ReadOnlyBeaconState) (uint64, pubsub.ValidationResult, error) {
|
||||
func (s *Service) validateCommitteeIndexAndCount(
|
||||
ctx context.Context,
|
||||
a eth.Att,
|
||||
bs state.ReadOnlyBeaconState,
|
||||
) (primitives.CommitteeIndex, uint64, pubsub.ValidationResult, error) {
|
||||
ci, result, err := s.validateCommitteeIndex(ctx, a)
|
||||
if result != pubsub.ValidationAccept {
|
||||
return 0, 0, result, err
|
||||
}
|
||||
valCount, err := helpers.ActiveValidatorCount(ctx, bs, slots.ToEpoch(a.GetData().Slot))
|
||||
if err != nil {
|
||||
return 0, pubsub.ValidationIgnore, err
|
||||
return 0, 0, pubsub.ValidationIgnore, err
|
||||
}
|
||||
count := helpers.SlotCommitteeCount(valCount)
|
||||
if uint64(a.GetData().CommitteeIndex) > count {
|
||||
return 0, pubsub.ValidationReject, errors.Errorf("committee index %d > %d", a.GetData().CommitteeIndex, count)
|
||||
if uint64(ci) > count {
|
||||
return 0, 0, pubsub.ValidationReject, fmt.Errorf("committee index %d > %d", a.GetData().CommitteeIndex, count)
|
||||
}
|
||||
return valCount, pubsub.ValidationAccept, nil
|
||||
return ci, valCount, pubsub.ValidationAccept, nil
|
||||
}
|
||||
|
||||
func (s *Service) validateCommitteeIndex(ctx context.Context, a eth.Att) (primitives.CommitteeIndex, pubsub.ValidationResult, error) {
|
||||
if a.Version() >= version.Electra {
|
||||
return validateCommitteeIndexElectra(ctx, a)
|
||||
}
|
||||
return a.GetData().CommitteeIndex, pubsub.ValidationAccept, nil
|
||||
}
|
||||
|
||||
// This validates beacon unaggregated attestation using the given state, the validation consists of bitfield length and count consistency
|
||||
@@ -253,7 +256,12 @@ func (s *Service) validateUnaggregatedAttWithState(ctx context.Context, a eth.At
|
||||
ctx, span := trace.StartSpan(ctx, "sync.validateUnaggregatedAttWithState")
|
||||
defer span.End()
|
||||
|
||||
committee, result, err := s.validateBitLength(ctx, bs, a.GetData().Slot, a.GetData().CommitteeIndex, a.GetAggregationBits())
|
||||
committeeIndex, err := a.GetCommitteeIndex()
|
||||
if err != nil {
|
||||
return pubsub.ValidationIgnore, err
|
||||
}
|
||||
|
||||
committee, result, err := s.validateBitLength(ctx, bs, a.GetData().Slot, committeeIndex, a.GetAggregationBits())
|
||||
if result != pubsub.ValidationAccept {
|
||||
return result, err
|
||||
}
|
||||
|
||||
@@ -5,23 +5,24 @@ import (
|
||||
"fmt"
|
||||
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
func validateCommitteeIndexElectra(ctx context.Context, a *ethpb.AttestationElectra) (primitives.CommitteeIndex, pubsub.ValidationResult, error) {
|
||||
// validateCommitteeIndexElectra implements the following checks from the spec:
|
||||
// - [REJECT] len(committee_indices) == 1, where committee_indices = get_committee_indices(attestation).
|
||||
// - [REJECT] attestation.data.index == 0
|
||||
func validateCommitteeIndexElectra(ctx context.Context, a ethpb.Att) (primitives.CommitteeIndex, pubsub.ValidationResult, error) {
|
||||
_, span := trace.StartSpan(ctx, "sync.validateCommitteeIndexElectra")
|
||||
defer span.End()
|
||||
|
||||
ci := a.Data.CommitteeIndex
|
||||
if ci != 0 {
|
||||
return 0, pubsub.ValidationReject, fmt.Errorf("committee index must be 0 but was %d", ci)
|
||||
_, ok := a.(*ethpb.AttestationElectra)
|
||||
if !ok {
|
||||
return 0, pubsub.ValidationIgnore, fmt.Errorf("attestation has wrong type (expected %T, got %T)", ðpb.AttestationElectra{}, a)
|
||||
}
|
||||
committeeIndices := helpers.CommitteeIndices(a.CommitteeBits)
|
||||
if len(committeeIndices) != 1 {
|
||||
return 0, pubsub.ValidationReject, fmt.Errorf("exactly 1 committee index must be set but %d were set", len(committeeIndices))
|
||||
committeeIndex, err := a.GetCommitteeIndex()
|
||||
if err != nil {
|
||||
return 0, pubsub.ValidationReject, err
|
||||
}
|
||||
return committeeIndices[0], pubsub.ValidationAccept, nil
|
||||
return committeeIndex, pubsub.ValidationAccept, nil
|
||||
}
|
||||
|
||||
@@ -39,4 +39,12 @@ const (
|
||||
MaxDepositRequestsPerPayload = 8192 // Maximum number of deposit requests in an execution payload.
|
||||
MaxWithdrawalRequestsPerPayload = 16 // Maximum number of execution layer withdrawal requests in an execution payload.
|
||||
MaxConsolidationRequestsPerPayload = 1 // Maximum number of consolidation requests in an execution payload.
|
||||
MaxProposerSlashings = 16 // Maximum number of proposer slashings in a block.
|
||||
MaxAttesterSlashings = 2 // Maximum number of attester slashings in a block.
|
||||
MaxAttesterSlashingsElectra = 1 // Maximum number of attester slashings in a block.
|
||||
MaxAttestations = 128 // Maximum number of attestations in a block.
|
||||
MaxAttestationsElectra = 8 // Maximum number of attestations in a block.
|
||||
MaxDeposits = 16 // Maximum number of deposits in a block.
|
||||
MaxVoluntaryExits = 16 // Maximum number of voluntary exits in a block.
|
||||
MaxBlsToExecutionChanges = 16 // Maximum number of bls to execution changes in a block.
|
||||
)
|
||||
|
||||
@@ -39,4 +39,12 @@ const (
|
||||
MaxDepositRequestsPerPayload = 4 // Maximum number of deposit requests in an execution payload.
|
||||
MaxWithdrawalRequestsPerPayload = 2 // Maximum number of execution layer withdrawal requests in an execution payload.
|
||||
MaxConsolidationRequestsPerPayload = 1 // Maximum number of consolidation requests in an execution payload.
|
||||
MaxProposerSlashings = 16 // Maximum number of proposer slashings in a block.
|
||||
MaxAttesterSlashings = 2 // Maximum number of attester slashings in a block.
|
||||
MaxAttesterSlashingsElectra = 1 // Maximum number of attester slashings in a block.
|
||||
MaxAttestations = 128 // Maximum number of attestations in a block.
|
||||
MaxAttestationsElectra = 8 // Maximum number of attestations in a block.
|
||||
MaxDeposits = 16 // Maximum number of deposits in a block.
|
||||
MaxVoluntaryExits = 16 // Maximum number of voluntary exits in a block.
|
||||
MaxBlsToExecutionChanges = 16 // Maximum number of bls to execution changes in a block.
|
||||
)
|
||||
|
||||
@@ -233,8 +233,6 @@ func ConfigToYaml(cfg *BeaconChainConfig) []byte {
|
||||
fmt.Sprintf("MESSAGE_DOMAIN_INVALID_SNAPPY: %#x", cfg.MessageDomainInvalidSnappy),
|
||||
fmt.Sprintf("MESSAGE_DOMAIN_VALID_SNAPPY: %#x", cfg.MessageDomainValidSnappy),
|
||||
fmt.Sprintf("MIN_EPOCHS_FOR_BLOCK_REQUESTS: %d", int(cfg.MinEpochsForBlockRequests)),
|
||||
fmt.Sprintf("ELECTRA_FORK_EPOCH: %d", cfg.ElectraForkEpoch),
|
||||
fmt.Sprintf("ELECTRA_FORK_VERSION: %#x", cfg.ElectraForkVersion),
|
||||
}
|
||||
|
||||
yamlFile := []byte(strings.Join(lines, "\n"))
|
||||
|
||||
@@ -32,6 +32,8 @@ var placeholderFields = []string{
|
||||
"EIP7002_FORK_VERSION",
|
||||
"EIP7594_FORK_EPOCH",
|
||||
"EIP7594_FORK_VERSION",
|
||||
"EIP7732_FORK_EPOCH",
|
||||
"EIP7732_FORK_VERSION",
|
||||
"FIELD_ELEMENTS_PER_BLOB", // Compile time constant.
|
||||
"KZG_COMMITMENT_INCLUSION_PROOF_DEPTH", // Compile time constant on BlobSidecar.commitment_inclusion_proof.
|
||||
"MAX_BLOBS_PER_BLOCK",
|
||||
|
||||
@@ -70,6 +70,7 @@ func MinimalSpecConfig() *BeaconChainConfig {
|
||||
minimalConfig.MaxDeposits = 16
|
||||
minimalConfig.MaxVoluntaryExits = 16
|
||||
minimalConfig.MaxWithdrawalsPerPayload = 4
|
||||
minimalConfig.MaxBlsToExecutionChanges = 16
|
||||
minimalConfig.MaxValidatorsPerWithdrawalsSweep = 16
|
||||
|
||||
// Signature domains
|
||||
|
||||
@@ -8,6 +8,7 @@ go_library(
|
||||
"get_payload.go",
|
||||
"getters.go",
|
||||
"kzg.go",
|
||||
"proofs.go",
|
||||
"proto.go",
|
||||
"roblob.go",
|
||||
"roblock.go",
|
||||
@@ -23,6 +24,7 @@ go_library(
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//container/trie:go_default_library",
|
||||
"//crypto/hash/htr:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//encoding/ssz:go_default_library",
|
||||
"//proto/engine/v1:go_default_library",
|
||||
@@ -32,6 +34,7 @@ go_library(
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prysmaticlabs_fastssz//:go_default_library",
|
||||
"@com_github_prysmaticlabs_gohashtree//:go_default_library",
|
||||
"@io_opencensus_go//trace:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -43,6 +46,7 @@ go_test(
|
||||
"factory_test.go",
|
||||
"getters_test.go",
|
||||
"kzg_test.go",
|
||||
"proofs_test.go",
|
||||
"proto_test.go",
|
||||
"roblob_test.go",
|
||||
"roblock_test.go",
|
||||
|
||||
@@ -503,6 +503,135 @@ func hydrateBeaconBlockBody() *eth.BeaconBlockBody {
|
||||
}
|
||||
}
|
||||
|
||||
func hydrateBeaconBlockBodyAltair() *eth.BeaconBlockBodyAltair {
|
||||
return ð.BeaconBlockBodyAltair{
|
||||
RandaoReveal: make([]byte, fieldparams.BLSSignatureLength),
|
||||
Graffiti: make([]byte, fieldparams.RootLength),
|
||||
Eth1Data: ð.Eth1Data{
|
||||
DepositRoot: make([]byte, fieldparams.RootLength),
|
||||
BlockHash: make([]byte, fieldparams.RootLength),
|
||||
},
|
||||
SyncAggregate: ð.SyncAggregate{
|
||||
SyncCommitteeBits: make([]byte, 64),
|
||||
SyncCommitteeSignature: make([]byte, fieldparams.BLSSignatureLength),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func hydrateBeaconBlockBodyBellatrix() *eth.BeaconBlockBodyBellatrix {
|
||||
return ð.BeaconBlockBodyBellatrix{
|
||||
RandaoReveal: make([]byte, fieldparams.BLSSignatureLength),
|
||||
Graffiti: make([]byte, fieldparams.RootLength),
|
||||
Eth1Data: ð.Eth1Data{
|
||||
DepositRoot: make([]byte, fieldparams.RootLength),
|
||||
BlockHash: make([]byte, fieldparams.RootLength),
|
||||
},
|
||||
SyncAggregate: ð.SyncAggregate{
|
||||
SyncCommitteeBits: make([]byte, 64),
|
||||
SyncCommitteeSignature: make([]byte, fieldparams.BLSSignatureLength),
|
||||
},
|
||||
ExecutionPayload: &pb.ExecutionPayload{
|
||||
ParentHash: make([]byte, fieldparams.RootLength),
|
||||
FeeRecipient: make([]byte, 20),
|
||||
StateRoot: make([]byte, fieldparams.RootLength),
|
||||
ReceiptsRoot: make([]byte, fieldparams.RootLength),
|
||||
LogsBloom: make([]byte, 256),
|
||||
PrevRandao: make([]byte, fieldparams.RootLength),
|
||||
ExtraData: make([]byte, 0),
|
||||
BaseFeePerGas: make([]byte, fieldparams.RootLength),
|
||||
BlockHash: make([]byte, fieldparams.RootLength),
|
||||
Transactions: make([][]byte, 0),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func hydrateBeaconBlockBodyCapella() *eth.BeaconBlockBodyCapella {
|
||||
return ð.BeaconBlockBodyCapella{
|
||||
RandaoReveal: make([]byte, fieldparams.BLSSignatureLength),
|
||||
Graffiti: make([]byte, fieldparams.RootLength),
|
||||
Eth1Data: ð.Eth1Data{
|
||||
DepositRoot: make([]byte, fieldparams.RootLength),
|
||||
BlockHash: make([]byte, fieldparams.RootLength),
|
||||
},
|
||||
SyncAggregate: ð.SyncAggregate{
|
||||
SyncCommitteeBits: make([]byte, fieldparams.SyncAggregateSyncCommitteeBytesLength),
|
||||
SyncCommitteeSignature: make([]byte, fieldparams.BLSSignatureLength),
|
||||
},
|
||||
ExecutionPayload: &pb.ExecutionPayloadCapella{
|
||||
ParentHash: make([]byte, fieldparams.RootLength),
|
||||
FeeRecipient: make([]byte, 20),
|
||||
StateRoot: make([]byte, fieldparams.RootLength),
|
||||
ReceiptsRoot: make([]byte, fieldparams.RootLength),
|
||||
LogsBloom: make([]byte, 256),
|
||||
PrevRandao: make([]byte, fieldparams.RootLength),
|
||||
ExtraData: make([]byte, 0),
|
||||
BaseFeePerGas: make([]byte, fieldparams.RootLength),
|
||||
BlockHash: make([]byte, fieldparams.RootLength),
|
||||
Transactions: make([][]byte, 0),
|
||||
Withdrawals: make([]*pb.Withdrawal, 0),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func hydrateBeaconBlockBodyDeneb() *eth.BeaconBlockBodyDeneb {
|
||||
return ð.BeaconBlockBodyDeneb{
|
||||
RandaoReveal: make([]byte, fieldparams.BLSSignatureLength),
|
||||
Graffiti: make([]byte, fieldparams.RootLength),
|
||||
Eth1Data: ð.Eth1Data{
|
||||
DepositRoot: make([]byte, fieldparams.RootLength),
|
||||
BlockHash: make([]byte, fieldparams.RootLength),
|
||||
},
|
||||
SyncAggregate: ð.SyncAggregate{
|
||||
SyncCommitteeBits: make([]byte, fieldparams.SyncAggregateSyncCommitteeBytesLength),
|
||||
SyncCommitteeSignature: make([]byte, fieldparams.BLSSignatureLength),
|
||||
},
|
||||
ExecutionPayload: &pb.ExecutionPayloadDeneb{
|
||||
ParentHash: make([]byte, fieldparams.RootLength),
|
||||
FeeRecipient: make([]byte, 20),
|
||||
StateRoot: make([]byte, fieldparams.RootLength),
|
||||
ReceiptsRoot: make([]byte, fieldparams.RootLength),
|
||||
LogsBloom: make([]byte, 256),
|
||||
PrevRandao: make([]byte, fieldparams.RootLength),
|
||||
ExtraData: make([]byte, 0),
|
||||
BaseFeePerGas: make([]byte, fieldparams.RootLength),
|
||||
BlockHash: make([]byte, fieldparams.RootLength),
|
||||
Transactions: make([][]byte, 0),
|
||||
Withdrawals: make([]*pb.Withdrawal, 0),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func hydrateBeaconBlockBodyElectra() *eth.BeaconBlockBodyElectra {
|
||||
return ð.BeaconBlockBodyElectra{
|
||||
RandaoReveal: make([]byte, fieldparams.BLSSignatureLength),
|
||||
Graffiti: make([]byte, fieldparams.RootLength),
|
||||
Eth1Data: ð.Eth1Data{
|
||||
DepositRoot: make([]byte, fieldparams.RootLength),
|
||||
BlockHash: make([]byte, fieldparams.RootLength),
|
||||
},
|
||||
SyncAggregate: ð.SyncAggregate{
|
||||
SyncCommitteeBits: make([]byte, fieldparams.SyncAggregateSyncCommitteeBytesLength),
|
||||
SyncCommitteeSignature: make([]byte, fieldparams.BLSSignatureLength),
|
||||
},
|
||||
ExecutionPayload: &pb.ExecutionPayloadElectra{
|
||||
ParentHash: make([]byte, fieldparams.RootLength),
|
||||
FeeRecipient: make([]byte, 20),
|
||||
StateRoot: make([]byte, fieldparams.RootLength),
|
||||
ReceiptsRoot: make([]byte, fieldparams.RootLength),
|
||||
LogsBloom: make([]byte, 256),
|
||||
PrevRandao: make([]byte, fieldparams.RootLength),
|
||||
ExtraData: make([]byte, 0),
|
||||
BaseFeePerGas: make([]byte, fieldparams.RootLength),
|
||||
BlockHash: make([]byte, fieldparams.RootLength),
|
||||
Transactions: make([][]byte, 0),
|
||||
Withdrawals: make([]*pb.Withdrawal, 0),
|
||||
DepositRequests: make([]*pb.DepositRequest, 0),
|
||||
WithdrawalRequests: make([]*pb.WithdrawalRequest, 0),
|
||||
ConsolidationRequests: make([]*pb.ConsolidationRequest, 0),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestPreElectraFailsInterfaceAssertion(t *testing.T) {
|
||||
var epd interfaces.ExecutionData = &executionPayloadDeneb{}
|
||||
_, ok := epd.(interfaces.ExecutionDataElectra)
|
||||
|
||||
174
consensus-types/blocks/proofs.go
Normal file
174
consensus-types/blocks/proofs.go
Normal file
@@ -0,0 +1,174 @@
|
||||
package blocks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v5/crypto/hash/htr"
|
||||
"github.com/prysmaticlabs/prysm/v5/encoding/ssz"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
func ComputeBlockBodyFieldRoots(ctx context.Context, blockBody *BeaconBlockBody) ([][]byte, error) {
|
||||
_, span := trace.StartSpan(ctx, "blocks.ComputeBlockBodyFieldRoots")
|
||||
defer span.End()
|
||||
|
||||
if blockBody == nil {
|
||||
return nil, errNilBlockBody
|
||||
}
|
||||
|
||||
var fieldRoots [][]byte
|
||||
switch blockBody.version {
|
||||
case version.Phase0:
|
||||
fieldRoots = make([][]byte, 8)
|
||||
case version.Altair:
|
||||
fieldRoots = make([][]byte, 9)
|
||||
case version.Bellatrix:
|
||||
fieldRoots = make([][]byte, 10)
|
||||
case version.Capella:
|
||||
fieldRoots = make([][]byte, 11)
|
||||
case version.Deneb:
|
||||
fieldRoots = make([][]byte, 12)
|
||||
case version.Electra:
|
||||
fieldRoots = make([][]byte, 12)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown block body version %s", version.String(blockBody.version))
|
||||
}
|
||||
|
||||
for i := range fieldRoots {
|
||||
fieldRoots[i] = make([]byte, 32)
|
||||
}
|
||||
|
||||
// Randao Reveal
|
||||
randao := blockBody.RandaoReveal()
|
||||
root, err := ssz.MerkleizeByteSliceSSZ(randao[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
copy(fieldRoots[0], root[:])
|
||||
|
||||
// eth1_data
|
||||
eth1 := blockBody.Eth1Data()
|
||||
root, err = eth1.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
copy(fieldRoots[1], root[:])
|
||||
|
||||
// graffiti
|
||||
root = blockBody.Graffiti()
|
||||
copy(fieldRoots[2], root[:])
|
||||
|
||||
// Proposer slashings
|
||||
ps := blockBody.ProposerSlashings()
|
||||
root, err = ssz.MerkleizeListSSZ(ps, params.BeaconConfig().MaxProposerSlashings)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
copy(fieldRoots[3], root[:])
|
||||
|
||||
// Attester slashings
|
||||
as := blockBody.AttesterSlashings()
|
||||
bodyVersion := blockBody.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
|
||||
}
|
||||
copy(fieldRoots[4], root[:])
|
||||
|
||||
// Attestations
|
||||
att := blockBody.Attestations()
|
||||
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
|
||||
}
|
||||
copy(fieldRoots[5], root[:])
|
||||
|
||||
// Deposits
|
||||
dep := blockBody.Deposits()
|
||||
root, err = ssz.MerkleizeListSSZ(dep, params.BeaconConfig().MaxDeposits)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
copy(fieldRoots[6], root[:])
|
||||
|
||||
// Voluntary Exits
|
||||
ve := blockBody.VoluntaryExits()
|
||||
root, err = ssz.MerkleizeListSSZ(ve, params.BeaconConfig().MaxVoluntaryExits)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
copy(fieldRoots[7], root[:])
|
||||
|
||||
if blockBody.version >= version.Altair {
|
||||
// Sync Aggregate
|
||||
sa, err := blockBody.SyncAggregate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
root, err = sa.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
copy(fieldRoots[8], root[:])
|
||||
}
|
||||
|
||||
if blockBody.version >= version.Bellatrix {
|
||||
// Execution Payload
|
||||
ep, err := blockBody.Execution()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
root, err = ep.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
copy(fieldRoots[9], root[:])
|
||||
}
|
||||
|
||||
if blockBody.version >= version.Capella {
|
||||
// BLS Changes
|
||||
bls, err := blockBody.BLSToExecutionChanges()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
root, err = ssz.MerkleizeListSSZ(bls, params.BeaconConfig().MaxBlsToExecutionChanges)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
copy(fieldRoots[10], root[:])
|
||||
}
|
||||
|
||||
if blockBody.version >= version.Deneb {
|
||||
// KZG commitments
|
||||
roots := make([][32]byte, len(blockBody.blobKzgCommitments))
|
||||
for i, commitment := range blockBody.blobKzgCommitments {
|
||||
chunks, err := ssz.PackByChunk([][]byte{commitment})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
roots[i] = htr.VectorizedSha256(chunks)[0]
|
||||
}
|
||||
commitmentsRoot, err := ssz.BitwiseMerkleize(roots, uint64(len(roots)), 4096)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
length := make([]byte, 32)
|
||||
binary.LittleEndian.PutUint64(length[:8], uint64(len(roots)))
|
||||
root = ssz.MixInLength(commitmentsRoot, length)
|
||||
copy(fieldRoots[11], root[:])
|
||||
}
|
||||
|
||||
return fieldRoots, nil
|
||||
}
|
||||
147
consensus-types/blocks/proofs_test.go
Normal file
147
consensus-types/blocks/proofs_test.go
Normal file
@@ -0,0 +1,147 @@
|
||||
package blocks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/container/trie"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
)
|
||||
|
||||
func TestComputeBlockBodyFieldRoots_Phase0(t *testing.T) {
|
||||
blockBodyPhase0 := hydrateBeaconBlockBody()
|
||||
i, err := NewBeaconBlockBody(blockBodyPhase0)
|
||||
require.NoError(t, err)
|
||||
|
||||
b, ok := i.(*BeaconBlockBody)
|
||||
require.Equal(t, true, ok)
|
||||
|
||||
fieldRoots, err := ComputeBlockBodyFieldRoots(context.Background(), b)
|
||||
require.NoError(t, err)
|
||||
trie, err := trie.GenerateTrieFromItems(fieldRoots, 3)
|
||||
require.NoError(t, err)
|
||||
layers := trie.ToProto().GetLayers()
|
||||
|
||||
hash := layers[len(layers)-1].Layer[0]
|
||||
require.NoError(t, err)
|
||||
|
||||
correctHash, err := b.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
require.DeepEqual(t, correctHash[:], hash)
|
||||
}
|
||||
|
||||
func TestComputeBlockBodyFieldRoots_Altair(t *testing.T) {
|
||||
blockBodyAltair := hydrateBeaconBlockBodyAltair()
|
||||
i, err := NewBeaconBlockBody(blockBodyAltair)
|
||||
require.NoError(t, err)
|
||||
|
||||
b, ok := i.(*BeaconBlockBody)
|
||||
require.Equal(t, true, ok)
|
||||
|
||||
fieldRoots, err := ComputeBlockBodyFieldRoots(context.Background(), b)
|
||||
require.NoError(t, err)
|
||||
trie, err := trie.GenerateTrieFromItems(fieldRoots, 4)
|
||||
require.NoError(t, err)
|
||||
layers := trie.ToProto().GetLayers()
|
||||
|
||||
hash := layers[len(layers)-1].Layer[0]
|
||||
require.NoError(t, err)
|
||||
|
||||
correctHash, err := b.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
require.DeepEqual(t, correctHash[:], hash)
|
||||
}
|
||||
|
||||
func TestComputeBlockBodyFieldRoots_Bellatrix(t *testing.T) {
|
||||
blockBodyBellatrix := hydrateBeaconBlockBodyBellatrix()
|
||||
i, err := NewBeaconBlockBody(blockBodyBellatrix)
|
||||
require.NoError(t, err)
|
||||
|
||||
b, ok := i.(*BeaconBlockBody)
|
||||
require.Equal(t, true, ok)
|
||||
|
||||
fieldRoots, err := ComputeBlockBodyFieldRoots(context.Background(), b)
|
||||
require.NoError(t, err)
|
||||
trie, err := trie.GenerateTrieFromItems(fieldRoots, 4)
|
||||
require.NoError(t, err)
|
||||
layers := trie.ToProto().GetLayers()
|
||||
|
||||
hash := layers[len(layers)-1].Layer[0]
|
||||
require.NoError(t, err)
|
||||
|
||||
correctHash, err := b.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
require.DeepEqual(t, correctHash[:], hash)
|
||||
}
|
||||
|
||||
func TestComputeBlockBodyFieldRoots_Capella(t *testing.T) {
|
||||
blockBodyCapella := hydrateBeaconBlockBodyCapella()
|
||||
i, err := NewBeaconBlockBody(blockBodyCapella)
|
||||
require.NoError(t, err)
|
||||
|
||||
b, ok := i.(*BeaconBlockBody)
|
||||
require.Equal(t, true, ok)
|
||||
|
||||
fieldRoots, err := ComputeBlockBodyFieldRoots(context.Background(), b)
|
||||
require.NoError(t, err)
|
||||
trie, err := trie.GenerateTrieFromItems(fieldRoots, 4)
|
||||
require.NoError(t, err)
|
||||
layers := trie.ToProto().GetLayers()
|
||||
|
||||
hash := layers[len(layers)-1].Layer[0]
|
||||
require.NoError(t, err)
|
||||
|
||||
correctHash, err := b.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
require.DeepEqual(t, correctHash[:], hash)
|
||||
}
|
||||
|
||||
func TestComputeBlockBodyFieldRoots_Deneb(t *testing.T) {
|
||||
blockBodyDeneb := hydrateBeaconBlockBodyDeneb()
|
||||
i, err := NewBeaconBlockBody(blockBodyDeneb)
|
||||
require.NoError(t, err)
|
||||
|
||||
b, ok := i.(*BeaconBlockBody)
|
||||
require.Equal(t, true, ok)
|
||||
|
||||
fieldRoots, err := ComputeBlockBodyFieldRoots(context.Background(), b)
|
||||
require.NoError(t, err)
|
||||
trie, err := trie.GenerateTrieFromItems(fieldRoots, 4)
|
||||
require.NoError(t, err)
|
||||
layers := trie.ToProto().GetLayers()
|
||||
|
||||
hash := layers[len(layers)-1].Layer[0]
|
||||
require.NoError(t, err)
|
||||
|
||||
correctHash, err := b.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
require.DeepEqual(t, correctHash[:], hash)
|
||||
}
|
||||
|
||||
func TestComputeBlockBodyFieldRoots_Electra(t *testing.T) {
|
||||
blockBodyElectra := hydrateBeaconBlockBodyElectra()
|
||||
i, err := NewBeaconBlockBody(blockBodyElectra)
|
||||
require.NoError(t, err)
|
||||
|
||||
b, ok := i.(*BeaconBlockBody)
|
||||
require.Equal(t, true, ok)
|
||||
|
||||
fieldRoots, err := ComputeBlockBodyFieldRoots(context.Background(), b)
|
||||
require.NoError(t, err)
|
||||
trie, err := trie.GenerateTrieFromItems(fieldRoots, 4)
|
||||
require.NoError(t, err)
|
||||
layers := trie.ToProto().GetLayers()
|
||||
|
||||
hash := layers[len(layers)-1].Layer[0]
|
||||
require.NoError(t, err)
|
||||
|
||||
correctHash, err := b.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
require.DeepEqual(t, correctHash[:], hash)
|
||||
}
|
||||
17
crypto/hash/hashtree/BUILD.bazel
Normal file
17
crypto/hash/hashtree/BUILD.bazel
Normal file
@@ -0,0 +1,17 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["hashtree.go"],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v5/crypto/hash/hashtree",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["@com_github_prysmaticlabs_hashtree//:go_default_library"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
size = "small",
|
||||
srcs = ["hashtree_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = ["//testing/require:go_default_library"],
|
||||
)
|
||||
47
crypto/hash/hashtree/hashtree.go
Normal file
47
crypto/hash/hashtree/hashtree.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package hashtree
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"sync"
|
||||
|
||||
"github.com/prysmaticlabs/hashtree"
|
||||
)
|
||||
|
||||
const minSliceSizeToParallelize = 5000
|
||||
|
||||
func hashParallel(inputList [][32]byte, outputList [][32]byte, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
err := hashtree.Hash(outputList, inputList)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// VectorizedSha256 takes a list of roots and hashes them using CPU
|
||||
// specific vector instructions. Depending on host machine's specific
|
||||
// hardware configuration, using this routine can lead to a significant
|
||||
// performance improvement compared to the default method of hashing
|
||||
// lists.
|
||||
func VectorizedSha256(inputList [][32]byte) [][32]byte {
|
||||
outputList := make([][32]byte, len(inputList)/2)
|
||||
if len(inputList) < minSliceSizeToParallelize {
|
||||
err := hashtree.Hash(outputList, inputList)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return outputList
|
||||
}
|
||||
n := runtime.GOMAXPROCS(0) - 1
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(n)
|
||||
groupSize := len(inputList) / (2 * (n + 1))
|
||||
for j := 0; j < n; j++ {
|
||||
go hashParallel(inputList[j*2*groupSize:(j+1)*2*groupSize], outputList[j*groupSize:], &wg)
|
||||
}
|
||||
err := hashtree.Hash(outputList[n*groupSize:], inputList[n*2*groupSize:])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
wg.Wait()
|
||||
return outputList
|
||||
}
|
||||
27
crypto/hash/hashtree/hashtree_test.go
Normal file
27
crypto/hash/hashtree/hashtree_test.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package hashtree
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
)
|
||||
|
||||
func Test_VectorizedSha256(t *testing.T) {
|
||||
largeSlice := make([][32]byte, 32*minSliceSizeToParallelize)
|
||||
secondLargeSlice := make([][32]byte, 32*minSliceSizeToParallelize)
|
||||
hash1 := make([][32]byte, 16*minSliceSizeToParallelize)
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
tempHash := VectorizedSha256(largeSlice)
|
||||
copy(hash1, tempHash)
|
||||
}()
|
||||
wg.Wait()
|
||||
hash2 := VectorizedSha256(secondLargeSlice)
|
||||
require.Equal(t, len(hash1), len(hash2))
|
||||
for i, r := range hash1 {
|
||||
require.Equal(t, r, hash2[i])
|
||||
}
|
||||
}
|
||||
@@ -332,6 +332,7 @@ go_library(
|
||||
"//proto/engine/v1:go_default_library",
|
||||
"//proto/eth/ext:go_default_library",
|
||||
"//runtime/version:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_golang_protobuf//proto:go_default_library",
|
||||
"@com_github_grpc_ecosystem_grpc_gateway_v2//protoc-gen-openapiv2/options:options_go_proto",
|
||||
"@com_github_grpc_ecosystem_grpc_gateway_v2//runtime:go_default_library",
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package eth
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
ssz "github.com/prysmaticlabs/fastssz"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
@@ -21,6 +24,7 @@ type Att interface {
|
||||
GetData() *AttestationData
|
||||
CommitteeBitsVal() bitfield.Bitfield
|
||||
GetSignature() []byte
|
||||
GetCommitteeIndex() (primitives.CommitteeIndex, error)
|
||||
}
|
||||
|
||||
// IndexedAtt defines common functionality for all indexed attestation types.
|
||||
@@ -123,6 +127,14 @@ func (a *Attestation) CommitteeBitsVal() bitfield.Bitfield {
|
||||
return cb
|
||||
}
|
||||
|
||||
// GetCommitteeIndex --
|
||||
func (a *Attestation) GetCommitteeIndex() (primitives.CommitteeIndex, error) {
|
||||
if a == nil || a.Data == nil {
|
||||
return 0, errors.New("nil attestation data")
|
||||
}
|
||||
return a.Data.CommitteeIndex, nil
|
||||
}
|
||||
|
||||
// Version --
|
||||
func (a *PendingAttestation) Version() int {
|
||||
return version.Phase0
|
||||
@@ -156,6 +168,14 @@ func (a *PendingAttestation) GetSignature() []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetCommitteeIndex --
|
||||
func (a *PendingAttestation) GetCommitteeIndex() (primitives.CommitteeIndex, error) {
|
||||
if a == nil || a.Data == nil {
|
||||
return 0, errors.New("nil attestation data")
|
||||
}
|
||||
return a.Data.CommitteeIndex, nil
|
||||
}
|
||||
|
||||
// Version --
|
||||
func (a *AttestationElectra) Version() int {
|
||||
return version.Electra
|
||||
@@ -184,6 +204,24 @@ func (a *AttestationElectra) CommitteeBitsVal() bitfield.Bitfield {
|
||||
return a.CommitteeBits
|
||||
}
|
||||
|
||||
// GetCommitteeIndex --
|
||||
func (a *AttestationElectra) GetCommitteeIndex() (primitives.CommitteeIndex, error) {
|
||||
if a == nil || a.Data == nil {
|
||||
return 0, errors.New("nil attestation data")
|
||||
}
|
||||
if len(a.CommitteeBits) == 0 {
|
||||
return 0, errors.New("no committee bits found in attestation")
|
||||
}
|
||||
if a.Data.CommitteeIndex != 0 {
|
||||
return 0, fmt.Errorf("attestation data's committee index must be 0 but was %d", a.Data.CommitteeIndex)
|
||||
}
|
||||
indices := a.CommitteeBits.BitIndices()
|
||||
if len(indices) != 1 {
|
||||
return 0, fmt.Errorf("exactly 1 committee index must be set but %d were set", len(indices))
|
||||
}
|
||||
return primitives.CommitteeIndex(uint64(indices[0])), nil
|
||||
}
|
||||
|
||||
// Version --
|
||||
func (a *IndexedAttestation) Version() int {
|
||||
return version.Phase0
|
||||
|
||||
@@ -8,6 +8,5 @@ import (
|
||||
)
|
||||
|
||||
func RunExecutionPayloadTest(t *testing.T, config string) {
|
||||
t.Skip("TODO: Electra uses a different execution payload")
|
||||
common.RunExecutionPayloadTest(t, config, version.String(version.Electra), sszToBlockBody, sszToState)
|
||||
}
|
||||
|
||||
@@ -2,8 +2,11 @@ package util
|
||||
|
||||
import (
|
||||
"context"
|
||||
rd "crypto/rand"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/signing"
|
||||
@@ -30,27 +33,35 @@ import (
|
||||
// BlockGenConfig is used to define the requested conditions
|
||||
// for block generation.
|
||||
type BlockGenConfig struct {
|
||||
NumProposerSlashings uint64
|
||||
NumAttesterSlashings uint64
|
||||
NumAttestations uint64
|
||||
NumDeposits uint64
|
||||
NumVoluntaryExits uint64
|
||||
NumTransactions uint64 // Only for post Bellatrix blocks
|
||||
FullSyncAggregate bool
|
||||
NumBLSChanges uint64 // Only for post Capella blocks
|
||||
NumProposerSlashings uint64
|
||||
NumAttesterSlashings uint64
|
||||
NumAttestations uint64
|
||||
NumDeposits uint64
|
||||
NumVoluntaryExits uint64
|
||||
NumTransactions uint64 // Only for post Bellatrix blocks
|
||||
FullSyncAggregate bool
|
||||
NumBLSChanges uint64 // Only for post Capella blocks
|
||||
NumWithdrawals uint64
|
||||
NumDepositRequests uint64 // Only for post Electra blocks
|
||||
NumWithdrawalRequests uint64 // Only for post Electra blocks
|
||||
NumConsolidationRequests uint64 // Only for post Electra blocks
|
||||
}
|
||||
|
||||
// DefaultBlockGenConfig returns the block config that utilizes the
|
||||
// current params in the beacon config.
|
||||
func DefaultBlockGenConfig() *BlockGenConfig {
|
||||
return &BlockGenConfig{
|
||||
NumProposerSlashings: 0,
|
||||
NumAttesterSlashings: 0,
|
||||
NumAttestations: 1,
|
||||
NumDeposits: 0,
|
||||
NumVoluntaryExits: 0,
|
||||
NumTransactions: 0,
|
||||
NumBLSChanges: 0,
|
||||
NumProposerSlashings: 0,
|
||||
NumAttesterSlashings: 0,
|
||||
NumAttestations: 1,
|
||||
NumDeposits: 0,
|
||||
NumVoluntaryExits: 0,
|
||||
NumTransactions: 0,
|
||||
NumBLSChanges: 0,
|
||||
NumWithdrawals: 0,
|
||||
NumConsolidationRequests: 0,
|
||||
NumWithdrawalRequests: 0,
|
||||
NumDepositRequests: 0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -487,6 +498,41 @@ func randValIndex(bState state.BeaconState) (primitives.ValidatorIndex, error) {
|
||||
return primitives.ValidatorIndex(rand.NewGenerator().Uint64() % activeCount), nil
|
||||
}
|
||||
|
||||
func generateWithdrawals(
|
||||
bState state.BeaconState,
|
||||
privs []bls.SecretKey,
|
||||
numWithdrawals uint64,
|
||||
) ([]*enginev1.Withdrawal, error) {
|
||||
withdrawalRequests := make([]*enginev1.Withdrawal, numWithdrawals)
|
||||
for i := uint64(0); i < numWithdrawals; i++ {
|
||||
valIndex, err := randValIndex(bState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
amount := uint64(10000)
|
||||
bal, err := bState.BalanceAtIndex(valIndex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
amounts := []uint64{
|
||||
amount, // some smaller amount
|
||||
bal, // the entire balance
|
||||
}
|
||||
// Get a random index
|
||||
nBig, err := rd.Int(rd.Reader, big.NewInt(int64(len(amounts))))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
randomIndex := nBig.Uint64()
|
||||
withdrawalRequests[i] = &enginev1.Withdrawal{
|
||||
ValidatorIndex: valIndex,
|
||||
Address: make([]byte, common.AddressLength),
|
||||
Amount: amounts[randomIndex],
|
||||
}
|
||||
}
|
||||
return withdrawalRequests, nil
|
||||
}
|
||||
|
||||
// HydrateSignedBeaconHeader hydrates a signed beacon block header with correct field length sizes
|
||||
// to comply with fssz marshalling and unmarshalling rules.
|
||||
func HydrateSignedBeaconHeader(h *ethpb.SignedBeaconBlockHeader) *ethpb.SignedBeaconBlockHeader {
|
||||
|
||||
@@ -2,11 +2,15 @@ package util
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/signing"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/transition"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
@@ -108,7 +112,6 @@ func GenerateFullBlockElectra(
|
||||
for i := uint64(0); i < numToGen; i++ {
|
||||
newTransactions[i] = bytesutil.Uint64ToBytesLittleEndian(i)
|
||||
}
|
||||
newWithdrawals := make([]*v1.Withdrawal, 0)
|
||||
|
||||
random, err := helpers.RandaoMix(bState, time.CurrentEpoch(bState))
|
||||
if err != nil {
|
||||
@@ -126,25 +129,59 @@ func GenerateFullBlockElectra(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newWithdrawals := make([]*v1.Withdrawal, 0)
|
||||
if conf.NumWithdrawals > 0 {
|
||||
newWithdrawals, err = generateWithdrawals(bState, privs, numToGen)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed generating %d withdrawals:", numToGen)
|
||||
}
|
||||
}
|
||||
|
||||
depositRequests := make([]*v1.DepositRequest, 0)
|
||||
if conf.NumDepositRequests > 0 {
|
||||
depositRequests, err = generateDepositRequests(bState, privs, conf.NumDepositRequests)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed generating %d deposit requests:", conf.NumDepositRequests)
|
||||
}
|
||||
}
|
||||
|
||||
withdrawalRequests := make([]*v1.WithdrawalRequest, 0)
|
||||
if conf.NumWithdrawalRequests > 0 {
|
||||
withdrawalRequests, err = generateWithdrawalRequests(bState, privs, conf.NumWithdrawalRequests)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed generating %d withdrawal requests:", conf.NumWithdrawalRequests)
|
||||
}
|
||||
}
|
||||
|
||||
consolidationRequests := make([]*v1.ConsolidationRequest, 0)
|
||||
if conf.NumConsolidationRequests > 0 {
|
||||
consolidationRequests, err = generateConsolidationRequests(bState, privs, conf.NumConsolidationRequests)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed generating %d consolidation requests:", conf.NumConsolidationRequests)
|
||||
}
|
||||
}
|
||||
parentExecution, err := stCopy.LatestExecutionPayloadHeader()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockHash := indexToHash(uint64(slot))
|
||||
newExecutionPayloadCapella := &v1.ExecutionPayloadElectra{
|
||||
ParentHash: parentExecution.BlockHash(),
|
||||
FeeRecipient: make([]byte, 20),
|
||||
StateRoot: params.BeaconConfig().ZeroHash[:],
|
||||
ReceiptsRoot: params.BeaconConfig().ZeroHash[:],
|
||||
LogsBloom: make([]byte, 256),
|
||||
PrevRandao: random,
|
||||
BlockNumber: uint64(slot),
|
||||
ExtraData: params.BeaconConfig().ZeroHash[:],
|
||||
BaseFeePerGas: params.BeaconConfig().ZeroHash[:],
|
||||
BlockHash: blockHash[:],
|
||||
Timestamp: uint64(timestamp.Unix()),
|
||||
Transactions: newTransactions,
|
||||
Withdrawals: newWithdrawals,
|
||||
newExecutionPayloadElectra := &v1.ExecutionPayloadElectra{
|
||||
ParentHash: parentExecution.BlockHash(),
|
||||
FeeRecipient: make([]byte, 20),
|
||||
StateRoot: params.BeaconConfig().ZeroHash[:],
|
||||
ReceiptsRoot: params.BeaconConfig().ZeroHash[:],
|
||||
LogsBloom: make([]byte, 256),
|
||||
PrevRandao: random,
|
||||
BlockNumber: uint64(slot),
|
||||
ExtraData: params.BeaconConfig().ZeroHash[:],
|
||||
BaseFeePerGas: params.BeaconConfig().ZeroHash[:],
|
||||
BlockHash: blockHash[:],
|
||||
Timestamp: uint64(timestamp.Unix()),
|
||||
Transactions: newTransactions,
|
||||
Withdrawals: newWithdrawals,
|
||||
DepositRequests: depositRequests,
|
||||
WithdrawalRequests: withdrawalRequests,
|
||||
ConsolidationRequests: consolidationRequests,
|
||||
}
|
||||
var syncCommitteeBits []byte
|
||||
currSize := new(ethpb.SyncAggregate).SyncCommitteeBits.Len()
|
||||
@@ -208,7 +245,7 @@ func GenerateFullBlockElectra(
|
||||
Deposits: newDeposits,
|
||||
Graffiti: make([]byte, fieldparams.RootLength),
|
||||
SyncAggregate: newSyncAggregate,
|
||||
ExecutionPayload: newExecutionPayloadCapella,
|
||||
ExecutionPayload: newExecutionPayloadElectra,
|
||||
BlsToExecutionChanges: changes,
|
||||
},
|
||||
}
|
||||
@@ -221,3 +258,132 @@ func GenerateFullBlockElectra(
|
||||
|
||||
return ðpb.SignedBeaconBlockElectra{Block: block, Signature: signature.Marshal()}, nil
|
||||
}
|
||||
|
||||
func generateWithdrawalRequests(
|
||||
bState state.BeaconState,
|
||||
privs []bls.SecretKey,
|
||||
numRequests uint64,
|
||||
) ([]*v1.WithdrawalRequest, error) {
|
||||
withdrawalRequests := make([]*v1.WithdrawalRequest, numRequests)
|
||||
for i := uint64(0); i < numRequests; i++ {
|
||||
valIndex, err := randValIndex(bState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Get a random index
|
||||
nBig, err := rand.Int(rand.Reader, big.NewInt(60000))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
amount := nBig.Uint64() // random amount created
|
||||
bal, err := bState.BalanceAtIndex(valIndex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
amounts := []uint64{
|
||||
amount, // some smaller amount
|
||||
bal, // the entire balance
|
||||
}
|
||||
// Get a random index
|
||||
nBig, err = rand.Int(rand.Reader, big.NewInt(int64(len(amounts))))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
randomIndex := nBig.Uint64()
|
||||
withdrawalRequests[i] = &v1.WithdrawalRequest{
|
||||
ValidatorPubkey: privs[valIndex].PublicKey().Marshal(),
|
||||
SourceAddress: make([]byte, common.AddressLength),
|
||||
Amount: amounts[randomIndex],
|
||||
}
|
||||
}
|
||||
return withdrawalRequests, nil
|
||||
}
|
||||
|
||||
func generateDepositRequests(
|
||||
bState state.BeaconState,
|
||||
privs []bls.SecretKey,
|
||||
numRequests uint64,
|
||||
) ([]*v1.DepositRequest, error) {
|
||||
depositRequests := make([]*v1.DepositRequest, numRequests)
|
||||
for i := uint64(0); i < numRequests; i++ {
|
||||
valIndex, err := randValIndex(bState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Get a random index
|
||||
nBig, err := rand.Int(rand.Reader, big.NewInt(60000))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
amount := nBig.Uint64() // random amount created
|
||||
prefixes := []byte{params.BeaconConfig().CompoundingWithdrawalPrefixByte, 0, params.BeaconConfig().BLSWithdrawalPrefixByte}
|
||||
withdrawalCred := make([]byte, 32)
|
||||
// Get a random index
|
||||
nBig, err = rand.Int(rand.Reader, big.NewInt(int64(len(prefixes))))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
randPrefixIndex := nBig.Uint64()
|
||||
withdrawalCred[0] = prefixes[randPrefixIndex]
|
||||
|
||||
depositMessage := ðpb.DepositMessage{
|
||||
PublicKey: privs[valIndex].PublicKey().Marshal(),
|
||||
Amount: amount,
|
||||
WithdrawalCredentials: withdrawalCred,
|
||||
}
|
||||
domain, err := signing.ComputeDomain(params.BeaconConfig().DomainDeposit, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sr, err := signing.ComputeSigningRoot(depositMessage, domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sig := privs[i].Sign(sr[:])
|
||||
depositRequests[i] = &v1.DepositRequest{
|
||||
Pubkey: depositMessage.PublicKey,
|
||||
Index: uint64(valIndex),
|
||||
WithdrawalCredentials: depositMessage.WithdrawalCredentials,
|
||||
Amount: depositMessage.Amount,
|
||||
Signature: sig.Marshal(),
|
||||
}
|
||||
}
|
||||
return depositRequests, nil
|
||||
}
|
||||
|
||||
func generateConsolidationRequests(
|
||||
bState state.BeaconState,
|
||||
privs []bls.SecretKey,
|
||||
numRequests uint64,
|
||||
) ([]*v1.ConsolidationRequest, error) {
|
||||
consolidationRequests := make([]*v1.ConsolidationRequest, numRequests)
|
||||
for i := uint64(0); i < numRequests; i++ {
|
||||
valIndex, err := randValIndex(bState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
valIndex2, err := randValIndex(bState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
source, err := randomAddress()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
consolidationRequests[i] = &v1.ConsolidationRequest{
|
||||
TargetPubkey: privs[valIndex2].PublicKey().Marshal(),
|
||||
SourceAddress: source.Bytes(),
|
||||
SourcePubkey: privs[valIndex].PublicKey().Marshal(),
|
||||
}
|
||||
}
|
||||
return consolidationRequests, nil
|
||||
}
|
||||
|
||||
func randomAddress() (common.Address, error) {
|
||||
b := make([]byte, 20)
|
||||
_, err := rand.Read(b)
|
||||
if err != nil {
|
||||
return common.Address{}, err
|
||||
}
|
||||
return common.BytesToAddress(b), nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user