github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/sync/validate_attester_slashing_test.go (about)

     1  package sync
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"math/rand"
     7  	"reflect"
     8  	"testing"
     9  	"time"
    10  
    11  	pubsub "github.com/libp2p/go-libp2p-pubsub"
    12  	pubsubpb "github.com/libp2p/go-libp2p-pubsub/pb"
    13  	types "github.com/prysmaticlabs/eth2-types"
    14  	mock "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
    15  	"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
    16  	"github.com/prysmaticlabs/prysm/beacon-chain/p2p"
    17  	p2ptest "github.com/prysmaticlabs/prysm/beacon-chain/p2p/testing"
    18  	iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
    19  	mockSync "github.com/prysmaticlabs/prysm/beacon-chain/sync/initial-sync/testing"
    20  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    21  	"github.com/prysmaticlabs/prysm/shared/bls"
    22  	"github.com/prysmaticlabs/prysm/shared/params"
    23  	"github.com/prysmaticlabs/prysm/shared/testutil"
    24  	"github.com/prysmaticlabs/prysm/shared/testutil/assert"
    25  	"github.com/prysmaticlabs/prysm/shared/testutil/require"
    26  )
    27  
    28  func setupValidAttesterSlashing(t *testing.T) (*ethpb.AttesterSlashing, iface.BeaconState) {
    29  	state, privKeys := testutil.DeterministicGenesisState(t, 5)
    30  	vals := state.Validators()
    31  	for _, vv := range vals {
    32  		vv.WithdrawableEpoch = types.Epoch(1 * params.BeaconConfig().SlotsPerEpoch)
    33  	}
    34  	require.NoError(t, state.SetValidators(vals))
    35  
    36  	att1 := testutil.HydrateIndexedAttestation(&ethpb.IndexedAttestation{
    37  		Data: &ethpb.AttestationData{
    38  			Source: &ethpb.Checkpoint{Epoch: 1},
    39  		},
    40  		AttestingIndices: []uint64{0, 1},
    41  	})
    42  	domain, err := helpers.Domain(state.Fork(), 0, params.BeaconConfig().DomainBeaconAttester, state.GenesisValidatorRoot())
    43  	require.NoError(t, err)
    44  	hashTreeRoot, err := helpers.ComputeSigningRoot(att1.Data, domain)
    45  	assert.NoError(t, err)
    46  	sig0 := privKeys[0].Sign(hashTreeRoot[:])
    47  	sig1 := privKeys[1].Sign(hashTreeRoot[:])
    48  	aggregateSig := bls.AggregateSignatures([]bls.Signature{sig0, sig1})
    49  	att1.Signature = aggregateSig.Marshal()
    50  
    51  	att2 := testutil.HydrateIndexedAttestation(&ethpb.IndexedAttestation{
    52  		AttestingIndices: []uint64{0, 1},
    53  	})
    54  	hashTreeRoot, err = helpers.ComputeSigningRoot(att2.Data, domain)
    55  	assert.NoError(t, err)
    56  	sig0 = privKeys[0].Sign(hashTreeRoot[:])
    57  	sig1 = privKeys[1].Sign(hashTreeRoot[:])
    58  	aggregateSig = bls.AggregateSignatures([]bls.Signature{sig0, sig1})
    59  	att2.Signature = aggregateSig.Marshal()
    60  
    61  	slashing := &ethpb.AttesterSlashing{
    62  		Attestation_1: att1,
    63  		Attestation_2: att2,
    64  	}
    65  
    66  	currentSlot := 2 * params.BeaconConfig().SlotsPerEpoch
    67  	require.NoError(t, state.SetSlot(currentSlot))
    68  
    69  	b := make([]byte, 32)
    70  	_, err = rand.Read(b)
    71  	require.NoError(t, err)
    72  
    73  	return slashing, state
    74  }
    75  
    76  func TestValidateAttesterSlashing_ValidSlashing(t *testing.T) {
    77  	p := p2ptest.NewTestP2P(t)
    78  	ctx := context.Background()
    79  
    80  	slashing, s := setupValidAttesterSlashing(t)
    81  
    82  	r := &Service{
    83  		cfg: &Config{
    84  			P2P:         p,
    85  			Chain:       &mock.ChainService{State: s},
    86  			InitialSync: &mockSync.Sync{IsSyncing: false},
    87  		},
    88  		seenAttesterSlashingCache: make(map[uint64]bool),
    89  	}
    90  
    91  	buf := new(bytes.Buffer)
    92  	_, err := p.Encoding().EncodeGossip(buf, slashing)
    93  	require.NoError(t, err)
    94  
    95  	topic := p2p.GossipTypeMapping[reflect.TypeOf(slashing)]
    96  	msg := &pubsub.Message{
    97  		Message: &pubsubpb.Message{
    98  			Data:  buf.Bytes(),
    99  			Topic: &topic,
   100  		},
   101  	}
   102  	valid := r.validateAttesterSlashing(ctx, "foobar", msg) == pubsub.ValidationAccept
   103  
   104  	assert.Equal(t, true, valid, "Failed Validation")
   105  	assert.NotNil(t, msg.ValidatorData, "Decoded message was not set on the message validator data")
   106  }
   107  
   108  func TestValidateAttesterSlashing_CanFilter(t *testing.T) {
   109  	p := p2ptest.NewTestP2P(t)
   110  	ctx := context.Background()
   111  
   112  	r := &Service{
   113  		cfg: &Config{
   114  			P2P:         p,
   115  			InitialSync: &mockSync.Sync{IsSyncing: false},
   116  		},
   117  		seenAttesterSlashingCache: make(map[uint64]bool),
   118  	}
   119  
   120  	r.setAttesterSlashingIndicesSeen([]uint64{1, 2, 3, 4}, []uint64{3, 4, 5, 6})
   121  
   122  	// The below attestations should be filtered hence bad signature is ok.
   123  	topic := p2p.GossipTypeMapping[reflect.TypeOf(&ethpb.AttesterSlashing{})]
   124  	buf := new(bytes.Buffer)
   125  	_, err := p.Encoding().EncodeGossip(buf, &ethpb.AttesterSlashing{
   126  		Attestation_1: testutil.HydrateIndexedAttestation(&ethpb.IndexedAttestation{
   127  			AttestingIndices: []uint64{3},
   128  		}),
   129  		Attestation_2: testutil.HydrateIndexedAttestation(&ethpb.IndexedAttestation{
   130  			AttestingIndices: []uint64{3},
   131  		}),
   132  	})
   133  	require.NoError(t, err)
   134  	msg := &pubsub.Message{
   135  		Message: &pubsubpb.Message{
   136  			Data:  buf.Bytes(),
   137  			Topic: &topic,
   138  		},
   139  	}
   140  	ignored := r.validateAttesterSlashing(ctx, "foobar", msg) == pubsub.ValidationIgnore
   141  	assert.Equal(t, true, ignored)
   142  
   143  	buf = new(bytes.Buffer)
   144  	_, err = p.Encoding().EncodeGossip(buf, &ethpb.AttesterSlashing{
   145  		Attestation_1: testutil.HydrateIndexedAttestation(&ethpb.IndexedAttestation{
   146  			AttestingIndices: []uint64{4, 3},
   147  		}),
   148  		Attestation_2: testutil.HydrateIndexedAttestation(&ethpb.IndexedAttestation{
   149  			AttestingIndices: []uint64{3, 4},
   150  		}),
   151  	})
   152  	require.NoError(t, err)
   153  	msg = &pubsub.Message{
   154  		Message: &pubsubpb.Message{
   155  			Data:  buf.Bytes(),
   156  			Topic: &topic,
   157  		},
   158  	}
   159  	ignored = r.validateAttesterSlashing(ctx, "foobar", msg) == pubsub.ValidationIgnore
   160  	assert.Equal(t, true, ignored)
   161  }
   162  
   163  func TestValidateAttesterSlashing_ContextTimeout(t *testing.T) {
   164  	p := p2ptest.NewTestP2P(t)
   165  
   166  	slashing, state := setupValidAttesterSlashing(t)
   167  	slashing.Attestation_1.Data.Target.Epoch = 100000000
   168  
   169  	ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
   170  	defer cancel()
   171  
   172  	r := &Service{
   173  		cfg: &Config{
   174  			P2P:         p,
   175  			Chain:       &mock.ChainService{State: state},
   176  			InitialSync: &mockSync.Sync{IsSyncing: false},
   177  		},
   178  		seenAttesterSlashingCache: make(map[uint64]bool),
   179  	}
   180  
   181  	buf := new(bytes.Buffer)
   182  	_, err := p.Encoding().EncodeGossip(buf, slashing)
   183  	require.NoError(t, err)
   184  
   185  	topic := p2p.GossipTypeMapping[reflect.TypeOf(slashing)]
   186  	msg := &pubsub.Message{
   187  		Message: &pubsubpb.Message{
   188  			Data:  buf.Bytes(),
   189  			Topic: &topic,
   190  		},
   191  	}
   192  	valid := r.validateAttesterSlashing(ctx, "", msg) == pubsub.ValidationAccept
   193  	assert.Equal(t, false, valid, "slashing from the far distant future should have timed out and returned false")
   194  }
   195  
   196  func TestValidateAttesterSlashing_Syncing(t *testing.T) {
   197  	p := p2ptest.NewTestP2P(t)
   198  	ctx := context.Background()
   199  
   200  	slashing, s := setupValidAttesterSlashing(t)
   201  
   202  	r := &Service{
   203  		cfg: &Config{
   204  			P2P:         p,
   205  			Chain:       &mock.ChainService{State: s},
   206  			InitialSync: &mockSync.Sync{IsSyncing: true},
   207  		},
   208  	}
   209  
   210  	buf := new(bytes.Buffer)
   211  	_, err := p.Encoding().EncodeGossip(buf, slashing)
   212  	require.NoError(t, err)
   213  
   214  	topic := p2p.GossipTypeMapping[reflect.TypeOf(slashing)]
   215  	msg := &pubsub.Message{
   216  		Message: &pubsubpb.Message{
   217  			Data:  buf.Bytes(),
   218  			Topic: &topic,
   219  		},
   220  	}
   221  	valid := r.validateAttesterSlashing(ctx, "", msg) == pubsub.ValidationAccept
   222  	assert.Equal(t, false, valid, "Passed validation")
   223  }
   224  
   225  func TestSeenAttesterSlashingIndices(t *testing.T) {
   226  	tt := []struct {
   227  		saveIndices1  []uint64
   228  		saveIndices2  []uint64
   229  		checkIndices1 []uint64
   230  		checkIndices2 []uint64
   231  		seen          bool
   232  	}{
   233  		{
   234  			saveIndices1:  []uint64{0, 1, 2},
   235  			saveIndices2:  []uint64{0},
   236  			checkIndices1: []uint64{0, 1, 2},
   237  			checkIndices2: []uint64{0},
   238  			seen:          true,
   239  		},
   240  		{
   241  			saveIndices1:  []uint64{100, 99, 98},
   242  			saveIndices2:  []uint64{99, 98, 97},
   243  			checkIndices1: []uint64{99, 98},
   244  			checkIndices2: []uint64{99, 98},
   245  			seen:          true,
   246  		},
   247  		{
   248  			saveIndices1:  []uint64{100},
   249  			saveIndices2:  []uint64{100},
   250  			checkIndices1: []uint64{100, 101},
   251  			checkIndices2: []uint64{100, 101},
   252  			seen:          false,
   253  		},
   254  		{
   255  			saveIndices1:  []uint64{100, 99, 98},
   256  			saveIndices2:  []uint64{99, 98, 97},
   257  			checkIndices1: []uint64{99, 98, 97},
   258  			checkIndices2: []uint64{99, 98, 97},
   259  			seen:          false,
   260  		},
   261  		{
   262  			saveIndices1:  []uint64{100, 99, 98},
   263  			saveIndices2:  []uint64{99, 98, 97},
   264  			checkIndices1: []uint64{101, 100},
   265  			checkIndices2: []uint64{101},
   266  			seen:          false,
   267  		},
   268  	}
   269  	for _, tc := range tt {
   270  		r := &Service{
   271  			seenAttesterSlashingCache: map[uint64]bool{},
   272  		}
   273  		r.setAttesterSlashingIndicesSeen(tc.saveIndices1, tc.saveIndices2)
   274  		assert.Equal(t, tc.seen, r.hasSeenAttesterSlashingIndices(tc.checkIndices1, tc.checkIndices2))
   275  	}
   276  }