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(ðpb.IndexedAttestation{ 37 Data: ðpb.AttestationData{ 38 Source: ðpb.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(ðpb.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 := ðpb.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(ðpb.AttesterSlashing{})] 124 buf := new(bytes.Buffer) 125 _, err := p.Encoding().EncodeGossip(buf, ðpb.AttesterSlashing{ 126 Attestation_1: testutil.HydrateIndexedAttestation(ðpb.IndexedAttestation{ 127 AttestingIndices: []uint64{3}, 128 }), 129 Attestation_2: testutil.HydrateIndexedAttestation(ðpb.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, ðpb.AttesterSlashing{ 145 Attestation_1: testutil.HydrateIndexedAttestation(ðpb.IndexedAttestation{ 146 AttestingIndices: []uint64{4, 3}, 147 }), 148 Attestation_2: testutil.HydrateIndexedAttestation(ðpb.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 }