Skip to content

Commit f1a0b20

Browse files
committed
Add AttestationDataAndCustodyBit data structure
1. Update `SlashableVoteData.messages` 2. Rename `aggregate_signature_poc_0_indices` => `custody_bit_0_indices` 3. Rename `aggregate_signature_poc_1_indices` => `custody_bit_1_indices`
1 parent d3b7a5a commit f1a0b20

10 files changed

+137
-69
lines changed

eth/beacon/helpers.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -437,9 +437,9 @@ def generate_aggregate_pubkeys(validators: Sequence['ValidatorRecord'],
437437
Compute the aggregate pubkey we expect based on
438438
the proof-of-custody indices found in the ``vote_data``.
439439
"""
440-
proof_of_custody_0_indices = vote_data.aggregate_signature_poc_0_indices
441-
proof_of_custody_1_indices = vote_data.aggregate_signature_poc_1_indices
442-
all_indices = (proof_of_custody_0_indices, proof_of_custody_1_indices)
440+
custody_bit_0_indices = vote_data.custody_bit_0_indices
441+
custody_bit_1_indices = vote_data.custody_bit_1_indices
442+
all_indices = (custody_bit_0_indices, custody_bit_1_indices)
443443
get_pubkeys = functools.partial(get_pubkey_for_indices, validators)
444444
return map(
445445
bls.aggregate_pubkeys,
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import rlp
2+
from rlp.sedes import (
3+
Boolean,
4+
)
5+
from eth_typing import (
6+
Hash32,
7+
)
8+
9+
from eth.beacon._utils.hash import (
10+
hash_eth2,
11+
)
12+
13+
from .attestation_data import (
14+
AttestationData,
15+
)
16+
17+
18+
class AttestationDataAndCustodyBit(rlp.Serializable):
19+
"""
20+
Note: using RLP until we have standardized serialization format.
21+
"""
22+
fields = [
23+
# Attestation data
24+
('data', AttestationData),
25+
# Custody bit
26+
('custody_bit', Boolean),
27+
]
28+
29+
def __init__(self,
30+
data: AttestationData,
31+
custody_bit: bool)-> None:
32+
33+
super().__init__(
34+
data=data,
35+
custody_bit=custody_bit,
36+
)
37+
38+
_hash = None
39+
40+
@property
41+
def hash(self) -> Hash32:
42+
if self._hash is None:
43+
self._hash = hash_eth2(rlp.encode(self.data))
44+
return self._hash
45+
46+
@property
47+
def root(self) -> Hash32:
48+
# Alias of `hash`.
49+
# Using flat hash, will likely use SSZ tree hash.
50+
return self.hash

eth/beacon/types/pending_attestation_records.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ class PendingAttestationRecord(rlp.Serializable):
2525
('data', AttestationData),
2626
# Attester participation bitfield
2727
('participation_bitfield', binary),
28-
# Proof of custody bitfield
28+
# Custody bitfield
2929
('custody_bitfield', binary),
30-
# Slot in which it was included
30+
# Slot the attestation was included
3131
('slot_included', uint64),
3232
]
3333

eth/beacon/types/slashable_vote_data.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,31 +21,32 @@
2121
from eth.beacon.constants import EMPTY_SIGNATURE
2222

2323
from .attestation_data import AttestationData
24+
from .attestation_data_and_custody_bits import AttestationDataAndCustodyBit
2425

2526

2627
class SlashableVoteData(rlp.Serializable):
2728
"""
2829
Note: using RLP until we have standardized serialization format.
2930
"""
3031
fields = [
31-
# Proof-of-custody indices (0 bits)
32-
('aggregate_signature_poc_0_indices', CountableList(uint24)),
33-
# Proof-of-custody indices (1 bits)
34-
('aggregate_signature_poc_1_indices', CountableList(uint24)),
32+
# Validator indices with custody bit equal to 0
33+
('custody_bit_0_indices', CountableList(uint24)),
34+
# Validator indices with custody bit equal to 1
35+
('custody_bit_1_indices', CountableList(uint24)),
3536
# Attestation data
3637
('data', AttestationData),
3738
# Aggregate signature
3839
('aggregate_signature', CountableList(uint384)),
3940
]
4041

4142
def __init__(self,
42-
aggregate_signature_poc_0_indices: Sequence[ValidatorIndex],
43-
aggregate_signature_poc_1_indices: Sequence[ValidatorIndex],
43+
custody_bit_0_indices: Sequence[ValidatorIndex],
44+
custody_bit_1_indices: Sequence[ValidatorIndex],
4445
data: AttestationData,
4546
aggregate_signature: BLSSignature = EMPTY_SIGNATURE) -> None:
4647
super().__init__(
47-
aggregate_signature_poc_0_indices,
48-
aggregate_signature_poc_1_indices,
48+
custody_bit_0_indices,
49+
custody_bit_1_indices,
4950
data,
5051
aggregate_signature,
5152
)
@@ -69,19 +70,18 @@ def root(self) -> Hash32:
6970
@property
7071
def vote_count(self) -> int:
7172
if self._vote_count is None:
72-
count_zero_indices = len(self.aggregate_signature_poc_0_indices)
73-
count_one_indices = len(self.aggregate_signature_poc_1_indices)
73+
count_zero_indices = len(self.custody_bit_0_indices)
74+
count_one_indices = len(self.custody_bit_1_indices)
7475
self._vote_count = count_zero_indices + count_one_indices
7576
return self._vote_count
7677

7778
@property
78-
def messages(self) -> Tuple[bytes, bytes]:
79+
def messages(self) -> Tuple[Hash32, Hash32]:
7980
"""
8081
Build the messages that validators are expected to sign for a ``CasperSlashing`` operation.
8182
"""
82-
# TODO: change to hash_tree_root(vote_data) when we have SSZ tree hashing
83-
vote_data_root = self.root
83+
# TODO: change to hash_tree_root when we have SSZ tree hashing
8484
return (
85-
vote_data_root + (0).to_bytes(1, 'big'),
86-
vote_data_root + (1).to_bytes(1, 'big'),
85+
AttestationDataAndCustodyBit(self.data, False).root,
86+
AttestationDataAndCustodyBit(self.data, True).root,
8787
)

eth/beacon/types/states.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,7 @@ class BeaconState(rlp.Serializable):
6565
('persistent_committees', CountableList(CountableList(uint24))),
6666
('persistent_committee_reassignments', CountableList(ShardReassignmentRecord)),
6767

68-
69-
# Proof of custody
68+
# Custody challenges
7069
('custody_challenges', CountableList(CustodyChallenge)),
7170

7271
# Finality

tests/beacon/conftest.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,14 @@ def sample_attestation_data_params():
117117
}
118118

119119

120+
@pytest.fixture
121+
def sample_attestation_data_and_custody_bit_params(sample_attestation_data_params):
122+
return {
123+
'data': AttestationData(**sample_attestation_data_params),
124+
'custody_bit': False,
125+
}
126+
127+
120128
@pytest.fixture
121129
def sample_beacon_block_body_params():
122130
return {
@@ -287,8 +295,8 @@ def sample_shard_reassignment_record():
287295
@pytest.fixture
288296
def sample_slashable_vote_data_params(sample_attestation_data_params):
289297
return {
290-
'aggregate_signature_poc_0_indices': (10, 11, 12, 15, 28),
291-
'aggregate_signature_poc_1_indices': (7, 8, 100, 131, 249),
298+
'custody_bit_0_indices': (10, 11, 12, 15, 28),
299+
'custody_bit_1_indices': (7, 8, 100, 131, 249),
292300
'data': AttestationData(**sample_attestation_data_params),
293301
'aggregate_signature': (1, 2, 3, 4, 5),
294302
}

tests/beacon/test_helpers.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -766,13 +766,13 @@ def test_generate_aggregate_pubkeys(genesis_validators, sample_slashable_vote_da
766766
max_value=max_value_for_list,
767767
)
768768
)
769-
proof_of_custody_0_indices = indices[:some_index]
770-
proof_of_custody_1_indices = indices[some_index:]
769+
custody_bit_0_indices = indices[:some_index]
770+
custody_bit_1_indices = indices[some_index:]
771771

772-
key = "aggregate_signature_poc_0_indices"
773-
sample_slashable_vote_data_params[key] = proof_of_custody_0_indices
774-
key = "aggregate_signature_poc_1_indices"
775-
sample_slashable_vote_data_params[key] = proof_of_custody_1_indices
772+
key = "custody_bit_0_indices"
773+
sample_slashable_vote_data_params[key] = custody_bit_0_indices
774+
key = "custody_bit_1_indices"
775+
sample_slashable_vote_data_params[key] = custody_bit_1_indices
776776

777777
votes = SlashableVoteData(**sample_slashable_vote_data_params)
778778

@@ -781,8 +781,8 @@ def test_generate_aggregate_pubkeys(genesis_validators, sample_slashable_vote_da
781781

782782
(poc_0_key, poc_1_key) = keys
783783

784-
poc_0_keys = get_pubkey_for_indices(genesis_validators, proof_of_custody_0_indices)
785-
poc_1_keys = get_pubkey_for_indices(genesis_validators, proof_of_custody_1_indices)
784+
poc_0_keys = get_pubkey_for_indices(genesis_validators, custody_bit_0_indices)
785+
poc_1_keys = get_pubkey_for_indices(genesis_validators, custody_bit_1_indices)
786786

787787
assert bls.aggregate_pubkeys(poc_0_keys) == poc_0_key
788788
assert bls.aggregate_pubkeys(poc_1_keys) == poc_1_key
@@ -791,13 +791,13 @@ def test_generate_aggregate_pubkeys(genesis_validators, sample_slashable_vote_da
791791
@given(st.data())
792792
def test_verify_vote_count(max_casper_votes, sample_slashable_vote_data_params, data):
793793
(indices, some_index) = _list_and_index(data, max_size=max_casper_votes)
794-
proof_of_custody_0_indices = indices[:some_index]
795-
proof_of_custody_1_indices = indices[some_index:]
794+
custody_bit_0_indices = indices[:some_index]
795+
custody_bit_1_indices = indices[some_index:]
796796

797-
key = "aggregate_signature_poc_0_indices"
798-
sample_slashable_vote_data_params[key] = proof_of_custody_0_indices
799-
key = "aggregate_signature_poc_1_indices"
800-
sample_slashable_vote_data_params[key] = proof_of_custody_1_indices
797+
key = "custody_bit_0_indices"
798+
sample_slashable_vote_data_params[key] = custody_bit_0_indices
799+
key = "custody_bit_1_indices"
800+
sample_slashable_vote_data_params[key] = custody_bit_1_indices
801801

802802
votes = SlashableVoteData(**sample_slashable_vote_data_params)
803803

@@ -821,15 +821,15 @@ def _correct_slashable_vote_data_params(params, validators, messages, privkeys):
821821

822822
num_validators = len(validators)
823823

824-
key = "aggregate_signature_poc_0_indices"
824+
key = "custody_bit_0_indices"
825825
(poc_0_indices, poc_0_signatures) = _get_indices_and_signatures(
826826
num_validators,
827827
messages[0],
828828
privkeys,
829829
)
830830
valid_params[key] = poc_0_indices
831831

832-
key = "aggregate_signature_poc_1_indices"
832+
key = "custody_bit_1_indices"
833833
# NOTE: does not guarantee non-empty intersection
834834
(poc_1_indices, poc_1_signatures) = _get_indices_and_signatures(
835835
num_validators,
@@ -857,7 +857,7 @@ def _corrupt_signature(params):
857857

858858
def _corrupt_vote_count(params):
859859
params = copy.deepcopy(params)
860-
key = "aggregate_signature_poc_0_indices"
860+
key = "custody_bit_0_indices"
861861
for i in itertools.count():
862862
if i not in params[key]:
863863
params[key].append(i)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from eth.beacon.types.attestation_data_and_custody_bits import (
2+
AttestationDataAndCustodyBit,
3+
)
4+
5+
6+
def test_defaults(sample_attestation_data_and_custody_bit_params):
7+
params = sample_attestation_data_and_custody_bit_params
8+
attestation_data_and_custody_bit = AttestationDataAndCustodyBit(**params)
9+
10+
assert attestation_data_and_custody_bit.data == params['data']
11+
assert attestation_data_and_custody_bit.custody_bit == params['custody_bit']

tests/beacon/types/test_casper_slashings.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ def test_defaults(sample_casper_slashing_params):
55
slashing = CasperSlashing(**sample_casper_slashing_params)
66

77
assert (slashing.slashable_vote_data_1
8-
.aggregate_signature_poc_0_indices ==
8+
.custody_bit_0_indices ==
99
sample_casper_slashing_params['slashable_vote_data_1']
10-
.aggregate_signature_poc_0_indices
10+
.custody_bit_0_indices
1111
)
1212
assert (slashing.slashable_vote_data_2
13-
.aggregate_signature_poc_1_indices ==
13+
.custody_bit_1_indices ==
1414
sample_casper_slashing_params['slashable_vote_data_2']
15-
.aggregate_signature_poc_1_indices
15+
.custody_bit_1_indices
1616
)
Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
1+
from eth.beacon.types.attestation_data_and_custody_bits import (
2+
AttestationDataAndCustodyBit,
3+
)
14
from eth.beacon.types.slashable_vote_data import (
25
SlashableVoteData,
36
)
47

58

69
def test_defaults(sample_slashable_vote_data_params):
7-
votes = SlashableVoteData(**sample_slashable_vote_data_params)
10+
vote_data = SlashableVoteData(**sample_slashable_vote_data_params)
811

9-
assert (votes.aggregate_signature_poc_0_indices ==
10-
sample_slashable_vote_data_params['aggregate_signature_poc_0_indices'])
11-
assert (votes.aggregate_signature_poc_1_indices ==
12-
sample_slashable_vote_data_params['aggregate_signature_poc_1_indices'])
13-
assert votes.data == sample_slashable_vote_data_params['data']
14-
assert votes.aggregate_signature == sample_slashable_vote_data_params['aggregate_signature']
12+
assert (vote_data.custody_bit_0_indices ==
13+
sample_slashable_vote_data_params['custody_bit_0_indices'])
14+
assert (vote_data.custody_bit_1_indices ==
15+
sample_slashable_vote_data_params['custody_bit_1_indices'])
16+
assert vote_data.data == sample_slashable_vote_data_params['data']
17+
assert vote_data.aggregate_signature == sample_slashable_vote_data_params['aggregate_signature']
1518

1619

1720
def test_hash(sample_slashable_vote_data_params):
18-
votes = SlashableVoteData(**sample_slashable_vote_data_params)
21+
vote_data = SlashableVoteData(**sample_slashable_vote_data_params)
1922

2023
# NOTE: this hash was simply copied from the existing implementation
2124
# which should be the keccak-256 of the rlp serialization of `votes`.
@@ -24,36 +27,33 @@ def test_hash(sample_slashable_vote_data_params):
2427
# if we expect the hash computation is not working correctly
2528
hash_hex = "7e4b4cf3ac47988865d693a29b6aa5a825f27e065cf21a80af5e077ea102e297"
2629

27-
assert votes.hash == bytes.fromhex(hash_hex)
30+
assert vote_data.hash == bytes.fromhex(hash_hex)
2831

2932

3033
def test_root(sample_slashable_vote_data_params):
31-
votes = SlashableVoteData(**sample_slashable_vote_data_params)
34+
vote_data = SlashableVoteData(**sample_slashable_vote_data_params)
3235

3336
# NOTE: see note in `test_hash`, this test will need to be updated
3437
# once ssz tree hash lands...
3538

36-
assert votes.root == votes.hash
39+
assert vote_data.root == vote_data.hash
3740

3841

3942
def test_vote_count(sample_slashable_vote_data_params):
40-
votes = SlashableVoteData(**sample_slashable_vote_data_params)
43+
vote_data = SlashableVoteData(**sample_slashable_vote_data_params)
4144

42-
key = "aggregate_signature_poc_0_indices"
43-
proof_of_custody_0_indices = sample_slashable_vote_data_params[key]
44-
key = "aggregate_signature_poc_1_indices"
45-
proof_of_custody_1_indices = sample_slashable_vote_data_params[key]
45+
key = "custody_bit_0_indices"
46+
custody_bit_0_indices = sample_slashable_vote_data_params[key]
47+
key = "custody_bit_1_indices"
48+
custody_bit_1_indices = sample_slashable_vote_data_params[key]
4649

47-
assert votes.vote_count == len(proof_of_custody_0_indices) + len(proof_of_custody_1_indices)
50+
assert vote_data.vote_count == len(custody_bit_0_indices) + len(custody_bit_1_indices)
4851

4952

5053
def test_messages(sample_slashable_vote_data_params):
51-
votes = SlashableVoteData(**sample_slashable_vote_data_params)
52-
53-
zero_discriminator = (0).to_bytes(1, 'big')
54-
one_discriminator = (1).to_bytes(1, 'big')
54+
vote_data = SlashableVoteData(**sample_slashable_vote_data_params)
5555

56-
assert votes.messages == (
57-
votes.root + zero_discriminator,
58-
votes.root + one_discriminator,
56+
assert vote_data.messages == (
57+
AttestationDataAndCustodyBit(vote_data.data, False).root,
58+
AttestationDataAndCustodyBit(vote_data.data, True).root,
5959
)

0 commit comments

Comments
 (0)