Skip to content

Commit bff0f46

Browse files
committed
Merge branch 'master' into attestation-validation
2 parents dab3e44 + 1f7172a commit bff0f46

File tree

14 files changed

+245
-52
lines changed

14 files changed

+245
-52
lines changed

eth/beacon/deposit_helpers.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,12 @@
3030

3131

3232
def get_min_empty_validator_index(validators: Sequence[ValidatorRecord],
33+
validator_balances: Sequence[int],
3334
current_slot: int,
3435
zero_balance_validator_ttl: int) -> int:
35-
for index, validator in enumerate(validators):
36+
for index, (validator, balance) in enumerate(zip(validators, validator_balances)):
3637
is_empty = (
37-
validator.balance == 0 and
38+
balance == 0 and
3839
validator.latest_status_change_slot + zero_balance_validator_ttl <= current_slot
3940
)
4041
if is_empty:
@@ -74,6 +75,7 @@ def validate_proof_of_possession(state: BeaconState,
7475

7576
def add_pending_validator(state: BeaconState,
7677
validator: ValidatorRecord,
78+
deposit: int,
7779
zero_balance_validator_ttl: int) -> Tuple[BeaconState, int]:
7880
"""
7981
Add a validator to the existing minimum empty validator index or
@@ -83,6 +85,7 @@ def add_pending_validator(state: BeaconState,
8385
try:
8486
index = get_min_empty_validator_index(
8587
state.validator_registry,
88+
state.validator_balances,
8689
state.slot,
8790
zero_balance_validator_ttl,
8891
)
@@ -93,11 +96,12 @@ def add_pending_validator(state: BeaconState,
9396
validator_registry = state.validator_registry + (validator,)
9497
state = state.copy(
9598
validator_registry=validator_registry,
99+
validator_balances=state.validator_balances + (deposit, )
96100
)
97101
index = len(state.validator_registry) - 1
98102
else:
99103
# Use the empty validator index
100-
state = state.update_validator(index, validator)
104+
state = state.update_validator(index, validator, deposit)
101105

102106
return state, index
103107

@@ -127,13 +131,13 @@ def process_deposit(*,
127131
pubkey=pubkey,
128132
withdrawal_credentials=withdrawal_credentials,
129133
randao_commitment=randao_commitment,
130-
balance=deposit,
131134
latest_status_change_slot=state.slot,
132135
)
133136

134137
state, index = add_pending_validator(
135138
state,
136139
validator,
140+
deposit,
137141
zero_balance_validator_ttl,
138142
)
139143
else:
@@ -151,9 +155,10 @@ def process_deposit(*,
151155
)
152156

153157
# Update validator's balance and state
154-
validator = validator.copy(
155-
balance=validator.balance + deposit,
158+
state = state.update_validator(
159+
validator_index=index,
160+
validator=validator,
161+
balance=state.validator_balances[index] + deposit,
156162
)
157-
state = state.update_validator(index, validator)
158163

159164
return state, index

eth/beacon/helpers.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -350,11 +350,12 @@ def get_attestation_participants(state: 'BeaconState',
350350
#
351351
# Misc
352352
#
353-
def get_effective_balance(validator: 'ValidatorRecord', max_deposit: int) -> int:
353+
def get_effective_balance(validator_balances: Sequence[int], index: int, max_deposit: int) -> int:
354354
"""
355-
Return the effective balance (also known as "balance at stake") for the ``validator``.
355+
Return the effective balance (also known as "balance at stake") for a
356+
``validator`` with the given ``index``.
356357
"""
357-
return min(validator.balance, max_deposit * denoms.gwei)
358+
return min(validator_balances[index], max_deposit * denoms.gwei)
358359

359360

360361
def get_new_validator_registry_delta_chain_tip(current_validator_registry_delta_chain_tip: Hash32,
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
from eth_utils import (
2+
ValidationError,
3+
)
4+
5+
from eth.beacon.enums import (
6+
SignatureDomain,
7+
)
8+
from eth.beacon.helpers import (
9+
get_beacon_proposer_index,
10+
get_domain,
11+
)
12+
from eth.beacon.types.blocks import (
13+
BaseBeaconBlock,
14+
)
15+
from eth.beacon.types.proposal_signed_data import (
16+
ProposalSignedData,
17+
)
18+
from eth.beacon.types.states import (
19+
BeaconState,
20+
)
21+
22+
from eth._utils.bls import (
23+
verify,
24+
)
25+
26+
27+
def validate_proposer_signature(state: BeaconState,
28+
block: BaseBeaconBlock,
29+
beacon_chain_shard_number: int,
30+
epoch_length: int) -> None:
31+
block_without_signature_root = block.block_without_signature_root
32+
33+
# TODO: Replace this root with tree hash root
34+
proposal_root = ProposalSignedData(
35+
state.slot,
36+
beacon_chain_shard_number,
37+
block_without_signature_root
38+
).root
39+
40+
# Get the public key of proposer
41+
beacon_proposer_index = get_beacon_proposer_index(state, state.slot, epoch_length)
42+
proposer_pubkey = state.validator_registry[beacon_proposer_index].pubkey
43+
44+
is_valid_signature = verify(
45+
pubkey=proposer_pubkey,
46+
message=proposal_root,
47+
signature=block.signature,
48+
domain=get_domain(state.fork_data, state.slot, SignatureDomain.DOMAIN_PROPOSAL)
49+
)
50+
51+
if not is_valid_signature:
52+
raise ValidationError("Invalid Proposer Signature on block")

eth/beacon/types/blocks.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
uint64,
2020
uint384,
2121
)
22+
23+
from eth.beacon.constants import EMPTY_SIGNATURE
2224
from eth.beacon._utils.hash import hash_eth2
2325

2426
from .attestations import Attestation
@@ -111,3 +113,9 @@ def root(self) -> Hash32:
111113
@property
112114
def num_attestations(self) -> int:
113115
return len(self.body.attestations)
116+
117+
@property
118+
def block_without_signature_root(self) -> Hash32:
119+
return self.copy(
120+
signature=EMPTY_SIGNATURE
121+
).root

eth/beacon/types/proposal_signed_data.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
)
44
import rlp
55

6+
from eth.beacon._utils.hash import hash_eth2
7+
68
from eth.rlp.sedes import (
79
uint64,
810
hash32,
@@ -31,3 +33,17 @@ def __init__(self,
3133
shard,
3234
block_root,
3335
)
36+
37+
_hash = None
38+
39+
@property
40+
def hash(self) -> Hash32:
41+
if self._hash is None:
42+
self._hash = hash_eth2(rlp.encode(self))
43+
return self._hash
44+
45+
@property
46+
def root(self) -> Hash32:
47+
# Alias of `hash`.
48+
# Using flat hash, might change to SSZ tree hash.
49+
return self.hash

eth/beacon/types/states.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class BeaconState(rlp.Serializable):
4444

4545
# Validator registry
4646
('validator_registry', CountableList(ValidatorRecord)),
47+
('validator_balances', CountableList(uint64)),
4748
('validator_registry_latest_change_slot', uint64),
4849
('validator_registry_exit_count', uint64),
4950
('validator_registry_delta_chain_tip', hash32), # For light clients to easily track delta
@@ -89,6 +90,7 @@ def __init__(
8990
finalized_slot: int,
9091
processed_pow_receipt_root: Hash32,
9192
validator_registry: Sequence[ValidatorRecord]=(),
93+
validator_balances: Sequence[int]=(),
9294
shard_committees_at_slots: Sequence[Sequence[ShardCommittee]]=(),
9395
persistent_committees: Sequence[Sequence[int]]=(),
9496
persistent_committee_reassignments: Sequence[ShardReassignmentRecord]=(),
@@ -106,6 +108,7 @@ def __init__(
106108
fork_data=fork_data,
107109
# Validator registry
108110
validator_registry=validator_registry,
111+
validator_balances=validator_balances,
109112
validator_registry_latest_change_slot=validator_registry_latest_change_slot,
110113
validator_registry_exit_count=validator_registry_exit_count,
111114
validator_registry_delta_chain_tip=validator_registry_delta_chain_tip,
@@ -160,10 +163,16 @@ def num_crosslinks(self) -> int:
160163

161164
def update_validator(self,
162165
validator_index: int,
163-
validator: ValidatorRecord) -> 'BeaconState':
166+
validator: ValidatorRecord,
167+
balance: int) -> 'BeaconState':
164168
validator_registry = list(self.validator_registry)
165169
validator_registry[validator_index] = validator
170+
171+
validator_balances = list(self.validator_balances)
172+
validator_balances[validator_index] = balance
173+
166174
updated_state = self.copy(
167175
validator_registry=tuple(validator_registry),
176+
validator_balances=tuple(validator_balances),
168177
)
169178
return updated_state

eth/beacon/types/validator_records.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@ class ValidatorRecord(rlp.Serializable):
3232
('randao_commitment', hash32),
3333
# Slot the proposer has skipped (ie. layers of RANDAO expected)
3434
('randao_layers', uint64),
35-
# Balance in Gwei
36-
('balance', uint64),
3735
# Status code
3836
('status', uint64),
3937
# Slot when validator last changed status (or 0)
@@ -47,7 +45,6 @@ def __init__(self,
4745
withdrawal_credentials: Hash32,
4846
randao_commitment: Hash32,
4947
randao_layers: int,
50-
balance: int,
5148
status: int,
5249
latest_status_change_slot: int,
5350
exit_count: int) -> None:
@@ -56,7 +53,6 @@ def __init__(self,
5653
withdrawal_credentials=withdrawal_credentials,
5754
randao_commitment=randao_commitment,
5855
randao_layers=randao_layers,
59-
balance=balance,
6056
status=status,
6157
latest_status_change_slot=latest_status_change_slot,
6258
exit_count=exit_count,
@@ -74,7 +70,6 @@ def get_pending_validator(cls,
7470
pubkey: int,
7571
withdrawal_credentials: Hash32,
7672
randao_commitment: Hash32,
77-
balance: int,
7873
latest_status_change_slot: int) -> 'ValidatorRecord':
7974
"""
8075
Return a new pending ``ValidatorRecord`` with the given fields.
@@ -84,7 +79,6 @@ def get_pending_validator(cls,
8479
withdrawal_credentials=withdrawal_credentials,
8580
randao_commitment=randao_commitment,
8681
randao_layers=0,
87-
balance=balance,
8882
status=ValidatorStatusCode.PENDING_ACTIVATION,
8983
latest_status_change_slot=latest_status_change_slot,
9084
exit_count=0,

tests/beacon/conftest.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import pytest
22
import rlp
33

4-
from eth_utils import denoms
5-
64
from eth.constants import (
75
ZERO_HASH32,
86
)
@@ -149,6 +147,7 @@ def sample_beacon_state_params(sample_fork_data_params):
149147
'genesis_time': 0,
150148
'fork_data': ForkData(**sample_fork_data_params),
151149
'validator_registry': (),
150+
'validator_balances': (),
152151
'validator_registry_latest_change_slot': 10,
153152
'validator_registry_exit_count': 10,
154153
'validator_registry_delta_chain_tip': b'\x55' * 32,
@@ -305,7 +304,6 @@ def sample_validator_record_params():
305304
'withdrawal_credentials': b'\x01' * 32,
306305
'randao_commitment': b'\x01' * 32,
307306
'randao_layers': 1,
308-
'balance': 100,
309307
'status': 1,
310308
'latest_status_change_slot': 0,
311309
'exit_count': 0
@@ -547,7 +545,6 @@ def genesis_validators(init_validator_keys,
547545
withdrawal_credentials=ZERO_HASH32,
548546
randao_commitment=init_randao,
549547
randao_layers=0,
550-
balance=max_deposit * denoms.gwei,
551548
status=ValidatorStatusCode.ACTIVE,
552549
latest_status_change_slot=0,
553550
exit_count=0,

tests/beacon/helpers.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,12 @@
88
from eth_utils import to_tuple
99

1010

11-
def mock_validator_record(pubkey, max_deposit):
11+
def mock_validator_record(pubkey):
1212
return ValidatorRecord(
1313
pubkey=pubkey,
1414
withdrawal_credentials=b'\x44' * 32,
1515
randao_commitment=b'\x55' * 32,
1616
randao_layers=0,
17-
balance=max_deposit,
1817
status=ValidatorStatusCode.ACTIVE,
1918
latest_status_change_slot=0,
2019
exit_count=0,

0 commit comments

Comments
 (0)