From 4d980aec71f93f2f788fc8ea76bec14521d53abc Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 23 Apr 2020 13:23:31 +0800 Subject: [PATCH 1/7] Fix validator guide 1. Avoid negative computation in `is_candidate_block` 2. Fix `get_block_signature`: avoid extra casting; it's simpler to use BeaconBlock instead of BeaconHeader --- specs/phase0/validator.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/specs/phase0/validator.md b/specs/phase0/validator.md index bc7510403..4576c4b90 100644 --- a/specs/phase0/validator.md +++ b/specs/phase0/validator.md @@ -281,8 +281,8 @@ def voting_period_start_time(state: BeaconState) -> uint64: ```python def is_candidate_block(block: Eth1Block, period_start: uint64) -> bool: return ( - block.timestamp <= period_start - SECONDS_PER_ETH1_BLOCK * ETH1_FOLLOW_DISTANCE - and block.timestamp >= period_start - SECONDS_PER_ETH1_BLOCK * ETH1_FOLLOW_DISTANCE * 2 + block.timestamp + SECONDS_PER_ETH1_BLOCK * ETH1_FOLLOW_DISTANCE <= period_start + and block.timestamp + SECONDS_PER_ETH1_BLOCK * ETH1_FOLLOW_DISTANCE * 2 >= period_start ) ``` @@ -350,9 +350,9 @@ def compute_new_state_root(state: BeaconState, block: BeaconBlock) -> Root: `signed_block = SignedBeaconBlock(message=block, signature=block_signature)`, where `block_signature` is obtained from: ```python -def get_block_signature(state: BeaconState, header: BeaconBlockHeader, privkey: int) -> BLSSignature: - domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(header.slot)) - signing_root = compute_signing_root(header, domain) +def get_block_signature(state: BeaconState, block: BeaconBlock, privkey: int) -> BLSSignature: + domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(block.slot)) + signing_root = compute_signing_root(block, domain) return bls.Sign(privkey, signing_root) ``` From 303d7d5adb35e51a49c570e15256763c136de8a1 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 23 Apr 2020 13:27:00 +0800 Subject: [PATCH 2/7] Add validator guide tests 1. "Becoming a validator" 2. "Validator assignments" 3. "Beacon chain responsibilities: Block proposal" --- .../test/validator/test_validator_unittest.py | 182 ++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 tests/core/pyspec/eth2spec/test/validator/test_validator_unittest.py diff --git a/tests/core/pyspec/eth2spec/test/validator/test_validator_unittest.py b/tests/core/pyspec/eth2spec/test/validator/test_validator_unittest.py new file mode 100644 index 000000000..019221eee --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/validator/test_validator_unittest.py @@ -0,0 +1,182 @@ +from eth2spec.test.context import spec_state_test, never_bls, with_all_phases +from eth2spec.test.helpers.block import build_empty_block +from eth2spec.test.helpers.deposits import prepare_state_and_deposit +from eth2spec.test.helpers.keys import privkeys, pubkeys +from eth2spec.test.helpers.state import next_epoch +from eth2spec.utils import bls + + +def run_is_candidate_block(spec, eth1_block, period_start, success): + result = spec.is_candidate_block(eth1_block, period_start) + if success: + assert result + else: + assert not result + + +def get_min_new_period_epochs(spec): + return int( + spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE * 2 # to seconds + / spec.SECONDS_PER_SLOT / spec.SLOTS_PER_EPOCH + ) + + +# +# Becoming a validator +# + + +@with_all_phases +@spec_state_test +@never_bls +def test_check_if_validator_active(spec, state): + active_validator_index = len(state.validators) - 1 + assert spec.check_if_validator_active(state, active_validator_index) + new_validator_index = len(state.validators) + amount = spec.MAX_EFFECTIVE_BALANCE + deposit = prepare_state_and_deposit(spec, state, new_validator_index, amount, signed=True) + spec.process_deposit(state, deposit) + assert not spec.check_if_validator_active(state, new_validator_index) + + +# +# Validator assignments +# + + +@with_all_phases +@spec_state_test +@never_bls +def test_get_committee_assignment(spec, state): + epoch = spec.get_current_epoch(state) + validator_index = len(state.validators) - 1 + assignment = spec.get_committee_assignment(state, epoch, validator_index) + committee, committee_index, slot = assignment + assert spec.compute_epoch_at_slot(slot) == epoch + assert committee == spec.get_beacon_committee(state, slot, committee_index) + assert committee_index < spec.get_committee_count_at_slot(state, slot) + + +@with_all_phases +@spec_state_test +@never_bls +def test_is_proposer(spec, state): + proposer_index = spec.get_beacon_proposer_index(state) + assert spec.is_proposer(state, proposer_index) + + proposer_index = proposer_index + 1 % len(state.validators) + assert not spec.is_proposer(state, proposer_index) + + +# +# Beacon chain responsibilities +# + + +# Block proposal + + +@with_all_phases +@spec_state_test +def test_get_epoch_signature(spec, state): + block = spec.BeaconBlock() + privkey = privkeys[0] + pubkey = pubkeys[0] + signature = spec.get_epoch_signature(state, block, privkey) + domain = spec.get_domain(state, spec.DOMAIN_RANDAO, spec.compute_epoch_at_slot(block.slot)) + signing_root = spec.compute_signing_root(spec.compute_epoch_at_slot(block.slot), domain) + assert bls.Verify(pubkey, signing_root, signature) + + +@with_all_phases +@spec_state_test +def test_is_candidate_block(spec, state): + period_start = spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE * 2 + 1000 + run_is_candidate_block( + spec, + spec.Eth1Block(timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE), + period_start, + success=True, + ) + run_is_candidate_block( + spec, + spec.Eth1Block(timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE + 1), + period_start, + success=False, + ) + run_is_candidate_block( + spec, + spec.Eth1Block(timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE * 2), + period_start, + success=True, + ) + run_is_candidate_block( + spec, + spec.Eth1Block(timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE * 2 - 1), + period_start, + success=False, + ) + + +@with_all_phases +@spec_state_test +def test_get_eth1_data_default_vote(spec, state): + min_new_period_epochs = get_min_new_period_epochs(spec) + for _ in range(min_new_period_epochs): + next_epoch(spec, state) + + state.eth1_data_votes = () + eth1_chain = [] + eth1_data = spec.get_eth1_vote(state, eth1_chain) + assert eth1_data == state.eth1_data + + +@with_all_phases +@spec_state_test +def test_get_eth1_data_consensus_vote(spec, state): + min_new_period_epochs = get_min_new_period_epochs(spec) + for _ in range(min_new_period_epochs): + next_epoch(spec, state) + + period_start = spec.voting_period_start_time(state) + votes_length = spec.get_current_epoch(state) % spec.EPOCHS_PER_ETH1_VOTING_PERIOD + state.eth1_data_votes = () + eth1_chain = [] + eth1_data_votes = [] + block = spec.Eth1Block(timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE) + for i in range(votes_length): + eth1_chain.append(block) + eth1_data_votes.append(spec.get_eth1_data(block)) + + state.eth1_data_votes = eth1_data_votes + eth1_data = spec.get_eth1_vote(state, eth1_chain) + print(state.eth1_data_votes) + assert eth1_data.block_hash == block.hash_tree_root() + + +@with_all_phases +@spec_state_test +def test_compute_new_state_root(spec, state): + pre_state = state.copy() + post_state = state.copy() + block = build_empty_block(spec, state, state.slot + 1) + state_root = spec.compute_new_state_root(state, block) + + assert state_root != pre_state.hash_tree_root() + + # dumb verification + spec.process_slots(post_state, block.slot) + spec.process_block(post_state, block) + assert state_root == post_state.hash_tree_root() + + +@with_all_phases +@spec_state_test +def test_get_block_signature(spec, state): + privkey = privkeys[0] + pubkey = pubkeys[0] + block = build_empty_block(spec, state) + signature = spec.get_block_signature(state, block, privkey) + domain = spec.get_domain(state, spec.DOMAIN_BEACON_PROPOSER, spec.compute_epoch_at_slot(block.slot)) + signing_root = spec.compute_signing_root(block, domain) + assert bls.Verify(pubkey, signing_root, signature) From bdae27e317b44c1ab031a0cbdb5b4d61d0fe05a7 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 23 Apr 2020 15:08:36 +0800 Subject: [PATCH 3/7] Add bls.AggregatePKs helper --- tests/core/pyspec/eth2spec/utils/bls.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/core/pyspec/eth2spec/utils/bls.py b/tests/core/pyspec/eth2spec/utils/bls.py index 83371ac62..3b648fac9 100644 --- a/tests/core/pyspec/eth2spec/utils/bls.py +++ b/tests/core/pyspec/eth2spec/utils/bls.py @@ -51,3 +51,8 @@ def Sign(SK, message): @only_with_bls(alt_return=STUB_COORDINATES) def signature_to_G2(signature): return _signature_to_G2(signature) + + +@only_with_bls(alt_return=STUB_PUBKEY) +def AggregatePKs(pubkeys): + return bls._AggregatePKs(pubkeys) From 8adc15e83de9ab6c0ac10b93aa739df2be989704 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 23 Apr 2020 15:09:23 +0800 Subject: [PATCH 4/7] Add validator guide tests 1. "Beacon chain responsibilities: Attesting" 2. "Beacon chain responsibilities: Attestation aggregation" --- .../test/validator/test_validator_unittest.py | 118 +++++++++++++++++- 1 file changed, 116 insertions(+), 2 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/validator/test_validator_unittest.py b/tests/core/pyspec/eth2spec/test/validator/test_validator_unittest.py index 019221eee..4f6697f2f 100644 --- a/tests/core/pyspec/eth2spec/test/validator/test_validator_unittest.py +++ b/tests/core/pyspec/eth2spec/test/validator/test_validator_unittest.py @@ -1,9 +1,11 @@ from eth2spec.test.context import spec_state_test, never_bls, with_all_phases +from eth2spec.test.helpers.attestations import build_attestation_data from eth2spec.test.helpers.block import build_empty_block from eth2spec.test.helpers.deposits import prepare_state_and_deposit from eth2spec.test.helpers.keys import privkeys, pubkeys from eth2spec.test.helpers.state import next_epoch from eth2spec.utils import bls +from eth2spec.utils.ssz.ssz_typing import Bitlist def run_is_candidate_block(spec, eth1_block, period_start, success): @@ -21,6 +23,14 @@ def get_min_new_period_epochs(spec): ) +def get_mock_aggregate(spec): + return spec.Attestation( + data=spec.AttestationData( + slot=10, + ) + ) + + # # Becoming a validator # @@ -47,7 +57,7 @@ def test_check_if_validator_active(spec, state): @with_all_phases @spec_state_test @never_bls -def test_get_committee_assignment(spec, state): +def test_get_committee_assignment_current_epoch(spec, state): epoch = spec.get_current_epoch(state) validator_index = len(state.validators) - 1 assignment = spec.get_committee_assignment(state, epoch, validator_index) @@ -150,7 +160,6 @@ def test_get_eth1_data_consensus_vote(spec, state): state.eth1_data_votes = eth1_data_votes eth1_data = spec.get_eth1_vote(state, eth1_chain) - print(state.eth1_data_votes) assert eth1_data.block_hash == block.hash_tree_root() @@ -180,3 +189,108 @@ def test_get_block_signature(spec, state): domain = spec.get_domain(state, spec.DOMAIN_BEACON_PROPOSER, spec.compute_epoch_at_slot(block.slot)) signing_root = spec.compute_signing_root(block, domain) assert bls.Verify(pubkey, signing_root, signature) + + +# Attesting + + +@with_all_phases +@spec_state_test +def test_get_attestation_signature(spec, state): + privkey = privkeys[0] + pubkey = pubkeys[0] + attestation_data = spec.AttestationData(slot=10) + signature = spec.get_attestation_signature(state, attestation_data, privkey) + domain = spec.get_domain(state, spec.DOMAIN_BEACON_ATTESTER, attestation_data.target.epoch) + signing_root = spec.compute_signing_root(attestation_data, domain) + assert bls.Verify(pubkey, signing_root, signature) + + +# Attestation aggregation + + +@with_all_phases +@spec_state_test +def test_get_slot_signature(spec, state): + privkey = privkeys[0] + pubkey = pubkeys[0] + slot = 10 + signature = spec.get_slot_signature(state, spec.Slot(slot), privkey) + domain = spec.get_domain(state, spec.DOMAIN_SELECTION_PROOF, spec.compute_epoch_at_slot(slot)) + signing_root = spec.compute_signing_root(spec.Slot(slot), domain) + assert bls.Verify(pubkey, signing_root, signature) + + +@with_all_phases +@spec_state_test +def test_is_aggregator(spec, state): + # TODO: we can test the probabilistic result against `TARGET_AGGREGATORS_PER_COMMITTEE` + # if we have more validators and larger committeee size + slot = state.slot + committee_index = 0 + has_aggregator = False + beacon_committee = spec.get_beacon_committee(state, slot, committee_index) + for validator_index in beacon_committee: + privkey = privkeys[validator_index] + slot_signature = spec.get_slot_signature(state, slot, privkey) + if spec.is_aggregator(state, slot, committee_index, slot_signature): + has_aggregator = True + break + assert has_aggregator + + +@with_all_phases +@spec_state_test +def test_get_aggregate_signature(spec, state): + attestations = [] + pubkeys = [] + slot = state.slot + committee_index = 0 + attestation_data = build_attestation_data(spec, state, slot=slot, index=committee_index) + beacon_committee = spec.get_beacon_committee( + state, + attestation_data.slot, + attestation_data.index, + ) + committee_size = len(beacon_committee) + aggregation_bits = Bitlist[spec.MAX_VALIDATORS_PER_COMMITTEE](*([0] * committee_size)) + for i, validator_index in enumerate(beacon_committee): + bits = aggregation_bits + bits[i] = True + attestations.append( + spec.Attestation( + data=attestation_data, + aggregation_bits=bits, + ) + ) + pubkeys.append(state.validators[validator_index].pubkey) + pubkey = bls.AggregatePKs(pubkeys) + signature = spec.get_aggregate_signature(attestations) + domain = spec.get_domain(state, spec.DOMAIN_BEACON_ATTESTER, attestation_data.target.epoch) + signing_root = spec.compute_signing_root(attestation_data, domain) + assert bls.Verify(pubkey, signing_root, signature) + + +@with_all_phases +@spec_state_test +def test_get_aggregate_and_proof(spec, state): + privkey = privkeys[0] + aggregator_index = spec.ValidatorIndex(10) + aggregate = get_mock_aggregate(spec) + aggregate_and_proof = spec.get_aggregate_and_proof(state, aggregator_index, aggregate, privkey) + assert aggregate_and_proof.aggregator_index == aggregator_index + assert aggregate_and_proof.aggregate == aggregate + assert aggregate_and_proof.selection_proof == spec.get_slot_signature(state, aggregate.data.slot, privkey) + + +@with_all_phases +@spec_state_test +def test_get_aggregate_and_proof_signature(spec, state): + privkey = privkeys[0] + pubkey = pubkeys[0] + aggregate = get_mock_aggregate(spec) + aggregate_and_proof = spec.get_aggregate_and_proof(state, spec.ValidatorIndex(1), aggregate, privkey) + signature = spec.get_aggregate_and_proof_signature(state, aggregate_and_proof, privkey) + domain = spec.get_domain(state, spec.DOMAIN_AGGREGATE_AND_PROOF, spec.compute_epoch_at_slot(aggregate.data.slot)) + signing_root = spec.compute_signing_root(aggregate_and_proof, domain) + assert bls.Verify(pubkey, signing_root, signature) From 70bd73d2b5f4b8c3f19a9397fd983c23fd1eecc6 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Mon, 27 Apr 2020 20:47:36 +0800 Subject: [PATCH 5/7] Apply PR feedback from @djrtwo Fix get_eth1_vote test cases --- .../test/validator/test_validator_unittest.py | 164 ++++++++++++++---- 1 file changed, 131 insertions(+), 33 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/validator/test_validator_unittest.py b/tests/core/pyspec/eth2spec/test/validator/test_validator_unittest.py index 4f6697f2f..a655cb486 100644 --- a/tests/core/pyspec/eth2spec/test/validator/test_validator_unittest.py +++ b/tests/core/pyspec/eth2spec/test/validator/test_validator_unittest.py @@ -8,12 +8,29 @@ from eth2spec.utils import bls from eth2spec.utils.ssz.ssz_typing import Bitlist -def run_is_candidate_block(spec, eth1_block, period_start, success): - result = spec.is_candidate_block(eth1_block, period_start) - if success: - assert result +def run_get_signature_test(spec, state, obj, domain, get_signature_fn, privkey, pubkey): + signature = get_signature_fn(state, obj, privkey) + signing_root = spec.compute_signing_root(obj, domain) + assert bls.Verify(pubkey, signing_root, signature) + + +def run_get_committee_assignment(spec, state, epoch, validator_index, valid=True): + try: + assignment = spec.get_committee_assignment(state, epoch, validator_index) + committee, committee_index, slot = assignment + assert spec.compute_epoch_at_slot(slot) == epoch + assert committee == spec.get_beacon_committee(state, slot, committee_index) + assert committee_index < spec.get_committee_count_at_slot(state, slot) + assert validator_index in committee + assert valid + except AssertionError: + assert not valid else: - assert not result + assert valid + + +def run_is_candidate_block(spec, eth1_block, period_start, success=True): + assert success == spec.is_candidate_block(eth1_block, period_start) def get_min_new_period_epochs(spec): @@ -60,11 +77,25 @@ def test_check_if_validator_active(spec, state): def test_get_committee_assignment_current_epoch(spec, state): epoch = spec.get_current_epoch(state) validator_index = len(state.validators) - 1 - assignment = spec.get_committee_assignment(state, epoch, validator_index) - committee, committee_index, slot = assignment - assert spec.compute_epoch_at_slot(slot) == epoch - assert committee == spec.get_beacon_committee(state, slot, committee_index) - assert committee_index < spec.get_committee_count_at_slot(state, slot) + run_get_committee_assignment(spec, state, epoch, validator_index, valid=True) + + +@with_all_phases +@spec_state_test +@never_bls +def test_get_committee_assignment_next_epoch(spec, state): + epoch = spec.get_current_epoch(state) + 1 + validator_index = len(state.validators) - 1 + run_get_committee_assignment(spec, state, epoch, validator_index, valid=True) + + +@with_all_phases +@spec_state_test +@never_bls +def test_get_committee_assignment_out_bound_epoch(spec, state): + epoch = spec.get_current_epoch(state) + 2 + validator_index = len(state.validators) - 1 + run_get_committee_assignment(spec, state, epoch, validator_index, valid=False) @with_all_phases @@ -92,10 +123,16 @@ def test_get_epoch_signature(spec, state): block = spec.BeaconBlock() privkey = privkeys[0] pubkey = pubkeys[0] - signature = spec.get_epoch_signature(state, block, privkey) domain = spec.get_domain(state, spec.DOMAIN_RANDAO, spec.compute_epoch_at_slot(block.slot)) - signing_root = spec.compute_signing_root(spec.compute_epoch_at_slot(block.slot), domain) - assert bls.Verify(pubkey, signing_root, signature) + run_get_signature_test( + spec=spec, + state=state, + obj=block, + domain=domain, + get_signature_fn=spec.get_epoch_signature, + privkey=privkey, + pubkey=pubkey, + ) @with_all_phases @@ -130,7 +167,7 @@ def test_is_candidate_block(spec, state): @with_all_phases @spec_state_test -def test_get_eth1_data_default_vote(spec, state): +def test_get_eth1_vote_default_vote(spec, state): min_new_period_epochs = get_min_new_period_epochs(spec) for _ in range(min_new_period_epochs): next_epoch(spec, state) @@ -143,24 +180,61 @@ def test_get_eth1_data_default_vote(spec, state): @with_all_phases @spec_state_test -def test_get_eth1_data_consensus_vote(spec, state): +def test_get_eth1_vote_consensus_vote(spec, state): min_new_period_epochs = get_min_new_period_epochs(spec) - for _ in range(min_new_period_epochs): + for _ in range(min_new_period_epochs + 2): next_epoch(spec, state) period_start = spec.voting_period_start_time(state) votes_length = spec.get_current_epoch(state) % spec.EPOCHS_PER_ETH1_VOTING_PERIOD + assert votes_length >= 3 # We need to have the majority vote state.eth1_data_votes = () - eth1_chain = [] + + block_1 = spec.Eth1Block(timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE - 1) + block_2 = spec.Eth1Block(timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE) + eth1_chain = [block_1, block_2] eth1_data_votes = [] - block = spec.Eth1Block(timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE) + + # Only the first vote is for block_1 + eth1_data_votes.append(spec.get_eth1_data(block_1)) + # Other votes are for block_2 + for _ in range(votes_length - 1): + eth1_data_votes.append(spec.get_eth1_data(block_2)) + + state.eth1_data_votes = eth1_data_votes + eth1_data = spec.get_eth1_vote(state, eth1_chain) + assert eth1_data.block_hash == block_2.hash_tree_root() + + +@with_all_phases +@spec_state_test +def test_get_eth1_vote_tie(spec, state): + min_new_period_epochs = get_min_new_period_epochs(spec) + for _ in range(min_new_period_epochs + 1): + next_epoch(spec, state) + + period_start = spec.voting_period_start_time(state) + votes_length = spec.get_current_epoch(state) % spec.EPOCHS_PER_ETH1_VOTING_PERIOD + assert votes_length > 0 and votes_length % 2 == 0 + + state.eth1_data_votes = () + block_1 = spec.Eth1Block(timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE - 1) + block_2 = spec.Eth1Block(timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE) + eth1_chain = [block_1, block_2] + eth1_data_votes = [] + # Half votes are for block_1, another half votes are for block_2 for i in range(votes_length): - eth1_chain.append(block) + if i % 2 == 0: + block = block_1 + else: + block = block_2 eth1_data_votes.append(spec.get_eth1_data(block)) state.eth1_data_votes = eth1_data_votes eth1_data = spec.get_eth1_vote(state, eth1_chain) - assert eth1_data.block_hash == block.hash_tree_root() + + # Tiebreak by smallest distance -> eth1_chain[0] + assert eth1_data.block_hash == eth1_chain[0].hash_tree_root() @with_all_phases @@ -185,10 +259,16 @@ def test_get_block_signature(spec, state): privkey = privkeys[0] pubkey = pubkeys[0] block = build_empty_block(spec, state) - signature = spec.get_block_signature(state, block, privkey) domain = spec.get_domain(state, spec.DOMAIN_BEACON_PROPOSER, spec.compute_epoch_at_slot(block.slot)) - signing_root = spec.compute_signing_root(block, domain) - assert bls.Verify(pubkey, signing_root, signature) + run_get_signature_test( + spec=spec, + state=state, + obj=block, + domain=domain, + get_signature_fn=spec.get_block_signature, + privkey=privkey, + pubkey=pubkey, + ) # Attesting @@ -200,10 +280,16 @@ def test_get_attestation_signature(spec, state): privkey = privkeys[0] pubkey = pubkeys[0] attestation_data = spec.AttestationData(slot=10) - signature = spec.get_attestation_signature(state, attestation_data, privkey) domain = spec.get_domain(state, spec.DOMAIN_BEACON_ATTESTER, attestation_data.target.epoch) - signing_root = spec.compute_signing_root(attestation_data, domain) - assert bls.Verify(pubkey, signing_root, signature) + run_get_signature_test( + spec=spec, + state=state, + obj=attestation_data, + domain=domain, + get_signature_fn=spec.get_attestation_signature, + privkey=privkey, + pubkey=pubkey, + ) # Attestation aggregation @@ -214,11 +300,17 @@ def test_get_attestation_signature(spec, state): def test_get_slot_signature(spec, state): privkey = privkeys[0] pubkey = pubkeys[0] - slot = 10 - signature = spec.get_slot_signature(state, spec.Slot(slot), privkey) + slot = spec.Slot(10) domain = spec.get_domain(state, spec.DOMAIN_SELECTION_PROOF, spec.compute_epoch_at_slot(slot)) - signing_root = spec.compute_signing_root(spec.Slot(slot), domain) - assert bls.Verify(pubkey, signing_root, signature) + run_get_signature_test( + spec=spec, + state=state, + obj=slot, + domain=domain, + get_signature_fn=spec.get_slot_signature, + privkey=privkey, + pubkey=pubkey, + ) @with_all_phases @@ -290,7 +382,13 @@ def test_get_aggregate_and_proof_signature(spec, state): pubkey = pubkeys[0] aggregate = get_mock_aggregate(spec) aggregate_and_proof = spec.get_aggregate_and_proof(state, spec.ValidatorIndex(1), aggregate, privkey) - signature = spec.get_aggregate_and_proof_signature(state, aggregate_and_proof, privkey) domain = spec.get_domain(state, spec.DOMAIN_AGGREGATE_AND_PROOF, spec.compute_epoch_at_slot(aggregate.data.slot)) - signing_root = spec.compute_signing_root(aggregate_and_proof, domain) - assert bls.Verify(pubkey, signing_root, signature) + run_get_signature_test( + spec=spec, + state=state, + obj=aggregate_and_proof, + domain=domain, + get_signature_fn=spec.get_aggregate_and_proof_signature, + privkey=privkey, + pubkey=pubkey, + ) From d311248d35684cd5aa6e47b286e075bb4feb46f4 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Mon, 27 Apr 2020 21:45:01 +0800 Subject: [PATCH 6/7] Increase `EPOCHS_PER_ETH1_VOTING_PERIOD` from `2` to `4` for testing eth1 votes consensus --- configs/minimal.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/minimal.yaml b/configs/minimal.yaml index b39a4fc01..c8b58146f 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -89,7 +89,7 @@ MIN_SEED_LOOKAHEAD: 1 # 2**2 (= 4) epochs MAX_SEED_LOOKAHEAD: 4 # [customized] higher frequency new deposits from eth1 for testing -EPOCHS_PER_ETH1_VOTING_PERIOD: 2 +EPOCHS_PER_ETH1_VOTING_PERIOD: 4 # [customized] smaller state SLOTS_PER_HISTORICAL_ROOT: 64 # 2**8 (= 256) epochs From 2dbc33327084d2814958f92eb0a838b9bc161903 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Mon, 27 Apr 2020 22:05:47 +0800 Subject: [PATCH 7/7] Make `compute_new_state_root` a pure function --- specs/phase0/validator.md | 7 ++++--- .../eth2spec/test/validator/test_validator_unittest.py | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/specs/phase0/validator.md b/specs/phase0/validator.md index 4576c4b90..cbe0c2d12 100644 --- a/specs/phase0/validator.md +++ b/specs/phase0/validator.md @@ -340,9 +340,10 @@ It is useful to be able to run a state transition function (working on a copy of ```python def compute_new_state_root(state: BeaconState, block: BeaconBlock) -> Root: - process_slots(state, block.slot) - process_block(state, block) - return hash_tree_root(state) + temp_state: BeaconState = state.copy() + signed_block = SignedBeaconBlock(message=block) + temp_state = state_transition(temp_state, signed_block, validate_result=False) + return hash_tree_root(temp_state) ``` ##### Signature diff --git a/tests/core/pyspec/eth2spec/test/validator/test_validator_unittest.py b/tests/core/pyspec/eth2spec/test/validator/test_validator_unittest.py index a655cb486..5bb246ed5 100644 --- a/tests/core/pyspec/eth2spec/test/validator/test_validator_unittest.py +++ b/tests/core/pyspec/eth2spec/test/validator/test_validator_unittest.py @@ -246,6 +246,7 @@ def test_compute_new_state_root(spec, state): state_root = spec.compute_new_state_root(state, block) assert state_root != pre_state.hash_tree_root() + assert state == pre_state # dumb verification spec.process_slots(post_state, block.slot)