2020-02-07 02:32:51 +00:00
|
|
|
package slashings
|
|
|
|
|
|
|
|
import (
|
2020-03-12 01:16:55 +00:00
|
|
|
"context"
|
2020-02-07 02:32:51 +00:00
|
|
|
"reflect"
|
|
|
|
"testing"
|
|
|
|
|
2020-05-20 20:27:23 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
|
|
|
"github.com/prysmaticlabs/prysm/shared/bls"
|
2020-07-15 18:37:51 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
2020-05-20 20:27:23 +00:00
|
|
|
|
2020-02-07 02:32:51 +00:00
|
|
|
"github.com/gogo/protobuf/proto"
|
|
|
|
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
2020-03-12 01:16:55 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
2020-02-07 02:32:51 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/shared/params"
|
2020-03-12 01:16:55 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/shared/testutil"
|
2020-07-15 18:37:51 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
2020-02-07 02:32:51 +00:00
|
|
|
)
|
|
|
|
|
2020-06-25 00:47:51 +00:00
|
|
|
func validAttesterSlashingForValIdx(t *testing.T, beaconState *state.BeaconState, privs []bls.SecretKey, valIdx ...uint64) *ethpb.AttesterSlashing {
|
2020-05-20 20:27:23 +00:00
|
|
|
slashings := []*ethpb.AttesterSlashing{}
|
|
|
|
for _, idx := range valIdx {
|
|
|
|
slashing, err := testutil.GenerateAttesterSlashingForValidator(beaconState, privs[idx], idx)
|
2020-07-15 18:37:51 +00:00
|
|
|
require.NoError(t, err)
|
2020-05-20 20:27:23 +00:00
|
|
|
slashings = append(slashings, slashing)
|
|
|
|
}
|
2020-06-25 00:47:51 +00:00
|
|
|
allSig1 := []bls.Signature{}
|
|
|
|
allSig2 := []bls.Signature{}
|
2020-05-20 20:27:23 +00:00
|
|
|
for _, slashing := range slashings {
|
|
|
|
sig1 := slashing.Attestation_1.Signature
|
|
|
|
sig2 := slashing.Attestation_2.Signature
|
|
|
|
sigFromBytes1, err := bls.SignatureFromBytes(sig1)
|
2020-07-15 18:37:51 +00:00
|
|
|
require.NoError(t, err)
|
2020-05-20 20:27:23 +00:00
|
|
|
sigFromBytes2, err := bls.SignatureFromBytes(sig2)
|
2020-07-15 18:37:51 +00:00
|
|
|
require.NoError(t, err)
|
2020-05-20 20:27:23 +00:00
|
|
|
allSig1 = append(allSig1, sigFromBytes1)
|
|
|
|
allSig2 = append(allSig2, sigFromBytes2)
|
|
|
|
}
|
|
|
|
aggSig1 := bls.AggregateSignatures(allSig1)
|
|
|
|
aggSig2 := bls.AggregateSignatures(allSig2)
|
|
|
|
aggSlashing := ðpb.AttesterSlashing{
|
2020-02-07 02:32:51 +00:00
|
|
|
Attestation_1: ðpb.IndexedAttestation{
|
|
|
|
AttestingIndices: valIdx,
|
2020-05-20 20:27:23 +00:00
|
|
|
Data: slashings[0].Attestation_1.Data,
|
|
|
|
Signature: aggSig1.Marshal(),
|
2020-02-07 02:32:51 +00:00
|
|
|
},
|
|
|
|
Attestation_2: ðpb.IndexedAttestation{
|
|
|
|
AttestingIndices: valIdx,
|
2020-05-20 20:27:23 +00:00
|
|
|
Data: slashings[0].Attestation_2.Data,
|
|
|
|
Signature: aggSig2.Marshal(),
|
2020-02-07 02:32:51 +00:00
|
|
|
},
|
|
|
|
}
|
2020-05-20 20:27:23 +00:00
|
|
|
return aggSlashing
|
|
|
|
}
|
|
|
|
|
|
|
|
func attesterSlashingForValIdx(valIdx ...uint64) *ethpb.AttesterSlashing {
|
|
|
|
return ðpb.AttesterSlashing{
|
|
|
|
Attestation_1: ðpb.IndexedAttestation{AttestingIndices: valIdx},
|
|
|
|
Attestation_2: ðpb.IndexedAttestation{AttestingIndices: valIdx},
|
|
|
|
}
|
2020-02-07 02:32:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func pendingSlashingForValIdx(valIdx ...uint64) *PendingAttesterSlashing {
|
|
|
|
return &PendingAttesterSlashing{
|
|
|
|
attesterSlashing: attesterSlashingForValIdx(valIdx...),
|
|
|
|
validatorToSlash: valIdx[0],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestPool_InsertAttesterSlashing(t *testing.T) {
|
|
|
|
type fields struct {
|
|
|
|
pending []*PendingAttesterSlashing
|
|
|
|
included map[uint64]bool
|
2020-05-20 20:27:23 +00:00
|
|
|
wantErr []bool
|
2020-02-14 04:20:45 +00:00
|
|
|
err string
|
2020-02-07 02:32:51 +00:00
|
|
|
}
|
|
|
|
type args struct {
|
2020-03-12 01:16:55 +00:00
|
|
|
slashings []*ethpb.AttesterSlashing
|
|
|
|
}
|
|
|
|
|
|
|
|
beaconState, privKeys := testutil.DeterministicGenesisState(t, 64)
|
|
|
|
pendingSlashings := make([]*PendingAttesterSlashing, 20)
|
|
|
|
slashings := make([]*ethpb.AttesterSlashing, 20)
|
|
|
|
for i := 0; i < len(pendingSlashings); i++ {
|
|
|
|
sl, err := testutil.GenerateAttesterSlashingForValidator(beaconState, privKeys[i], uint64(i))
|
2020-07-15 18:37:51 +00:00
|
|
|
require.NoError(t, err)
|
2020-03-12 01:16:55 +00:00
|
|
|
pendingSlashings[i] = &PendingAttesterSlashing{
|
|
|
|
attesterSlashing: sl,
|
|
|
|
validatorToSlash: uint64(i),
|
|
|
|
}
|
|
|
|
slashings[i] = sl
|
2020-02-07 02:32:51 +00:00
|
|
|
}
|
2020-03-12 01:16:55 +00:00
|
|
|
if err := beaconState.SetSlot(helpers.StartSlot(1)); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// We mark the following validators with some preconditions.
|
2020-04-14 16:41:09 +00:00
|
|
|
exitedVal, err := beaconState.ValidatorAtIndex(uint64(2))
|
2020-07-15 18:37:51 +00:00
|
|
|
require.NoError(t, err)
|
2020-05-29 04:26:09 +00:00
|
|
|
exitedVal.WithdrawableEpoch = 0
|
|
|
|
if err := beaconState.UpdateValidatorAtIndex(uint64(2), exitedVal); err != nil {
|
2020-04-14 16:41:09 +00:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2020-05-29 04:26:09 +00:00
|
|
|
futureWithdrawVal, err := beaconState.ValidatorAtIndex(uint64(4))
|
2020-07-15 18:37:51 +00:00
|
|
|
require.NoError(t, err)
|
2020-05-29 04:26:09 +00:00
|
|
|
futureWithdrawVal.WithdrawableEpoch = 17
|
|
|
|
if err := beaconState.UpdateValidatorAtIndex(uint64(4), futureWithdrawVal); err != nil {
|
2020-05-20 20:27:23 +00:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2020-05-29 04:26:09 +00:00
|
|
|
slashedVal, err := beaconState.ValidatorAtIndex(uint64(5))
|
2020-07-15 18:37:51 +00:00
|
|
|
require.NoError(t, err)
|
2020-05-29 04:26:09 +00:00
|
|
|
slashedVal.Slashed = true
|
|
|
|
if err := beaconState.UpdateValidatorAtIndex(uint64(5), slashedVal); err != nil {
|
2020-03-12 01:16:55 +00:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2020-05-29 04:26:09 +00:00
|
|
|
slashedVal2, err := beaconState.ValidatorAtIndex(uint64(21))
|
2020-07-15 18:37:51 +00:00
|
|
|
require.NoError(t, err)
|
2020-05-29 04:26:09 +00:00
|
|
|
slashedVal2.Slashed = true
|
2020-05-20 20:27:23 +00:00
|
|
|
if err := beaconState.UpdateValidatorAtIndex(uint64(21), slashedVal2); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
aggSlashing1 := validAttesterSlashingForValIdx(t, beaconState, privKeys, 0, 1, 2)
|
|
|
|
aggSlashing2 := validAttesterSlashingForValIdx(t, beaconState, privKeys, 5, 9, 13)
|
|
|
|
aggSlashing3 := validAttesterSlashingForValIdx(t, beaconState, privKeys, 15, 20, 21)
|
|
|
|
aggSlashing4 := validAttesterSlashingForValIdx(t, beaconState, privKeys, 2, 5, 21)
|
2020-03-12 01:16:55 +00:00
|
|
|
|
2020-02-07 02:32:51 +00:00
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
fields fields
|
|
|
|
args args
|
|
|
|
want []*PendingAttesterSlashing
|
|
|
|
err string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "Empty list",
|
|
|
|
fields: fields{
|
|
|
|
pending: make([]*PendingAttesterSlashing, 0),
|
|
|
|
included: make(map[uint64]bool),
|
2020-05-20 20:27:23 +00:00
|
|
|
wantErr: []bool{false},
|
2020-02-07 02:32:51 +00:00
|
|
|
},
|
|
|
|
args: args{
|
2020-03-12 01:16:55 +00:00
|
|
|
slashings: slashings[0:1],
|
2020-02-07 02:32:51 +00:00
|
|
|
},
|
|
|
|
want: []*PendingAttesterSlashing{
|
|
|
|
{
|
2020-03-12 01:16:55 +00:00
|
|
|
attesterSlashing: slashings[0],
|
2020-02-07 02:32:51 +00:00
|
|
|
validatorToSlash: 0,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
2020-03-12 01:16:55 +00:00
|
|
|
name: "Empty list two validators slashed",
|
2020-02-07 02:32:51 +00:00
|
|
|
fields: fields{
|
|
|
|
pending: make([]*PendingAttesterSlashing, 0),
|
|
|
|
included: make(map[uint64]bool),
|
2020-05-20 20:27:23 +00:00
|
|
|
wantErr: []bool{false, false},
|
2020-02-07 02:32:51 +00:00
|
|
|
},
|
|
|
|
args: args{
|
2020-03-12 01:16:55 +00:00
|
|
|
slashings: slashings[0:2],
|
2020-02-07 02:32:51 +00:00
|
|
|
},
|
2020-03-12 01:16:55 +00:00
|
|
|
want: pendingSlashings[0:2],
|
2020-02-07 02:32:51 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Duplicate identical slashing",
|
|
|
|
fields: fields{
|
|
|
|
pending: []*PendingAttesterSlashing{
|
2020-03-12 01:16:55 +00:00
|
|
|
pendingSlashings[1],
|
2020-02-07 02:32:51 +00:00
|
|
|
},
|
|
|
|
included: make(map[uint64]bool),
|
2020-05-20 20:27:23 +00:00
|
|
|
wantErr: []bool{true},
|
2020-02-07 02:32:51 +00:00
|
|
|
},
|
|
|
|
args: args{
|
2020-03-12 01:16:55 +00:00
|
|
|
slashings: slashings[1:2],
|
2020-02-07 02:32:51 +00:00
|
|
|
},
|
2020-03-12 01:16:55 +00:00
|
|
|
want: pendingSlashings[1:2],
|
2020-02-07 02:32:51 +00:00
|
|
|
},
|
|
|
|
{
|
2020-05-29 04:26:09 +00:00
|
|
|
name: "Slashing for already exit validator",
|
2020-02-07 02:32:51 +00:00
|
|
|
fields: fields{
|
|
|
|
pending: []*PendingAttesterSlashing{},
|
|
|
|
included: make(map[uint64]bool),
|
2020-05-20 20:27:23 +00:00
|
|
|
wantErr: []bool{true},
|
2020-02-07 02:32:51 +00:00
|
|
|
},
|
|
|
|
args: args{
|
2020-03-12 01:16:55 +00:00
|
|
|
slashings: slashings[5:6],
|
2020-02-07 02:32:51 +00:00
|
|
|
},
|
|
|
|
want: []*PendingAttesterSlashing{},
|
|
|
|
},
|
|
|
|
{
|
2020-05-29 04:26:09 +00:00
|
|
|
name: "Slashing for withdrawable validator",
|
2020-02-07 02:32:51 +00:00
|
|
|
fields: fields{
|
|
|
|
pending: []*PendingAttesterSlashing{},
|
|
|
|
included: make(map[uint64]bool),
|
2020-05-20 20:27:23 +00:00
|
|
|
wantErr: []bool{true},
|
2020-02-07 02:32:51 +00:00
|
|
|
},
|
|
|
|
args: args{
|
2020-03-12 01:16:55 +00:00
|
|
|
slashings: slashings[2:3],
|
2020-02-07 02:32:51 +00:00
|
|
|
},
|
2020-03-12 01:16:55 +00:00
|
|
|
want: []*PendingAttesterSlashing{},
|
2020-02-07 02:32:51 +00:00
|
|
|
},
|
|
|
|
{
|
2020-05-29 04:26:09 +00:00
|
|
|
name: "Slashing for slashed validator",
|
2020-02-07 02:32:51 +00:00
|
|
|
fields: fields{
|
|
|
|
pending: []*PendingAttesterSlashing{},
|
|
|
|
included: make(map[uint64]bool),
|
2020-05-20 20:27:23 +00:00
|
|
|
wantErr: []bool{false},
|
2020-02-07 02:32:51 +00:00
|
|
|
},
|
|
|
|
args: args{
|
2020-03-12 01:16:55 +00:00
|
|
|
slashings: slashings[4:5],
|
2020-02-07 02:32:51 +00:00
|
|
|
},
|
2020-03-12 01:16:55 +00:00
|
|
|
want: pendingSlashings[4:5],
|
2020-02-07 02:32:51 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Already included",
|
|
|
|
fields: fields{
|
|
|
|
pending: []*PendingAttesterSlashing{},
|
|
|
|
included: map[uint64]bool{
|
|
|
|
1: true,
|
|
|
|
},
|
2020-05-20 20:27:23 +00:00
|
|
|
wantErr: []bool{true},
|
2020-02-07 02:32:51 +00:00
|
|
|
},
|
|
|
|
args: args{
|
2020-03-12 01:16:55 +00:00
|
|
|
slashings: slashings[1:2],
|
2020-02-07 02:32:51 +00:00
|
|
|
},
|
|
|
|
want: []*PendingAttesterSlashing{},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Maintains sorted order",
|
|
|
|
fields: fields{
|
|
|
|
pending: []*PendingAttesterSlashing{
|
2020-03-12 01:16:55 +00:00
|
|
|
pendingSlashings[0],
|
|
|
|
pendingSlashings[2],
|
2020-02-07 02:32:51 +00:00
|
|
|
},
|
|
|
|
included: make(map[uint64]bool),
|
2020-05-20 20:27:23 +00:00
|
|
|
wantErr: []bool{false},
|
2020-02-07 02:32:51 +00:00
|
|
|
},
|
|
|
|
args: args{
|
2020-03-12 01:16:55 +00:00
|
|
|
slashings: slashings[1:2],
|
2020-02-07 02:32:51 +00:00
|
|
|
},
|
2020-03-12 01:16:55 +00:00
|
|
|
want: pendingSlashings[0:3],
|
2020-02-07 02:32:51 +00:00
|
|
|
},
|
2020-05-20 20:27:23 +00:00
|
|
|
{
|
|
|
|
name: "Doesn't reject partially slashed slashings",
|
|
|
|
fields: fields{
|
|
|
|
pending: []*PendingAttesterSlashing{},
|
|
|
|
included: make(map[uint64]bool),
|
|
|
|
wantErr: []bool{false, false, false, true},
|
|
|
|
},
|
|
|
|
args: args{
|
|
|
|
slashings: []*ethpb.AttesterSlashing{
|
|
|
|
aggSlashing1,
|
|
|
|
aggSlashing2,
|
|
|
|
aggSlashing3,
|
|
|
|
aggSlashing4,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
want: []*PendingAttesterSlashing{
|
|
|
|
{
|
|
|
|
attesterSlashing: aggSlashing1,
|
|
|
|
validatorToSlash: 0,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
attesterSlashing: aggSlashing1,
|
|
|
|
validatorToSlash: 1,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
attesterSlashing: aggSlashing2,
|
|
|
|
validatorToSlash: 9,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
attesterSlashing: aggSlashing2,
|
|
|
|
validatorToSlash: 13,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
attesterSlashing: aggSlashing3,
|
|
|
|
validatorToSlash: 15,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
attesterSlashing: aggSlashing3,
|
|
|
|
validatorToSlash: 20,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2020-02-07 02:32:51 +00:00
|
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
p := &Pool{
|
|
|
|
pendingAttesterSlashing: tt.fields.pending,
|
|
|
|
included: tt.fields.included,
|
|
|
|
}
|
2020-03-12 01:16:55 +00:00
|
|
|
var err error
|
|
|
|
for i := 0; i < len(tt.args.slashings); i++ {
|
|
|
|
err = p.InsertAttesterSlashing(context.Background(), beaconState, tt.args.slashings[i])
|
2020-05-20 20:27:23 +00:00
|
|
|
if (err != nil) != tt.fields.wantErr[i] {
|
|
|
|
t.Fatalf("Unexpected expect error at %d: %v", i, err)
|
|
|
|
}
|
2020-02-14 04:20:45 +00:00
|
|
|
}
|
2020-07-15 18:37:51 +00:00
|
|
|
assert.Equal(t, len(tt.want), len(p.pendingAttesterSlashing))
|
|
|
|
|
2020-02-07 02:32:51 +00:00
|
|
|
for i := range p.pendingAttesterSlashing {
|
2020-07-15 18:37:51 +00:00
|
|
|
assert.Equal(t, tt.want[i].validatorToSlash, p.pendingAttesterSlashing[i].validatorToSlash)
|
2020-02-07 02:32:51 +00:00
|
|
|
if !proto.Equal(p.pendingAttesterSlashing[i].attesterSlashing, tt.want[i].attesterSlashing) {
|
|
|
|
t.Errorf(
|
|
|
|
"Pending attester slashing at index %d does not match expected. Got=%v wanted=%v",
|
|
|
|
i,
|
|
|
|
p.pendingAttesterSlashing[i],
|
|
|
|
tt.want[i],
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-12 01:16:55 +00:00
|
|
|
func TestPool_InsertAttesterSlashing_SigFailsVerify_ClearPool(t *testing.T) {
|
2020-05-05 08:39:38 +00:00
|
|
|
params.SetupTestConfigCleanup(t)
|
2020-03-12 01:16:55 +00:00
|
|
|
conf := params.BeaconConfig()
|
|
|
|
conf.MaxAttesterSlashings = 2
|
|
|
|
params.OverrideBeaconConfig(conf)
|
|
|
|
beaconState, privKeys := testutil.DeterministicGenesisState(t, 64)
|
|
|
|
pendingSlashings := make([]*PendingAttesterSlashing, 2)
|
|
|
|
slashings := make([]*ethpb.AttesterSlashing, 2)
|
|
|
|
for i := 0; i < 2; i++ {
|
|
|
|
sl, err := testutil.GenerateAttesterSlashingForValidator(beaconState, privKeys[i], uint64(i))
|
2020-07-15 18:37:51 +00:00
|
|
|
require.NoError(t, err)
|
2020-03-12 01:16:55 +00:00
|
|
|
pendingSlashings[i] = &PendingAttesterSlashing{
|
|
|
|
attesterSlashing: sl,
|
|
|
|
validatorToSlash: uint64(i),
|
|
|
|
}
|
|
|
|
slashings[i] = sl
|
|
|
|
}
|
|
|
|
// We mess up the signature of the second slashing.
|
|
|
|
badSig := make([]byte, 96)
|
|
|
|
copy(badSig, "muahaha")
|
|
|
|
pendingSlashings[1].attesterSlashing.Attestation_1.Signature = badSig
|
|
|
|
slashings[1].Attestation_1.Signature = badSig
|
|
|
|
p := &Pool{
|
|
|
|
pendingAttesterSlashing: make([]*PendingAttesterSlashing, 0),
|
|
|
|
}
|
|
|
|
if err := p.InsertAttesterSlashing(
|
|
|
|
context.Background(),
|
|
|
|
beaconState,
|
|
|
|
slashings[0],
|
|
|
|
); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if err := p.InsertAttesterSlashing(
|
|
|
|
context.Background(),
|
|
|
|
beaconState,
|
|
|
|
slashings[1],
|
|
|
|
); err == nil {
|
|
|
|
t.Error("Expected error when inserting slashing with bad sig, got nil")
|
|
|
|
}
|
2020-07-15 18:37:51 +00:00
|
|
|
assert.Equal(t, 1, len(p.pendingAttesterSlashing))
|
2020-03-12 01:16:55 +00:00
|
|
|
}
|
|
|
|
|
2020-02-07 02:32:51 +00:00
|
|
|
func TestPool_MarkIncludedAttesterSlashing(t *testing.T) {
|
|
|
|
type fields struct {
|
|
|
|
pending []*PendingAttesterSlashing
|
|
|
|
included map[uint64]bool
|
|
|
|
}
|
|
|
|
type args struct {
|
|
|
|
slashing *ethpb.AttesterSlashing
|
|
|
|
}
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
fields fields
|
|
|
|
args args
|
|
|
|
want fields
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "Included, does not exist in pending",
|
|
|
|
fields: fields{
|
|
|
|
pending: []*PendingAttesterSlashing{
|
|
|
|
{
|
|
|
|
attesterSlashing: attesterSlashingForValIdx(1),
|
|
|
|
validatorToSlash: 1,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
included: make(map[uint64]bool),
|
|
|
|
},
|
|
|
|
args: args{
|
|
|
|
slashing: attesterSlashingForValIdx(3),
|
|
|
|
},
|
|
|
|
want: fields{
|
|
|
|
pending: []*PendingAttesterSlashing{
|
|
|
|
pendingSlashingForValIdx(1),
|
|
|
|
},
|
|
|
|
included: map[uint64]bool{
|
|
|
|
3: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Removes from pending list",
|
|
|
|
fields: fields{
|
|
|
|
pending: []*PendingAttesterSlashing{
|
|
|
|
pendingSlashingForValIdx(1),
|
|
|
|
pendingSlashingForValIdx(2),
|
|
|
|
pendingSlashingForValIdx(3),
|
|
|
|
},
|
|
|
|
included: map[uint64]bool{
|
|
|
|
0: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
args: args{
|
|
|
|
slashing: attesterSlashingForValIdx(2),
|
|
|
|
},
|
|
|
|
want: fields{
|
|
|
|
pending: []*PendingAttesterSlashing{
|
|
|
|
pendingSlashingForValIdx(1),
|
|
|
|
pendingSlashingForValIdx(3),
|
|
|
|
},
|
|
|
|
included: map[uint64]bool{
|
|
|
|
0: true,
|
|
|
|
2: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2020-03-03 05:52:35 +00:00
|
|
|
{
|
|
|
|
name: "Removes from long pending list",
|
|
|
|
fields: fields{
|
|
|
|
pending: []*PendingAttesterSlashing{
|
|
|
|
pendingSlashingForValIdx(1),
|
|
|
|
pendingSlashingForValIdx(2),
|
|
|
|
pendingSlashingForValIdx(3),
|
|
|
|
pendingSlashingForValIdx(4),
|
|
|
|
pendingSlashingForValIdx(5),
|
|
|
|
pendingSlashingForValIdx(6),
|
|
|
|
pendingSlashingForValIdx(7),
|
|
|
|
pendingSlashingForValIdx(8),
|
|
|
|
pendingSlashingForValIdx(9),
|
|
|
|
pendingSlashingForValIdx(10),
|
|
|
|
pendingSlashingForValIdx(11),
|
|
|
|
},
|
|
|
|
included: map[uint64]bool{
|
|
|
|
0: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
args: args{
|
|
|
|
slashing: attesterSlashingForValIdx(6),
|
|
|
|
},
|
|
|
|
want: fields{
|
|
|
|
pending: []*PendingAttesterSlashing{
|
|
|
|
pendingSlashingForValIdx(1),
|
|
|
|
pendingSlashingForValIdx(2),
|
|
|
|
pendingSlashingForValIdx(3),
|
|
|
|
pendingSlashingForValIdx(4),
|
|
|
|
pendingSlashingForValIdx(5),
|
|
|
|
pendingSlashingForValIdx(7),
|
|
|
|
pendingSlashingForValIdx(8),
|
|
|
|
pendingSlashingForValIdx(9),
|
|
|
|
pendingSlashingForValIdx(10),
|
|
|
|
pendingSlashingForValIdx(11),
|
|
|
|
},
|
|
|
|
included: map[uint64]bool{
|
|
|
|
0: true,
|
|
|
|
6: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2020-02-07 02:32:51 +00:00
|
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
p := &Pool{
|
|
|
|
pendingAttesterSlashing: tt.fields.pending,
|
|
|
|
included: tt.fields.included,
|
|
|
|
}
|
|
|
|
p.MarkIncludedAttesterSlashing(tt.args.slashing)
|
2020-07-15 18:37:51 +00:00
|
|
|
assert.Equal(t, len(tt.want.pending), len(p.pendingAttesterSlashing))
|
2020-02-07 02:32:51 +00:00
|
|
|
for i := range p.pendingAttesterSlashing {
|
2020-07-15 18:37:51 +00:00
|
|
|
assert.DeepEqual(t, tt.want.pending[i], p.pendingAttesterSlashing[i])
|
2020-02-07 02:32:51 +00:00
|
|
|
}
|
2020-07-15 18:37:51 +00:00
|
|
|
assert.DeepEqual(t, tt.want.included, p.included)
|
2020-02-07 02:32:51 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestPool_PendingAttesterSlashings(t *testing.T) {
|
|
|
|
type fields struct {
|
|
|
|
pending []*PendingAttesterSlashing
|
|
|
|
}
|
2020-05-05 08:39:38 +00:00
|
|
|
params.SetupTestConfigCleanup(t)
|
2020-03-12 01:16:55 +00:00
|
|
|
beaconState, privKeys := testutil.DeterministicGenesisState(t, 64)
|
|
|
|
pendingSlashings := make([]*PendingAttesterSlashing, 20)
|
|
|
|
slashings := make([]*ethpb.AttesterSlashing, 20)
|
|
|
|
for i := 0; i < len(pendingSlashings); i++ {
|
|
|
|
sl, err := testutil.GenerateAttesterSlashingForValidator(beaconState, privKeys[i], uint64(i))
|
2020-07-15 18:37:51 +00:00
|
|
|
require.NoError(t, err)
|
2020-03-12 01:16:55 +00:00
|
|
|
pendingSlashings[i] = &PendingAttesterSlashing{
|
|
|
|
attesterSlashing: sl,
|
|
|
|
validatorToSlash: uint64(i),
|
|
|
|
}
|
|
|
|
slashings[i] = sl
|
|
|
|
}
|
2020-02-07 02:32:51 +00:00
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
fields fields
|
|
|
|
want []*ethpb.AttesterSlashing
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "Empty list",
|
|
|
|
fields: fields{
|
|
|
|
pending: []*PendingAttesterSlashing{},
|
|
|
|
},
|
|
|
|
want: []*ethpb.AttesterSlashing{},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "All eligible",
|
|
|
|
fields: fields{
|
2020-03-12 01:16:55 +00:00
|
|
|
pending: pendingSlashings,
|
2020-02-07 02:32:51 +00:00
|
|
|
},
|
2020-06-09 22:40:48 +00:00
|
|
|
want: slashings[0:2],
|
2020-02-07 02:32:51 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Multiple indices",
|
|
|
|
fields: fields{
|
2020-03-12 01:16:55 +00:00
|
|
|
pending: pendingSlashings[3:6],
|
2020-02-07 02:32:51 +00:00
|
|
|
},
|
2020-06-09 22:40:48 +00:00
|
|
|
want: slashings[3:5],
|
2020-02-07 02:32:51 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
p := &Pool{
|
|
|
|
pendingAttesterSlashing: tt.fields.pending,
|
|
|
|
}
|
2020-03-12 01:16:55 +00:00
|
|
|
if got := p.PendingAttesterSlashings(
|
2020-05-14 17:11:28 +00:00
|
|
|
context.Background(), beaconState,
|
2020-03-12 01:16:55 +00:00
|
|
|
); !reflect.DeepEqual(tt.want, got) {
|
2020-02-07 02:32:51 +00:00
|
|
|
t.Errorf("Unexpected return from PendingAttesterSlashings, wanted %v, received %v", tt.want, got)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-14 17:11:28 +00:00
|
|
|
func TestPool_PendingAttesterSlashings_Slashed(t *testing.T) {
|
|
|
|
type fields struct {
|
|
|
|
pending []*PendingAttesterSlashing
|
|
|
|
}
|
|
|
|
params.SetupTestConfigCleanup(t)
|
|
|
|
conf := params.BeaconConfig()
|
|
|
|
conf.MaxAttesterSlashings = 2
|
|
|
|
params.OverrideBeaconConfig(conf)
|
|
|
|
beaconState, privKeys := testutil.DeterministicGenesisState(t, 64)
|
|
|
|
val, err := beaconState.ValidatorAtIndex(0)
|
2020-07-15 18:37:51 +00:00
|
|
|
require.NoError(t, err)
|
2020-05-14 17:11:28 +00:00
|
|
|
val.Slashed = true
|
|
|
|
if err := beaconState.UpdateValidatorAtIndex(0, val); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
val, err = beaconState.ValidatorAtIndex(3)
|
2020-07-15 18:37:51 +00:00
|
|
|
require.NoError(t, err)
|
2020-05-14 17:11:28 +00:00
|
|
|
val.Slashed = true
|
|
|
|
if err := beaconState.UpdateValidatorAtIndex(3, val); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
val, err = beaconState.ValidatorAtIndex(5)
|
2020-07-15 18:37:51 +00:00
|
|
|
require.NoError(t, err)
|
2020-05-14 17:11:28 +00:00
|
|
|
val.Slashed = true
|
|
|
|
if err := beaconState.UpdateValidatorAtIndex(5, val); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
pendingSlashings := make([]*PendingAttesterSlashing, 20)
|
|
|
|
slashings := make([]*ethpb.AttesterSlashing, 20)
|
|
|
|
for i := 0; i < len(pendingSlashings); i++ {
|
|
|
|
sl, err := testutil.GenerateAttesterSlashingForValidator(beaconState, privKeys[i], uint64(i))
|
2020-07-15 18:37:51 +00:00
|
|
|
require.NoError(t, err)
|
2020-05-14 17:11:28 +00:00
|
|
|
pendingSlashings[i] = &PendingAttesterSlashing{
|
|
|
|
attesterSlashing: sl,
|
|
|
|
validatorToSlash: uint64(i),
|
|
|
|
}
|
|
|
|
slashings[i] = sl
|
|
|
|
}
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
fields fields
|
|
|
|
want []*ethpb.AttesterSlashing
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "Skips slashed validator",
|
|
|
|
fields: fields{
|
|
|
|
pending: pendingSlashings,
|
|
|
|
},
|
|
|
|
want: slashings[1:3],
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Skips gapped slashed validators",
|
|
|
|
fields: fields{
|
|
|
|
pending: pendingSlashings[2:],
|
|
|
|
},
|
|
|
|
want: []*ethpb.AttesterSlashing{slashings[4], slashings[6]},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
p := &Pool{pendingAttesterSlashing: tt.fields.pending}
|
|
|
|
if got := p.PendingAttesterSlashings(context.Background(), beaconState); !reflect.DeepEqual(tt.want, got) {
|
|
|
|
t.Errorf("Unexpected return from PendingAttesterSlashings, \nwanted %v, \nreceived %v", tt.want, got)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-12 01:16:55 +00:00
|
|
|
func TestPool_PendingAttesterSlashings_NoDuplicates(t *testing.T) {
|
2020-05-05 08:39:38 +00:00
|
|
|
params.SetupTestConfigCleanup(t)
|
2020-02-07 02:32:51 +00:00
|
|
|
conf := params.BeaconConfig()
|
|
|
|
conf.MaxAttesterSlashings = 2
|
|
|
|
params.OverrideBeaconConfig(conf)
|
2020-03-12 01:16:55 +00:00
|
|
|
beaconState, privKeys := testutil.DeterministicGenesisState(t, 64)
|
|
|
|
pendingSlashings := make([]*PendingAttesterSlashing, 3)
|
|
|
|
slashings := make([]*ethpb.AttesterSlashing, 3)
|
|
|
|
for i := 0; i < 2; i++ {
|
|
|
|
sl, err := testutil.GenerateAttesterSlashingForValidator(beaconState, privKeys[i], uint64(i))
|
2020-07-15 18:37:51 +00:00
|
|
|
require.NoError(t, err)
|
2020-03-12 01:16:55 +00:00
|
|
|
pendingSlashings[i] = &PendingAttesterSlashing{
|
|
|
|
attesterSlashing: sl,
|
|
|
|
validatorToSlash: uint64(i),
|
|
|
|
}
|
|
|
|
slashings[i] = sl
|
2020-02-07 02:32:51 +00:00
|
|
|
}
|
2020-03-12 01:16:55 +00:00
|
|
|
// We duplicate the last slashing.
|
|
|
|
pendingSlashings[2] = pendingSlashings[1]
|
|
|
|
slashings[2] = slashings[1]
|
|
|
|
p := &Pool{
|
|
|
|
pendingAttesterSlashing: pendingSlashings,
|
2020-02-07 02:32:51 +00:00
|
|
|
}
|
2020-03-12 01:16:55 +00:00
|
|
|
want := slashings[0:2]
|
|
|
|
if got := p.PendingAttesterSlashings(
|
2020-05-14 17:11:28 +00:00
|
|
|
context.Background(), beaconState,
|
2020-03-12 01:16:55 +00:00
|
|
|
); !reflect.DeepEqual(want, got) {
|
|
|
|
t.Errorf("Unexpected return from PendingAttesterSlashings, wanted %v, received %v", want, got)
|
2020-02-07 02:32:51 +00:00
|
|
|
}
|
|
|
|
}
|