mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-29 06:37:17 +00:00
b5c4dc2a75
* init-sync updates * slasher/db/kv tests * beacon-chain/rpc/beacon tests * update kv_test * beacon-chain/rpc-validator tests updated * slasher/db/kv - remove teardown method * beacon-chain/sync tests updated * beacon-chain/db/kv tests updated * beacon-chain/blockchain tests updated * beacon-chain/state/stategen tests updated * beacon-chain/powchain updates * updates rest of slasher tests * validator/db tests * rest of the tests * minor comments update * gazelle * Merge refs/heads/master into teardowndb-to-cleanup
421 lines
12 KiB
Go
421 lines
12 KiB
Go
package detection
|
|
|
|
import (
|
|
"context"
|
|
"reflect"
|
|
"testing"
|
|
|
|
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
|
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
|
testDB "github.com/prysmaticlabs/prysm/slasher/db/testing"
|
|
status "github.com/prysmaticlabs/prysm/slasher/db/types"
|
|
"github.com/prysmaticlabs/prysm/slasher/detection/attestations"
|
|
"github.com/prysmaticlabs/prysm/slasher/detection/proposals"
|
|
testDetect "github.com/prysmaticlabs/prysm/slasher/detection/testing"
|
|
)
|
|
|
|
func TestDetect_detectAttesterSlashings_Surround(t *testing.T) {
|
|
type testStruct struct {
|
|
name string
|
|
savedAtts []*ethpb.IndexedAttestation
|
|
incomingAtt *ethpb.IndexedAttestation
|
|
slashingsFound int
|
|
}
|
|
tests := []testStruct{
|
|
{
|
|
name: "surrounding vote detected should report a slashing",
|
|
savedAtts: []*ethpb.IndexedAttestation{
|
|
{
|
|
AttestingIndices: []uint64{3},
|
|
Data: ðpb.AttestationData{
|
|
Source: ðpb.Checkpoint{Epoch: 9},
|
|
Target: ðpb.Checkpoint{Epoch: 13},
|
|
},
|
|
Signature: bytesutil.PadTo([]byte{1, 2}, 96),
|
|
},
|
|
},
|
|
incomingAtt: ðpb.IndexedAttestation{
|
|
AttestingIndices: []uint64{1, 3, 7},
|
|
Data: ðpb.AttestationData{
|
|
Source: ðpb.Checkpoint{Epoch: 7},
|
|
Target: ðpb.Checkpoint{Epoch: 14},
|
|
},
|
|
},
|
|
slashingsFound: 1,
|
|
},
|
|
{
|
|
name: "surrounded vote detected should report a slashing",
|
|
savedAtts: []*ethpb.IndexedAttestation{
|
|
{
|
|
AttestingIndices: []uint64{0, 2, 4, 8},
|
|
Data: ðpb.AttestationData{
|
|
Source: ðpb.Checkpoint{Epoch: 6},
|
|
Target: ðpb.Checkpoint{Epoch: 10},
|
|
},
|
|
Signature: bytesutil.PadTo([]byte{1, 2}, 96),
|
|
},
|
|
},
|
|
incomingAtt: ðpb.IndexedAttestation{
|
|
AttestingIndices: []uint64{0, 4},
|
|
Data: ðpb.AttestationData{
|
|
Source: ðpb.Checkpoint{Epoch: 7},
|
|
Target: ðpb.Checkpoint{Epoch: 9},
|
|
},
|
|
},
|
|
slashingsFound: 1,
|
|
},
|
|
{
|
|
name: "2 different surrounded votes detected should report 2 slashings",
|
|
savedAtts: []*ethpb.IndexedAttestation{
|
|
{
|
|
AttestingIndices: []uint64{0, 2},
|
|
Data: ðpb.AttestationData{
|
|
Source: ðpb.Checkpoint{Epoch: 4},
|
|
Target: ðpb.Checkpoint{Epoch: 5},
|
|
},
|
|
Signature: bytesutil.PadTo([]byte{1, 2}, 96),
|
|
},
|
|
{
|
|
AttestingIndices: []uint64{4, 8},
|
|
Data: ðpb.AttestationData{
|
|
Source: ðpb.Checkpoint{Epoch: 3},
|
|
Target: ðpb.Checkpoint{Epoch: 4},
|
|
},
|
|
Signature: bytesutil.PadTo([]byte{1, 3}, 96),
|
|
},
|
|
},
|
|
incomingAtt: ðpb.IndexedAttestation{
|
|
AttestingIndices: []uint64{0, 4},
|
|
Data: ðpb.AttestationData{
|
|
Source: ðpb.Checkpoint{Epoch: 2},
|
|
Target: ðpb.Checkpoint{Epoch: 7},
|
|
},
|
|
},
|
|
slashingsFound: 2,
|
|
},
|
|
{
|
|
name: "2 different surrounding votes detected should report 2 slashings",
|
|
savedAtts: []*ethpb.IndexedAttestation{
|
|
{
|
|
AttestingIndices: []uint64{0, 2},
|
|
Data: ðpb.AttestationData{
|
|
Source: ðpb.Checkpoint{Epoch: 4},
|
|
Target: ðpb.Checkpoint{Epoch: 10},
|
|
},
|
|
Signature: bytesutil.PadTo([]byte{1, 2}, 96),
|
|
},
|
|
{
|
|
AttestingIndices: []uint64{4, 8},
|
|
Data: ðpb.AttestationData{
|
|
Source: ðpb.Checkpoint{Epoch: 5},
|
|
Target: ðpb.Checkpoint{Epoch: 9},
|
|
},
|
|
Signature: bytesutil.PadTo([]byte{1, 3}, 96),
|
|
},
|
|
},
|
|
incomingAtt: ðpb.IndexedAttestation{
|
|
AttestingIndices: []uint64{0, 4},
|
|
Data: ðpb.AttestationData{
|
|
Source: ðpb.Checkpoint{Epoch: 7},
|
|
Target: ðpb.Checkpoint{Epoch: 8},
|
|
},
|
|
},
|
|
slashingsFound: 2,
|
|
},
|
|
{
|
|
name: "no slashable detected should not report a slashing",
|
|
savedAtts: []*ethpb.IndexedAttestation{
|
|
{
|
|
AttestingIndices: []uint64{0},
|
|
Data: ðpb.AttestationData{
|
|
Source: ðpb.Checkpoint{Epoch: 1},
|
|
Target: ðpb.Checkpoint{Epoch: 2},
|
|
},
|
|
Signature: bytesutil.PadTo([]byte{1, 2}, 96),
|
|
},
|
|
},
|
|
incomingAtt: ðpb.IndexedAttestation{
|
|
AttestingIndices: []uint64{0},
|
|
Data: ðpb.AttestationData{
|
|
Source: ðpb.Checkpoint{Epoch: 0},
|
|
Target: ðpb.Checkpoint{Epoch: 1},
|
|
},
|
|
},
|
|
slashingsFound: 0,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
db := testDB.SetupSlasherDB(t, false)
|
|
ctx := context.Background()
|
|
ds := Service{
|
|
ctx: ctx,
|
|
slasherDB: db,
|
|
minMaxSpanDetector: attestations.NewSpanDetector(db),
|
|
}
|
|
if err := db.SaveIndexedAttestations(ctx, tt.savedAtts); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, att := range tt.savedAtts {
|
|
if err := ds.minMaxSpanDetector.UpdateSpans(ctx, att); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
slashings, err := ds.DetectAttesterSlashings(ctx, tt.incomingAtt)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(slashings) != tt.slashingsFound {
|
|
t.Fatalf("Unexpected amount of slashings found, received %d, expected %d", len(slashings), tt.slashingsFound)
|
|
}
|
|
attsl, err := db.AttesterSlashings(ctx, status.Active)
|
|
if len(attsl) != tt.slashingsFound {
|
|
t.Fatalf("Didnt save slashing to db")
|
|
}
|
|
for _, ss := range slashings {
|
|
slashingAtt1 := ss.Attestation_1
|
|
slashingAtt2 := ss.Attestation_2
|
|
if !isSurrounding(slashingAtt1, slashingAtt2) {
|
|
t.Fatalf(
|
|
"Expected slashing to be valid, received atts %d->%d and %d->%d",
|
|
slashingAtt2.Data.Source.Epoch,
|
|
slashingAtt2.Data.Target.Epoch,
|
|
slashingAtt1.Data.Source.Epoch,
|
|
slashingAtt1.Data.Target.Epoch,
|
|
)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDetect_detectAttesterSlashings_Double(t *testing.T) {
|
|
type testStruct struct {
|
|
name string
|
|
savedAtts []*ethpb.IndexedAttestation
|
|
incomingAtt *ethpb.IndexedAttestation
|
|
slashingsFound int
|
|
}
|
|
tests := []testStruct{
|
|
{
|
|
name: "different source, same target, should report a slashing",
|
|
savedAtts: []*ethpb.IndexedAttestation{
|
|
{
|
|
AttestingIndices: []uint64{3},
|
|
Data: ðpb.AttestationData{
|
|
Source: ðpb.Checkpoint{Epoch: 3},
|
|
Target: ðpb.Checkpoint{Epoch: 4},
|
|
},
|
|
Signature: bytesutil.PadTo([]byte{1, 2}, 96),
|
|
},
|
|
},
|
|
incomingAtt: ðpb.IndexedAttestation{
|
|
AttestingIndices: []uint64{1, 3, 7},
|
|
Data: ðpb.AttestationData{
|
|
Source: ðpb.Checkpoint{Epoch: 2},
|
|
Target: ðpb.Checkpoint{Epoch: 4},
|
|
},
|
|
Signature: bytesutil.PadTo([]byte{1, 2}, 96),
|
|
},
|
|
slashingsFound: 1,
|
|
},
|
|
{
|
|
name: "different histories, same target, should report 2 slashings",
|
|
savedAtts: []*ethpb.IndexedAttestation{
|
|
{
|
|
AttestingIndices: []uint64{1},
|
|
Data: ðpb.AttestationData{
|
|
Source: ðpb.Checkpoint{Epoch: 3},
|
|
Target: ðpb.Checkpoint{Epoch: 4},
|
|
},
|
|
Signature: bytesutil.PadTo([]byte{1, 2}, 96),
|
|
},
|
|
{
|
|
AttestingIndices: []uint64{3},
|
|
Data: ðpb.AttestationData{
|
|
Source: ðpb.Checkpoint{Epoch: 1},
|
|
Target: ðpb.Checkpoint{Epoch: 4},
|
|
},
|
|
Signature: bytesutil.PadTo([]byte{1, 3}, 96),
|
|
},
|
|
},
|
|
incomingAtt: ðpb.IndexedAttestation{
|
|
AttestingIndices: []uint64{1, 3, 7},
|
|
Data: ðpb.AttestationData{
|
|
Source: ðpb.Checkpoint{Epoch: 2},
|
|
Target: ðpb.Checkpoint{Epoch: 4},
|
|
},
|
|
Signature: bytesutil.PadTo([]byte{1, 4}, 96),
|
|
},
|
|
slashingsFound: 2,
|
|
},
|
|
{
|
|
name: "same source and target, different block root, should report a slashing ",
|
|
savedAtts: []*ethpb.IndexedAttestation{
|
|
{
|
|
AttestingIndices: []uint64{0, 2, 4, 8},
|
|
Data: ðpb.AttestationData{
|
|
Source: ðpb.Checkpoint{Epoch: 2},
|
|
Target: ðpb.Checkpoint{Epoch: 4},
|
|
BeaconBlockRoot: bytesutil.PadTo([]byte("good block root"), 32),
|
|
},
|
|
Signature: bytesutil.PadTo([]byte{1, 2}, 96),
|
|
},
|
|
},
|
|
incomingAtt: ðpb.IndexedAttestation{
|
|
AttestingIndices: []uint64{0, 4},
|
|
Data: ðpb.AttestationData{
|
|
Source: ðpb.Checkpoint{Epoch: 2},
|
|
Target: ðpb.Checkpoint{Epoch: 4},
|
|
BeaconBlockRoot: bytesutil.PadTo([]byte("bad block root"), 32),
|
|
},
|
|
},
|
|
slashingsFound: 1,
|
|
},
|
|
{
|
|
name: "same attestation should not report double",
|
|
savedAtts: []*ethpb.IndexedAttestation{
|
|
{
|
|
AttestingIndices: []uint64{0},
|
|
Data: ðpb.AttestationData{
|
|
Source: ðpb.Checkpoint{Epoch: 0},
|
|
Target: ðpb.Checkpoint{Epoch: 2},
|
|
BeaconBlockRoot: bytesutil.PadTo([]byte("good block root"), 32),
|
|
},
|
|
Signature: bytesutil.PadTo([]byte{1, 2}, 96),
|
|
},
|
|
},
|
|
incomingAtt: ðpb.IndexedAttestation{
|
|
AttestingIndices: []uint64{0},
|
|
Data: ðpb.AttestationData{
|
|
Source: ðpb.Checkpoint{Epoch: 0},
|
|
Target: ðpb.Checkpoint{Epoch: 2},
|
|
BeaconBlockRoot: bytesutil.PadTo([]byte("good block root"), 32),
|
|
},
|
|
},
|
|
slashingsFound: 0,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
db := testDB.SetupSlasherDB(t, false)
|
|
ctx := context.Background()
|
|
ds := Service{
|
|
ctx: ctx,
|
|
slasherDB: db,
|
|
minMaxSpanDetector: attestations.NewSpanDetector(db),
|
|
}
|
|
if err := db.SaveIndexedAttestations(ctx, tt.savedAtts); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, att := range tt.savedAtts {
|
|
if err := ds.minMaxSpanDetector.UpdateSpans(ctx, att); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
slashings, err := ds.DetectAttesterSlashings(ctx, tt.incomingAtt)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(slashings) != tt.slashingsFound {
|
|
t.Fatalf("Unexpected amount of slashings found, received %d, expected %d", len(slashings), tt.slashingsFound)
|
|
}
|
|
savedSlashings, err := db.AttesterSlashings(ctx, status.Active)
|
|
if len(savedSlashings) != tt.slashingsFound {
|
|
t.Fatalf("Did not save slashing to db")
|
|
}
|
|
|
|
for _, ss := range slashings {
|
|
slashingAtt1 := ss.Attestation_1
|
|
slashingAtt2 := ss.Attestation_2
|
|
if !isDoubleVote(slashingAtt1, slashingAtt2) {
|
|
t.Fatalf(
|
|
"Expected slashing to be valid, received atts with target epoch %d and %d but not valid",
|
|
slashingAtt2.Data.Target.Epoch,
|
|
slashingAtt1.Data.Target.Epoch,
|
|
)
|
|
}
|
|
}
|
|
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDetect_detectProposerSlashing(t *testing.T) {
|
|
type testStruct struct {
|
|
name string
|
|
blk *ethpb.SignedBeaconBlockHeader
|
|
incomingBlk *ethpb.SignedBeaconBlockHeader
|
|
slashing *ethpb.ProposerSlashing
|
|
}
|
|
blk1slot0, err := testDetect.SignedBlockHeader(testDetect.StartSlot(0), 0)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
blk2slot0, err := testDetect.SignedBlockHeader(testDetect.StartSlot(0), 0)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
blk1epoch1, err := testDetect.SignedBlockHeader(testDetect.StartSlot(1), 0)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
tests := []testStruct{
|
|
{
|
|
name: "same block sig dont slash",
|
|
blk: blk1slot0,
|
|
incomingBlk: blk1slot0,
|
|
slashing: nil,
|
|
},
|
|
{
|
|
name: "block from different epoch dont slash",
|
|
blk: blk1slot0,
|
|
incomingBlk: blk1epoch1,
|
|
slashing: nil,
|
|
},
|
|
{
|
|
name: "different sig from same slot slash",
|
|
blk: blk1slot0,
|
|
incomingBlk: blk2slot0,
|
|
slashing: ðpb.ProposerSlashing{Header_1: blk2slot0, Header_2: blk1slot0},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
db := testDB.SetupSlasherDB(t, false)
|
|
ctx := context.Background()
|
|
ds := Service{
|
|
ctx: ctx,
|
|
slasherDB: db,
|
|
proposalsDetector: proposals.NewProposeDetector(db),
|
|
}
|
|
if err := db.SaveBlockHeader(ctx, tt.blk); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
slashing, err := ds.proposalsDetector.DetectDoublePropose(ctx, tt.incomingBlk)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !reflect.DeepEqual(slashing, tt.slashing) {
|
|
t.Errorf("Wanted: %v, received %v", tt.slashing, slashing)
|
|
}
|
|
savedSlashings, err := db.ProposalSlashingsByStatus(ctx, status.Active)
|
|
if tt.slashing != nil && len(savedSlashings) != 1 {
|
|
t.Fatalf("Did not save slashing to db")
|
|
}
|
|
|
|
if slashing != nil && !isDoublePropose(slashing.Header_1, slashing.Header_2) {
|
|
t.Fatalf(
|
|
"Expected slashing to be valid, received atts with target epoch %v and %v but not valid",
|
|
slashing.Header_1,
|
|
slashing.Header_2,
|
|
)
|
|
}
|
|
|
|
})
|
|
}
|
|
}
|