1
1
import pytest
2
+ from hypothesis import (
3
+ given ,
4
+ settings ,
5
+ strategies as st ,
6
+ )
2
7
3
8
from eth_utils import (
4
9
ValidationError ,
5
10
)
11
+
12
+ import rlp
13
+
6
14
from eth .constants import (
7
15
ZERO_HASH32 ,
8
16
)
9
17
18
+ from eth ._utils import bls
19
+ from eth ._utils .bitfield import (
20
+ get_empty_bitfield ,
21
+ )
22
+ from eth .beacon ._utils .hash import (
23
+ hash_eth2 ,
24
+ )
25
+ from eth .beacon .aggregation import (
26
+ aggregate_votes ,
27
+ )
28
+ from eth .beacon .enums import (
29
+ SignatureDomain ,
30
+ )
31
+ from eth .beacon .helpers import (
32
+ get_domain ,
33
+ )
10
34
from eth .beacon .state_machines .forks .serenity .validation import (
35
+ validate_serenity_attestation_aggregate_signature ,
11
36
validate_serenity_attestation_latest_crosslink_root ,
12
37
validate_serenity_attestation_justified_block_root ,
13
38
validate_serenity_attestation_justified_slot ,
14
39
validate_serenity_attestation_shard_block_root ,
15
40
validate_serenity_attestation_slot ,
16
41
)
17
- from eth .beacon .types .attestation_data import (
18
- AttestationData ,
19
- )
42
+ from eth .beacon .types .attestations import Attestation
43
+ from eth .beacon .types .attestation_data import AttestationData
44
+
45
+
46
+ def create_mock_signed_attestation (state ,
47
+ shard_committee ,
48
+ voting_committee_indices ,
49
+ attestation_data ,
50
+ privkeys ):
51
+ message = hash_eth2 (
52
+ rlp .encode (attestation_data ) +
53
+ (0 ).to_bytes (1 , "big" )
54
+ )
55
+ # participants sign message
56
+ signatures = [
57
+ bls .sign (
58
+ message ,
59
+ privkeys [shard_committee .committee [committee_index ]],
60
+ domain = get_domain (
61
+ fork_data = state .fork_data ,
62
+ slot = attestation_data .slot ,
63
+ domain_type = SignatureDomain .DOMAIN_ATTESTATION ,
64
+ )
65
+ )
66
+ for committee_index in voting_committee_indices
67
+ ]
68
+
69
+ # aggregate signatures and construct participant bitfield
70
+ participation_bitfield , aggregate_signature = aggregate_votes (
71
+ bitfield = get_empty_bitfield (len (shard_committee .committee )),
72
+ sigs = (),
73
+ voting_sigs = signatures ,
74
+ voting_committee_indices = voting_committee_indices ,
75
+ )
76
+
77
+ # create attestation from attestation_data, particpipant_bitfield, and signature
78
+ return Attestation (
79
+ data = attestation_data ,
80
+ participation_bitfield = participation_bitfield ,
81
+ custody_bitfield = b'' ,
82
+ aggregate_signature = aggregate_signature ,
83
+ )
20
84
21
85
22
86
@pytest .mark .parametrize (
@@ -151,7 +215,7 @@ def test_validate_serenity_attestation_justified_block_root(sample_attestation_d
151
215
(
152
216
'attestation_latest_crosslink_root,'
153
217
'attestation_shard_block_root,'
154
- 'latest_crosslink_shard_block_root ,'
218
+ 'latest_crosslink_root ,'
155
219
'is_valid,'
156
220
),
157
221
[
@@ -165,7 +229,7 @@ def test_validate_serenity_attestation_justified_block_root(sample_attestation_d
165
229
def test_validate_serenity_attestation_latest_crosslink_root (sample_attestation_data_params ,
166
230
attestation_latest_crosslink_root ,
167
231
attestation_shard_block_root ,
168
- latest_crosslink_shard_block_root ,
232
+ latest_crosslink_root ,
169
233
is_valid ):
170
234
sample_attestation_data_params ['latest_crosslink_root' ] = attestation_latest_crosslink_root
171
235
sample_attestation_data_params ['shard_block_root' ] = attestation_shard_block_root
@@ -177,13 +241,13 @@ def test_validate_serenity_attestation_latest_crosslink_root(sample_attestation_
177
241
if is_valid :
178
242
validate_serenity_attestation_latest_crosslink_root (
179
243
attestation_data ,
180
- latest_crosslink_shard_block_root ,
244
+ latest_crosslink_root ,
181
245
)
182
246
else :
183
247
with pytest .raises (ValidationError ):
184
248
validate_serenity_attestation_latest_crosslink_root (
185
249
attestation_data ,
186
- latest_crosslink_shard_block_root ,
250
+ latest_crosslink_root ,
187
251
)
188
252
189
253
@@ -216,5 +280,72 @@ def test_validate_serenity_attestation_shard_block_root(sample_attestation_data_
216
280
)
217
281
218
282
219
- def test_validate_serenity_attestation_aggregate_signature ():
220
- pass
283
+ @settings (max_examples = 1 )
284
+ @given (random = st .randoms ())
285
+ @pytest .mark .parametrize (
286
+ (
287
+ 'num_validators,'
288
+ 'epoch_length,'
289
+ 'target_committee_size,'
290
+ 'shard_count,'
291
+ 'is_valid,'
292
+ ),
293
+ [
294
+ (10 , 2 , 2 , 2 , True ),
295
+ (40 , 4 , 3 , 5 , True ),
296
+ (20 , 5 , 3 , 2 , True ),
297
+ (20 , 5 , 3 , 2 , False ),
298
+ (10 , 2 , 3 , 4 , False ),
299
+ ],
300
+ )
301
+ def test_validate_serenity_attestation_aggregate_signature (genesis_state ,
302
+ epoch_length ,
303
+ random ,
304
+ privkeys ,
305
+ sample_attestation_data_params ,
306
+ is_valid ):
307
+ state = genesis_state
308
+
309
+ # choose committee
310
+ slot = 0
311
+ shard_committee = state .shard_committees_at_slots [slot ][0 ]
312
+ committee_size = len (shard_committee .committee )
313
+
314
+ # randomly select 3/4 participants from committee
315
+ votes_count = len (shard_committee .committee ) * 3 // 4
316
+ voting_committee_indices = random .sample (range (committee_size ), votes_count )
317
+ assert len (voting_committee_indices ) > 0
318
+
319
+ attestation_data = AttestationData (** sample_attestation_data_params ).copy (
320
+ slot = slot ,
321
+ shard = shard_committee .shard ,
322
+ )
323
+
324
+ attestation = create_mock_signed_attestation (
325
+ state ,
326
+ shard_committee ,
327
+ voting_committee_indices ,
328
+ attestation_data ,
329
+ privkeys ,
330
+ )
331
+
332
+ if is_valid :
333
+ validate_serenity_attestation_aggregate_signature (
334
+ state ,
335
+ attestation ,
336
+ epoch_length ,
337
+ )
338
+ else :
339
+ # mess up signature
340
+ attestation = attestation .copy (
341
+ aggregate_signature = (
342
+ attestation .aggregate_signature [0 ] + 10 ,
343
+ attestation .aggregate_signature [1 ] - 1
344
+ )
345
+ )
346
+ with pytest .raises (ValidationError ):
347
+ validate_serenity_attestation_aggregate_signature (
348
+ state ,
349
+ attestation ,
350
+ epoch_length ,
351
+ )
0 commit comments