mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 15:37:56 -05:00
* config values * block protos * get_committee_indices * proto and ssz * attestation interface * Revert "Auxiliary commit to revert individual files from deadb2183723511721b3288c7168808a4fa97c64" This reverts commit 32ad5009537bc5ec0e6caf9f52143d380d00be85. * todos * get_attesting_indices * Revert "Auxiliary commit to revert individual files from dd2789723f90b15eb1f874b561d88d11dcc9c0bf" This reverts commit f39644ed3cb6f3964fc6c86fdf4bd5de2a9668c8. * beacon spec changes * Fix pending attestation. Build ok * Electra: add electra version * Electra: consensus types * gocognit exclusion * @potuz's suggestion * build fix * interfaces for indexed att and slashing * indexed att usage * BuildSignedBeaconBlockFromExecutionPayload * slashing usage * grpc stubs * remove unused methods * Electra attestation interfaces * cleanup * tests * make linter happy * simple casting * test fixes * Fix spectest failures * Regen pb and ssz files * Handle "not ok" type assertion cases * Setters that check version should always return an error. SetAttesterSlashings and SetAttestations * gofmt * Fix TestMinSpanChunksSlice_CheckSlashable --------- Co-authored-by: terence tsao <terence@prysmaticlabs.com> Co-authored-by: Preston Van Loon <preston@pvl.dev>
399 lines
14 KiB
Go
399 lines
14 KiB
Go
package blocks_test
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/blocks"
|
|
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/signing"
|
|
v "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/validators"
|
|
state_native "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native"
|
|
"github.com/prysmaticlabs/prysm/v5/config/params"
|
|
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
|
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
|
"github.com/prysmaticlabs/prysm/v5/crypto/bls"
|
|
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
|
|
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
|
"github.com/prysmaticlabs/prysm/v5/testing/assert"
|
|
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
|
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
|
)
|
|
|
|
func TestSlashableAttestationData_CanSlash(t *testing.T) {
|
|
att1 := util.HydrateAttestationData(ðpb.AttestationData{
|
|
Target: ðpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
|
|
Source: ðpb.Checkpoint{Root: bytesutil.PadTo([]byte{'A'}, 32)},
|
|
})
|
|
att2 := util.HydrateAttestationData(ðpb.AttestationData{
|
|
Target: ðpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
|
|
Source: ðpb.Checkpoint{Root: bytesutil.PadTo([]byte{'B'}, 32)},
|
|
})
|
|
assert.Equal(t, true, blocks.IsSlashableAttestationData(att1, att2), "Atts should have been slashable")
|
|
att1.Target.Epoch = 4
|
|
att1.Source.Epoch = 2
|
|
att2.Source.Epoch = 3
|
|
assert.Equal(t, true, blocks.IsSlashableAttestationData(att1, att2), "Atts should have been slashable")
|
|
}
|
|
|
|
func TestProcessAttesterSlashings_DataNotSlashable(t *testing.T) {
|
|
slashings := []*ethpb.AttesterSlashing{{
|
|
Attestation_1: util.HydrateIndexedAttestation(ðpb.IndexedAttestation{}),
|
|
Attestation_2: util.HydrateIndexedAttestation(ðpb.IndexedAttestation{
|
|
Data: ðpb.AttestationData{
|
|
Source: ðpb.Checkpoint{Epoch: 1},
|
|
Target: ðpb.Checkpoint{Epoch: 1}},
|
|
})}}
|
|
|
|
var registry []*ethpb.Validator
|
|
currentSlot := primitives.Slot(0)
|
|
|
|
beaconState, err := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{
|
|
Validators: registry,
|
|
Slot: currentSlot,
|
|
})
|
|
require.NoError(t, err)
|
|
b := util.NewBeaconBlock()
|
|
b.Block = ðpb.BeaconBlock{
|
|
Body: ðpb.BeaconBlockBody{
|
|
AttesterSlashings: slashings,
|
|
},
|
|
}
|
|
ss := make([]interfaces.AttesterSlashing, len(b.Block.Body.AttesterSlashings))
|
|
for i, s := range b.Block.Body.AttesterSlashings {
|
|
ss[i] = s
|
|
}
|
|
_, err = blocks.ProcessAttesterSlashings(context.Background(), beaconState, ss, v.SlashValidator)
|
|
assert.ErrorContains(t, "attestations are not slashable", err)
|
|
}
|
|
|
|
func TestProcessAttesterSlashings_IndexedAttestationFailedToVerify(t *testing.T) {
|
|
var registry []*ethpb.Validator
|
|
currentSlot := primitives.Slot(0)
|
|
|
|
beaconState, err := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{
|
|
Validators: registry,
|
|
Slot: currentSlot,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
slashings := []*ethpb.AttesterSlashing{
|
|
{
|
|
Attestation_1: util.HydrateIndexedAttestation(ðpb.IndexedAttestation{
|
|
Data: ðpb.AttestationData{
|
|
Source: ðpb.Checkpoint{Epoch: 1},
|
|
},
|
|
AttestingIndices: make([]uint64, params.BeaconConfig().MaxValidatorsPerCommittee+1),
|
|
}),
|
|
Attestation_2: util.HydrateIndexedAttestation(ðpb.IndexedAttestation{
|
|
AttestingIndices: make([]uint64, params.BeaconConfig().MaxValidatorsPerCommittee+1),
|
|
}),
|
|
},
|
|
}
|
|
|
|
b := util.NewBeaconBlock()
|
|
b.Block = ðpb.BeaconBlock{
|
|
Body: ðpb.BeaconBlockBody{
|
|
AttesterSlashings: slashings,
|
|
},
|
|
}
|
|
|
|
ss := make([]interfaces.AttesterSlashing, len(b.Block.Body.AttesterSlashings))
|
|
for i, s := range b.Block.Body.AttesterSlashings {
|
|
ss[i] = s
|
|
}
|
|
_, err = blocks.ProcessAttesterSlashings(context.Background(), beaconState, ss, v.SlashValidator)
|
|
assert.ErrorContains(t, "validator indices count exceeds MAX_VALIDATORS_PER_COMMITTEE", err)
|
|
}
|
|
|
|
func TestProcessAttesterSlashings_AppliesCorrectStatus(t *testing.T) {
|
|
beaconState, privKeys := util.DeterministicGenesisState(t, 100)
|
|
for _, vv := range beaconState.Validators() {
|
|
vv.WithdrawableEpoch = primitives.Epoch(params.BeaconConfig().SlotsPerEpoch)
|
|
}
|
|
|
|
att1 := util.HydrateIndexedAttestation(ðpb.IndexedAttestation{
|
|
Data: ðpb.AttestationData{
|
|
Source: ðpb.Checkpoint{Epoch: 1},
|
|
},
|
|
AttestingIndices: []uint64{0, 1},
|
|
})
|
|
domain, err := signing.Domain(beaconState.Fork(), 0, params.BeaconConfig().DomainBeaconAttester, beaconState.GenesisValidatorsRoot())
|
|
require.NoError(t, err)
|
|
signingRoot, err := signing.ComputeSigningRoot(att1.Data, domain)
|
|
assert.NoError(t, err, "Could not get signing root of beacon block header")
|
|
sig0 := privKeys[0].Sign(signingRoot[:])
|
|
sig1 := privKeys[1].Sign(signingRoot[:])
|
|
aggregateSig := bls.AggregateSignatures([]bls.Signature{sig0, sig1})
|
|
att1.Signature = aggregateSig.Marshal()
|
|
|
|
att2 := util.HydrateIndexedAttestation(ðpb.IndexedAttestation{
|
|
AttestingIndices: []uint64{0, 1},
|
|
})
|
|
signingRoot, err = signing.ComputeSigningRoot(att2.Data, domain)
|
|
assert.NoError(t, err, "Could not get signing root of beacon block header")
|
|
sig0 = privKeys[0].Sign(signingRoot[:])
|
|
sig1 = privKeys[1].Sign(signingRoot[:])
|
|
aggregateSig = bls.AggregateSignatures([]bls.Signature{sig0, sig1})
|
|
att2.Signature = aggregateSig.Marshal()
|
|
|
|
slashings := []*ethpb.AttesterSlashing{
|
|
{
|
|
Attestation_1: att1,
|
|
Attestation_2: att2,
|
|
},
|
|
}
|
|
|
|
currentSlot := 2 * params.BeaconConfig().SlotsPerEpoch
|
|
require.NoError(t, beaconState.SetSlot(currentSlot))
|
|
|
|
b := util.NewBeaconBlock()
|
|
b.Block = ðpb.BeaconBlock{
|
|
Body: ðpb.BeaconBlockBody{
|
|
AttesterSlashings: slashings,
|
|
},
|
|
}
|
|
|
|
ss := make([]interfaces.AttesterSlashing, len(b.Block.Body.AttesterSlashings))
|
|
for i, s := range b.Block.Body.AttesterSlashings {
|
|
ss[i] = s
|
|
}
|
|
newState, err := blocks.ProcessAttesterSlashings(context.Background(), beaconState, ss, v.SlashValidator)
|
|
require.NoError(t, err)
|
|
newRegistry := newState.Validators()
|
|
|
|
// Given the intersection of slashable indices is [1], only validator
|
|
// at index 1 should be slashed and exited. We confirm this below.
|
|
if newRegistry[1].ExitEpoch != beaconState.Validators()[1].ExitEpoch {
|
|
t.Errorf(
|
|
`
|
|
Expected validator at index 1's exit epoch to match
|
|
%d, received %d instead
|
|
`,
|
|
beaconState.Validators()[1].ExitEpoch,
|
|
newRegistry[1].ExitEpoch,
|
|
)
|
|
}
|
|
|
|
require.Equal(t, uint64(31750000000), newState.Balances()[1])
|
|
require.Equal(t, uint64(32000000000), newState.Balances()[2])
|
|
}
|
|
|
|
func TestProcessAttesterSlashings_AppliesCorrectStatusAltair(t *testing.T) {
|
|
beaconState, privKeys := util.DeterministicGenesisStateAltair(t, 100)
|
|
for _, vv := range beaconState.Validators() {
|
|
vv.WithdrawableEpoch = primitives.Epoch(params.BeaconConfig().SlotsPerEpoch)
|
|
}
|
|
|
|
att1 := util.HydrateIndexedAttestation(ðpb.IndexedAttestation{
|
|
Data: ðpb.AttestationData{
|
|
Source: ðpb.Checkpoint{Epoch: 1},
|
|
},
|
|
AttestingIndices: []uint64{0, 1},
|
|
})
|
|
domain, err := signing.Domain(beaconState.Fork(), 0, params.BeaconConfig().DomainBeaconAttester, beaconState.GenesisValidatorsRoot())
|
|
require.NoError(t, err)
|
|
signingRoot, err := signing.ComputeSigningRoot(att1.Data, domain)
|
|
assert.NoError(t, err, "Could not get signing root of beacon block header")
|
|
sig0 := privKeys[0].Sign(signingRoot[:])
|
|
sig1 := privKeys[1].Sign(signingRoot[:])
|
|
aggregateSig := bls.AggregateSignatures([]bls.Signature{sig0, sig1})
|
|
att1.Signature = aggregateSig.Marshal()
|
|
|
|
att2 := util.HydrateIndexedAttestation(ðpb.IndexedAttestation{
|
|
AttestingIndices: []uint64{0, 1},
|
|
})
|
|
signingRoot, err = signing.ComputeSigningRoot(att2.Data, domain)
|
|
assert.NoError(t, err, "Could not get signing root of beacon block header")
|
|
sig0 = privKeys[0].Sign(signingRoot[:])
|
|
sig1 = privKeys[1].Sign(signingRoot[:])
|
|
aggregateSig = bls.AggregateSignatures([]bls.Signature{sig0, sig1})
|
|
att2.Signature = aggregateSig.Marshal()
|
|
|
|
slashings := []*ethpb.AttesterSlashing{
|
|
{
|
|
Attestation_1: att1,
|
|
Attestation_2: att2,
|
|
},
|
|
}
|
|
|
|
currentSlot := 2 * params.BeaconConfig().SlotsPerEpoch
|
|
require.NoError(t, beaconState.SetSlot(currentSlot))
|
|
|
|
b := util.NewBeaconBlock()
|
|
b.Block = ðpb.BeaconBlock{
|
|
Body: ðpb.BeaconBlockBody{
|
|
AttesterSlashings: slashings,
|
|
},
|
|
}
|
|
|
|
ss := make([]interfaces.AttesterSlashing, len(b.Block.Body.AttesterSlashings))
|
|
for i, s := range b.Block.Body.AttesterSlashings {
|
|
ss[i] = s
|
|
}
|
|
newState, err := blocks.ProcessAttesterSlashings(context.Background(), beaconState, ss, v.SlashValidator)
|
|
require.NoError(t, err)
|
|
newRegistry := newState.Validators()
|
|
|
|
// Given the intersection of slashable indices is [1], only validator
|
|
// at index 1 should be slashed and exited. We confirm this below.
|
|
if newRegistry[1].ExitEpoch != beaconState.Validators()[1].ExitEpoch {
|
|
t.Errorf(
|
|
`
|
|
Expected validator at index 1's exit epoch to match
|
|
%d, received %d instead
|
|
`,
|
|
beaconState.Validators()[1].ExitEpoch,
|
|
newRegistry[1].ExitEpoch,
|
|
)
|
|
}
|
|
|
|
require.Equal(t, uint64(31500000000), newState.Balances()[1])
|
|
require.Equal(t, uint64(32000000000), newState.Balances()[2])
|
|
}
|
|
|
|
func TestProcessAttesterSlashings_AppliesCorrectStatusBellatrix(t *testing.T) {
|
|
beaconState, privKeys := util.DeterministicGenesisStateBellatrix(t, 100)
|
|
for _, vv := range beaconState.Validators() {
|
|
vv.WithdrawableEpoch = primitives.Epoch(params.BeaconConfig().SlotsPerEpoch)
|
|
}
|
|
|
|
att1 := util.HydrateIndexedAttestation(ðpb.IndexedAttestation{
|
|
Data: ðpb.AttestationData{
|
|
Source: ðpb.Checkpoint{Epoch: 1},
|
|
},
|
|
AttestingIndices: []uint64{0, 1},
|
|
})
|
|
domain, err := signing.Domain(beaconState.Fork(), 0, params.BeaconConfig().DomainBeaconAttester, beaconState.GenesisValidatorsRoot())
|
|
require.NoError(t, err)
|
|
signingRoot, err := signing.ComputeSigningRoot(att1.Data, domain)
|
|
assert.NoError(t, err, "Could not get signing root of beacon block header")
|
|
sig0 := privKeys[0].Sign(signingRoot[:])
|
|
sig1 := privKeys[1].Sign(signingRoot[:])
|
|
aggregateSig := bls.AggregateSignatures([]bls.Signature{sig0, sig1})
|
|
att1.Signature = aggregateSig.Marshal()
|
|
|
|
att2 := util.HydrateIndexedAttestation(ðpb.IndexedAttestation{
|
|
AttestingIndices: []uint64{0, 1},
|
|
})
|
|
signingRoot, err = signing.ComputeSigningRoot(att2.Data, domain)
|
|
assert.NoError(t, err, "Could not get signing root of beacon block header")
|
|
sig0 = privKeys[0].Sign(signingRoot[:])
|
|
sig1 = privKeys[1].Sign(signingRoot[:])
|
|
aggregateSig = bls.AggregateSignatures([]bls.Signature{sig0, sig1})
|
|
att2.Signature = aggregateSig.Marshal()
|
|
|
|
slashings := []*ethpb.AttesterSlashing{
|
|
{
|
|
Attestation_1: att1,
|
|
Attestation_2: att2,
|
|
},
|
|
}
|
|
|
|
currentSlot := 2 * params.BeaconConfig().SlotsPerEpoch
|
|
require.NoError(t, beaconState.SetSlot(currentSlot))
|
|
|
|
b := util.NewBeaconBlock()
|
|
b.Block = ðpb.BeaconBlock{
|
|
Body: ðpb.BeaconBlockBody{
|
|
AttesterSlashings: slashings,
|
|
},
|
|
}
|
|
|
|
ss := make([]interfaces.AttesterSlashing, len(b.Block.Body.AttesterSlashings))
|
|
for i, s := range b.Block.Body.AttesterSlashings {
|
|
ss[i] = s
|
|
}
|
|
newState, err := blocks.ProcessAttesterSlashings(context.Background(), beaconState, ss, v.SlashValidator)
|
|
require.NoError(t, err)
|
|
newRegistry := newState.Validators()
|
|
|
|
// Given the intersection of slashable indices is [1], only validator
|
|
// at index 1 should be slashed and exited. We confirm this below.
|
|
if newRegistry[1].ExitEpoch != beaconState.Validators()[1].ExitEpoch {
|
|
t.Errorf(
|
|
`
|
|
Expected validator at index 1's exit epoch to match
|
|
%d, received %d instead
|
|
`,
|
|
beaconState.Validators()[1].ExitEpoch,
|
|
newRegistry[1].ExitEpoch,
|
|
)
|
|
}
|
|
|
|
require.Equal(t, uint64(31000000000), newState.Balances()[1])
|
|
require.Equal(t, uint64(32000000000), newState.Balances()[2])
|
|
}
|
|
|
|
func TestProcessAttesterSlashings_AppliesCorrectStatusCapella(t *testing.T) {
|
|
beaconState, privKeys := util.DeterministicGenesisStateCapella(t, 100)
|
|
for _, vv := range beaconState.Validators() {
|
|
vv.WithdrawableEpoch = primitives.Epoch(params.BeaconConfig().SlotsPerEpoch)
|
|
}
|
|
|
|
att1 := util.HydrateIndexedAttestation(ðpb.IndexedAttestation{
|
|
Data: ðpb.AttestationData{
|
|
Source: ðpb.Checkpoint{Epoch: 1},
|
|
},
|
|
AttestingIndices: []uint64{0, 1},
|
|
})
|
|
domain, err := signing.Domain(beaconState.Fork(), 0, params.BeaconConfig().DomainBeaconAttester, beaconState.GenesisValidatorsRoot())
|
|
require.NoError(t, err)
|
|
signingRoot, err := signing.ComputeSigningRoot(att1.Data, domain)
|
|
assert.NoError(t, err, "Could not get signing root of beacon block header")
|
|
sig0 := privKeys[0].Sign(signingRoot[:])
|
|
sig1 := privKeys[1].Sign(signingRoot[:])
|
|
aggregateSig := bls.AggregateSignatures([]bls.Signature{sig0, sig1})
|
|
att1.Signature = aggregateSig.Marshal()
|
|
|
|
att2 := util.HydrateIndexedAttestation(ðpb.IndexedAttestation{
|
|
AttestingIndices: []uint64{0, 1},
|
|
})
|
|
signingRoot, err = signing.ComputeSigningRoot(att2.Data, domain)
|
|
assert.NoError(t, err, "Could not get signing root of beacon block header")
|
|
sig0 = privKeys[0].Sign(signingRoot[:])
|
|
sig1 = privKeys[1].Sign(signingRoot[:])
|
|
aggregateSig = bls.AggregateSignatures([]bls.Signature{sig0, sig1})
|
|
att2.Signature = aggregateSig.Marshal()
|
|
|
|
slashings := []*ethpb.AttesterSlashing{
|
|
{
|
|
Attestation_1: att1,
|
|
Attestation_2: att2,
|
|
},
|
|
}
|
|
|
|
currentSlot := 2 * params.BeaconConfig().SlotsPerEpoch
|
|
require.NoError(t, beaconState.SetSlot(currentSlot))
|
|
|
|
b := util.NewBeaconBlock()
|
|
b.Block = ðpb.BeaconBlock{
|
|
Body: ðpb.BeaconBlockBody{
|
|
AttesterSlashings: slashings,
|
|
},
|
|
}
|
|
|
|
ss := make([]interfaces.AttesterSlashing, len(b.Block.Body.AttesterSlashings))
|
|
for i, s := range b.Block.Body.AttesterSlashings {
|
|
ss[i] = s
|
|
}
|
|
newState, err := blocks.ProcessAttesterSlashings(context.Background(), beaconState, ss, v.SlashValidator)
|
|
require.NoError(t, err)
|
|
newRegistry := newState.Validators()
|
|
|
|
// Given the intersection of slashable indices is [1], only validator
|
|
// at index 1 should be slashed and exited. We confirm this below.
|
|
if newRegistry[1].ExitEpoch != beaconState.Validators()[1].ExitEpoch {
|
|
t.Errorf(
|
|
`
|
|
Expected validator at index 1's exit epoch to match
|
|
%d, received %d instead
|
|
`,
|
|
beaconState.Validators()[1].ExitEpoch,
|
|
newRegistry[1].ExitEpoch,
|
|
)
|
|
}
|
|
|
|
require.Equal(t, uint64(31000000000), newState.Balances()[1])
|
|
require.Equal(t, uint64(32000000000), newState.Balances()[2])
|
|
}
|