def test_get_block_committees_info(monkeypatch, sample_block, sample_state, num_validators, committee, parent_block_number, result_proposer_index, epoch_length): from eth.beacon import helpers def mock_get_shard_committees_at_slot(state, slot, epoch_length): return (ShardCommittee( shard=1, committee=committee, total_validator_count=num_validators, ), ) monkeypatch.setattr(helpers, 'get_shard_committees_at_slot', mock_get_shard_committees_at_slot) parent_block = sample_block parent_block = sample_block.copy(slot=parent_block_number, ) if isinstance(result_proposer_index, Exception): with pytest.raises(ValidationError): get_block_committees_info( parent_block, sample_state, epoch_length, ) else: block_committees_info = get_block_committees_info( parent_block, sample_state, epoch_length, ) assert (block_committees_info.proposer_index == result_proposer_index)
def test_get_block_committees_info(monkeypatch, genesis_block, genesis_crystallized_state, committee, parent_block_number, result_proposer_index_in_committee, cycle_length): from eth.beacon import helpers def mock_get_shards_and_committees_for_slot(parent_block, crystallized_state, cycle_length): return [ ShardAndCommittee(shard_id=1, committee=committee), ] monkeypatch.setattr(helpers, 'get_shards_and_committees_for_slot', mock_get_shards_and_committees_for_slot) parent_block = genesis_block parent_block = genesis_block.copy(slot_number=parent_block_number, ) if isinstance(result_proposer_index_in_committee, Exception): with pytest.raises(ValueError): get_block_committees_info( parent_block, genesis_crystallized_state, cycle_length, ) else: block_committees_info = get_block_committees_info( parent_block, genesis_crystallized_state, cycle_length, ) assert (block_committees_info.proposer_index_in_committee == result_proposer_index_in_committee)
def attest_proposed_block(cls, post_crystallized_state: CrystallizedState, post_active_state: ActiveState, block_proposal: 'BlockProposal', chaindb: BaseBeaconChainDB, private_key: int) -> 'AttestationRecord': """ Return the initial attestation by the block proposer. The proposer broadcasts their attestation with the proposed block. """ block_committees_info = get_block_committees_info( block_proposal.block, post_crystallized_state, cls.config.CYCLE_LENGTH, ) # Vote attester_bitfield = set_voted( get_empty_bitfield(block_committees_info.proposer_committee_size), block_committees_info.proposer_index_in_committee, ) # Get justified_slot and justified_block_hash justified_slot = post_crystallized_state.last_justified_slot justified_block_hash = chaindb.get_canonical_block_hash_by_slot( justified_slot) # Get signing message and sign it parent_hashes = get_hashes_to_sign( post_active_state.recent_block_hashes, block_proposal.block, cls.config.CYCLE_LENGTH, ) message = create_signing_message( block_proposal.block.slot_number, parent_hashes, block_proposal.shard_id, block_proposal.shard_block_hash, justified_slot, ) sig = bls.sign( message, private_key, ) return cls.get_attestation_record_class()( slot=block_proposal.block.slot_number, shard_id=block_proposal.shard_id, oblique_parent_hashes=(), shard_block_hash=block_proposal.shard_block_hash, attester_bitfield=attester_bitfield, justified_slot=justified_slot, justified_block_hash=justified_block_hash, aggregate_sig=sig, )
def attestation_validation_fixture(fixture_sm_class, initial_chaindb, genesis_block, privkeys): # NOTE: Copied from `test_proposer.py`, might need to refactor it. chaindb = initial_chaindb # Propose a block block_1_shell = genesis_block.copy( parent_hash=genesis_block.hash, slot_number=genesis_block.slot_number + 1, ) sm = fixture_sm_class(chaindb, block_1_shell) # The proposer of block_1 block_committees_info = (get_block_committees_info( block_1_shell, sm.crystallized_state, sm.config.CYCLE_LENGTH, )) # public_key = sm.crystallized_state.validators[block_committees_info.proposer_index].pubkey private_key = privkeys[block_committees_info.proposer_index] block_proposal = BlockProposal( block=block_1_shell, shard_id=block_committees_info.proposer_shard_id, shard_block_hash=ZERO_HASH32, ) (block_1, post_crystallized_state, post_active_state, proposer_attestation) = (sm.propose_block( crystallized_state=sm.crystallized_state, active_state=sm.active_state, block_proposal=block_proposal, chaindb=sm.chaindb, config=sm.config, private_key=private_key, )) # Block 2 # Manually update state for testing sm._update_the_states(post_crystallized_state, post_active_state) # Validate the attestation block_2_shell = block_1.copy( parent_hash=block_1.hash, slot_number=block_1.slot_number + 1, attestations=[proposer_attestation], ) recent_block_hashes = get_new_recent_block_hashes( sm.active_state.recent_block_hashes, block_1.slot_number, block_2_shell.slot_number, block_1.hash) filled_active_state = sm.active_state.copy( recent_block_hashes=recent_block_hashes, ) return (post_crystallized_state, filled_active_state, proposer_attestation, block_2_shell, block_1, sm.chaindb)
def validate_parent_block_proposer(crystallized_state: 'CrystallizedState', block: 'BaseBeaconBlock', parent_block: 'BaseBeaconBlock', cycle_length: int) -> None: if block.slot_number == 0: return block_committees_info = get_block_committees_info( parent_block, crystallized_state, cycle_length, ) try: attestation = block.attestations[0] except IndexError: raise ValidationError("block.attestations should not be an empty list") is_proposer_attestation = ( attestation.shard_id == block_committees_info.proposer_shard_id and attestation.slot == parent_block.slot_number and has_voted(attestation.attester_bitfield, block_committees_info.proposer_index_in_committee)) if not is_proposer_attestation: raise ValidationError( "Proposer of parent block should be one of the attesters in block.attestions[0]:\n" "\tExpected: proposer index in committee: %d, shard_id: %d, slot: %d\n" "\tFound: shard_id: %d, slot: %d, voted: %s" % ( block_committees_info.proposer_index_in_committee, block_committees_info.proposer_shard_id, parent_block.slot_number, attestation.shard_id, attestation.slot, has_voted( attestation.attester_bitfield, block_committees_info.proposer_index_in_committee, ), ))
def test_propose_block(fixture_sm_class, initial_chaindb, genesis_block, privkeys): chaindb = initial_chaindb # Propose a block block_1_shell = genesis_block.copy( parent_hash=genesis_block.hash, slot_number=genesis_block.slot_number + 1, ) sm = fixture_sm_class(chaindb, block_1_shell) # # The proposer of block_1 # block_committees_info = ( get_block_committees_info( block_1_shell, sm.crystallized_state, sm.config.CYCLE_LENGTH, ) ) private_key = privkeys[block_committees_info.proposer_index] block_proposal = BlockProposal( block=block_1_shell, shard_id=block_committees_info.proposer_shard_id, shard_block_hash=ZERO_HASH32, ) (block_1, post_crystallized_state, post_active_state, proposer_attestation) = ( sm.propose_block( crystallized_state=sm.crystallized_state, active_state=sm.active_state, block_proposal=block_proposal, chaindb=sm.chaindb, config=sm.config, private_key=private_key, ) ) expect_block_1 = block_1_shell.copy( active_state_root=post_active_state.hash, crystallized_state_root=post_crystallized_state.hash, ) assert block_1.hash == expect_block_1.hash # Persist block_1 sm.import_block(block_1) sm.chaindb.persist_block(block_1) # Validate the attestation block_2_shell = block_1.copy( parent_hash=block_1.hash, slot_number=block_1.slot_number + 1, attestations=(proposer_attestation, ), ) # Validate the parent block proposer validate_parent_block_proposer( sm.crystallized_state, block_2_shell, block_1, sm.config.CYCLE_LENGTH, ) assert has_voted( proposer_attestation.attester_bitfield, block_committees_info.proposer_index_in_committee ) # # The proposer of block_2 # block_committees_info = ( get_block_committees_info( block_2_shell, sm.crystallized_state, sm.config.CYCLE_LENGTH, ) ) private_key = privkeys[block_committees_info.proposer_index] block_proposal = BlockProposal( block=block_2_shell, shard_id=block_committees_info.proposer_shard_id, shard_block_hash=ZERO_HASH32, ) (block_2, post_crystallized_state, post_active_state, proposer_attestation) = ( sm.propose_block( crystallized_state=sm.crystallized_state, active_state=sm.active_state, block_proposal=block_proposal, chaindb=sm.chaindb, config=sm.config, private_key=private_key, ) ) expect_block_2 = block_2_shell.copy( active_state_root=post_active_state.hash, crystallized_state_root=post_crystallized_state.hash, ) assert block_2.hash == expect_block_2.hash