def test_get_state_by_slot(valid_chain, genesis_block, genesis_state, config, keymap): # First, skip block and check if `get_state_by_slot` returns the expected state state_machine = valid_chain.get_state_machine(genesis_block.slot) state = valid_chain.get_head_state() block_skipped_slot = genesis_block.slot + 1 block_skipped_state = state_machine.state_transition.apply_state_transition( state, future_slot=block_skipped_slot) valid_chain.chaindb.persist_state(block_skipped_state) with pytest.raises(StateNotFound): valid_chain.get_state_by_slot(block_skipped_slot) # Next, import proposed block and check if `get_state_by_slot` returns the expected state proposed_slot = block_skipped_slot + 1 block = create_mock_block( state=block_skipped_state, config=config, state_machine=state_machine, signed_block_class=genesis_block.__class__, parent_block=genesis_block, keymap=keymap, slot=proposed_slot, attestations=(), ) valid_chain.import_block(block) state = valid_chain.get_head_state() assert (valid_chain.get_state_by_slot(proposed_slot).hash_tree_root == state.hash_tree_root)
def test_get_attestation_root(valid_chain, genesis_block, genesis_state, config, keymap, min_attestation_inclusion_delay): state_machine = valid_chain.get_state_machine() attestations = create_mock_signed_attestations_at_slot( state=genesis_state, config=config, state_machine=state_machine, attestation_slot=genesis_block.slot, beacon_block_root=genesis_block.signing_root, keymap=keymap, ) block = create_mock_block( state=genesis_state, config=config, state_machine=state_machine, block_class=genesis_block.__class__, parent_block=genesis_block, keymap=keymap, slot=genesis_state.slot + 1, attestations=attestations, ) valid_chain.import_block(block) # Only one attestation in attestations, so just check that one a0 = attestations[0] assert valid_chain.get_attestation_by_root(a0.root) == a0 assert valid_chain.attestation_exists(a0.root) fake_attestation = a0.copy(signature=b'\x78' * 96, ) with pytest.raises(AttestationRootNotFound): valid_chain.get_attestation_by_root(fake_attestation.root) assert not valid_chain.attestation_exists(fake_attestation.root)
def test_per_slot_transition( chaindb, genesis_block, genesis_state, fixture_sm_class, config, state_slot, fork_choice_scoring, empty_attestation_pool, keymap, ): chaindb.persist_block(genesis_block, SerenityBeaconBlock, fork_choice_scoring) chaindb.persist_state(genesis_state) state = genesis_state # Create a block block = create_mock_block( state=state, config=config, state_machine=fixture_sm_class(chaindb, empty_attestation_pool, genesis_block.slot), block_class=SerenityBeaconBlock, parent_block=genesis_block, keymap=keymap, slot=state_slot, ) # Store in chaindb chaindb.persist_block(block, SerenityBeaconBlock, fork_choice_scoring) # Get state machine instance sm = fixture_sm_class(chaindb, empty_attestation_pool, block.slot) # Get state transition instance st = sm.state_transition_class(sm.config) updated_state = st.apply_state_transition(state, future_slot=state.slot + 1) # Ensure that slot gets increased by 1 assert updated_state.slot == state.slot + 1 # block_roots roots_index = (updated_state.slot - 1) % st.config.SLOTS_PER_HISTORICAL_ROOT assert updated_state.block_roots[roots_index] == block.parent_root # state_roots assert updated_state.state_roots[roots_index] == state.hash_tree_root # historical_roots if updated_state.slot % st.config.SLOTS_PER_HISTORICAL_ROOT == 0: historical_batch = HistoricalBatch(block_roots=state.block_roots, state_roots=state.state_roots) assert updated_state.historical_roots[ -1] == historical_batch.hash_tree_root else: assert updated_state.historical_roots == state.historical_roots
def test_import_blocks(valid_chain, genesis_block, genesis_state, config, keymap): state = genesis_state blocks = tuple() valid_chain_2 = copy.deepcopy(valid_chain) for i in range(3): block = create_mock_block( state=state, config=config, block_class=genesis_block.__class__, parent_block=genesis_block, keymap=keymap, slot=state.slot + 2, ) valid_chain.import_block(block) state = valid_chain.get_state_machine(block).state assert block == valid_chain.get_canonical_block_by_slot(block.slot) assert block.root == valid_chain.get_canonical_block_root(block.slot) blocks += (block, ) assert valid_chain.get_canonical_head( ) != valid_chain_2.get_canonical_head() for block in blocks: valid_chain_2.import_block(block) assert valid_chain.get_canonical_head( ) == valid_chain_2.get_canonical_head() assert (valid_chain.get_state_machine( blocks[-1]).state == valid_chain_2.get_state_machine(blocks[-1]).state)
def test_get_state_by_slot(valid_chain, genesis_block, genesis_state, config, keymap): # Fisrt, skip block and check if `get_state_by_slot` returns the expected state state_machine = valid_chain.get_state_machine(genesis_block.slot) state = state_machine.state block_skipped_slot = genesis_block.slot + 1 block_skipped_state = state_machine.state_transition.apply_state_transition_without_block( state, block_skipped_slot, ) with pytest.raises(StateSlotNotFound): valid_chain.get_state_by_slot(block_skipped_slot) valid_chain.chaindb.persist_state(block_skipped_state) assert valid_chain.get_state_by_slot(block_skipped_slot).root == block_skipped_state.root # Next, import proposed block and check if `get_state_by_slot` returns the expected state proposed_slot = block_skipped_slot + 1 block = create_mock_block( state=block_skipped_state, config=config, state_machine=state_machine, block_class=genesis_block.__class__, parent_block=genesis_block, keymap=keymap, slot=proposed_slot, attestations=(), ) valid_chain.import_block(block) state = valid_chain.get_state_machine().state assert valid_chain.get_state_by_slot(proposed_slot).root == state.root
def test_import_blocks(valid_chain, genesis_block, genesis_state, config, keymap): state = genesis_state blocks = (genesis_block,) valid_chain_2 = copy.deepcopy(valid_chain) for _ in range(3): block = create_mock_block( state=state, config=config, state_machine=valid_chain.get_state_machine(blocks[-1].slot), block_class=genesis_block.__class__, parent_block=blocks[-1], keymap=keymap, slot=state.slot + 2, ) valid_chain.import_block(block) assert valid_chain.get_canonical_head() == block state = valid_chain.get_state_by_slot(block.slot) assert block == valid_chain.get_canonical_block_by_slot(block.slot) assert block.signing_root == valid_chain.get_canonical_block_root(block.slot) blocks += (block,) assert valid_chain.get_canonical_head() != valid_chain_2.get_canonical_head() for block in blocks[1:]: valid_chain_2.import_block(block) assert valid_chain.get_canonical_head() == valid_chain_2.get_canonical_head() assert valid_chain.get_state_by_slot(blocks[-1].slot).slot != 0 assert valid_chain.get_state_by_slot( blocks[-1].slot ) == valid_chain_2.get_state_by_slot(blocks[-1].slot)
def test_per_slot_transition(base_db, genesis_block, genesis_state, fixture_sm_class, config, state_slot, keymap): chaindb = BeaconChainDB(base_db) chaindb.persist_block(genesis_block, SerenityBeaconBlock) chaindb.persist_state(genesis_state) state = genesis_state # Create a block block = create_mock_block( state=state, config=config, state_machine=fixture_sm_class( chaindb, genesis_block, ), block_class=SerenityBeaconBlock, parent_block=genesis_block, keymap=keymap, slot=state_slot, ) # Store in chaindb chaindb.persist_block(block, SerenityBeaconBlock) # Get state machine instance sm = fixture_sm_class( chaindb, block, ) # Get state transition instance st = sm.state_transition_class(sm.config) # NOTE: we want to run both functions, however they are run independently # so we have two function calls updated_state = st.cache_state(state) updated_state = st.per_slot_transition(updated_state) # Ensure that slot gets increased by 1 assert updated_state.slot == state.slot + 1 # latest_block_roots latest_block_roots_index = (updated_state.slot - 1) % st.config.SLOTS_PER_HISTORICAL_ROOT assert updated_state.latest_block_roots[ latest_block_roots_index] == block.previous_block_root # historical_roots if updated_state.slot % st.config.SLOTS_PER_HISTORICAL_ROOT == 0: historical_batch = HistoricalBatch( block_roots=state.latest_block_roots, state_roots=state.latest_state_roots, slots_per_historical_root=config.SLOTS_PER_HISTORICAL_ROOT, ) assert updated_state.historical_roots[ -1] == historical_batch.hash_tree_root else: assert updated_state.historical_roots == state.historical_roots
def test_per_slot_transition(base_db, genesis_block, genesis_state, fixture_sm_class, config, state_slot, keymap): chaindb = BeaconChainDB(base_db) chaindb.persist_block(genesis_block, SerenityBeaconBlock) chaindb.persist_state(genesis_state) state = genesis_state # Create a block block = create_mock_block( state=state, config=config, state_machine=fixture_sm_class( chaindb, genesis_block, ), block_class=SerenityBeaconBlock, parent_block=genesis_block, keymap=keymap, slot=state_slot, ) # Store in chaindb chaindb.persist_block(block, SerenityBeaconBlock) # Get state machine instance sm = fixture_sm_class( chaindb, block, ) # Get state transition instance st = sm.state_transition_class(sm.config) updated_state = st.per_slot_transition(state, block.parent_root) # Ensure that slot gets increased by 1 assert updated_state.slot == state.slot + 1 # latest_block_roots latest_block_roots_index = (updated_state.slot - 1) % st.config.SLOTS_PER_HISTORICAL_ROOT assert updated_state.latest_block_roots[latest_block_roots_index] == block.parent_root # historical_roots if updated_state.slot % st.config.SLOTS_PER_HISTORICAL_ROOT == 0: assert updated_state.historical_roots[-1] == get_merkle_root( updated_state.latest_block_roots ) else: assert updated_state.historical_roots == state.historical_roots
def test_demo(base_db, validator_count, keymap, pubkeys, fork_choice_scoring): bls.use_noop_backend() slots_per_epoch = 8 config = SERENITY_CONFIG._replace( SLOTS_PER_EPOCH=slots_per_epoch, GENESIS_EPOCH=slot_to_epoch(SERENITY_CONFIG.GENESIS_SLOT, slots_per_epoch), TARGET_COMMITTEE_SIZE=3, SHARD_COUNT=2, MIN_ATTESTATION_INCLUSION_DELAY=2, ) override_vector_lengths(config) fixture_sm_class = SerenityStateMachine.configure( __name__='SerenityStateMachineForTesting', config=config, ) genesis_slot = config.GENESIS_SLOT genesis_epoch = config.GENESIS_EPOCH chaindb = BeaconChainDB(base_db, config) attestation_pool = AttestationPool() # TODO(ralexstokes) clean up how the cache is populated for i in range(validator_count): pubkeys[i] genesis_state, genesis_block = create_mock_genesis( num_validators=validator_count, config=config, keymap=keymap, genesis_block_class=SerenityBeaconBlock, ) for i in range(validator_count): assert genesis_state.validators[i].is_active(genesis_slot) chaindb.persist_block(genesis_block, SerenityBeaconBlock, fork_choice_scoring) chaindb.persist_state(genesis_state) state = genesis_state block = genesis_block chain_length = 3 * config.SLOTS_PER_EPOCH blocks = (block, ) attestations_map = {} # Dict[Slot, Sequence[Attestation]] for current_slot in range(genesis_slot + 1, genesis_slot + chain_length + 1): if current_slot > genesis_slot + config.MIN_ATTESTATION_INCLUSION_DELAY: attestations = attestations_map[ current_slot - config.MIN_ATTESTATION_INCLUSION_DELAY] else: attestations = () block = create_mock_block( state=state, config=config, state_machine=fixture_sm_class( chaindb, attestation_pool, blocks[-1].slot, ), block_class=SerenityBeaconBlock, parent_block=block, keymap=keymap, slot=current_slot, attestations=attestations, ) # Get state machine instance sm = fixture_sm_class( chaindb, attestation_pool, blocks[-1].slot, ) state, _ = sm.import_block(block) chaindb.persist_state(state) chaindb.persist_block(block, SerenityBeaconBlock, fork_choice_scoring) blocks += (block, ) # Mock attestations attestation_slot = current_slot attestations = create_mock_signed_attestations_at_slot( state=state, config=config, state_machine=fixture_sm_class( chaindb, attestation_pool, block.slot, ), attestation_slot=attestation_slot, beacon_block_root=block.signing_root, keymap=keymap, voted_attesters_ratio=1.0, ) attestations_map[attestation_slot] = attestations assert state.slot == chain_length + genesis_slot # Justification assertions assert state.current_justified_epoch == genesis_epoch assert state.finalized_epoch == genesis_epoch
def test_demo(base_db, num_validators, config, keymap, fixture_sm_class): genesis_slot = config.GENESIS_SLOT genesis_epoch = config.GENESIS_EPOCH chaindb = BeaconChainDB(base_db) genesis_state, genesis_block = create_mock_genesis( num_validators=num_validators, config=config, keymap=keymap, genesis_block_class=SerenityBeaconBlock, ) for i in range(num_validators): assert genesis_state.validator_registry[i].is_active(genesis_slot) chaindb.persist_block(genesis_block, SerenityBeaconBlock) chaindb.persist_state(genesis_state) state = genesis_state block = genesis_block chain_length = 3 * config.SLOTS_PER_EPOCH blocks = (block, ) attestations_map = {} # Dict[Slot, Sequence[Attestation]] for current_slot in range(genesis_slot + 1, genesis_slot + chain_length + 1): if current_slot > genesis_slot + config.MIN_ATTESTATION_INCLUSION_DELAY: attestations = attestations_map[ current_slot - config.MIN_ATTESTATION_INCLUSION_DELAY] else: attestations = () block = create_mock_block( state=state, config=config, state_machine=fixture_sm_class( chaindb, blocks[-1], ), block_class=SerenityBeaconBlock, parent_block=block, keymap=keymap, slot=current_slot, attestations=attestations, ) # Get state machine instance sm = fixture_sm_class( chaindb, blocks[-1], ) state, _ = sm.import_block(block) chaindb.persist_state(state) chaindb.persist_block(block, SerenityBeaconBlock) blocks += (block, ) # Mock attestations attestation_slot = current_slot attestations = create_mock_signed_attestations_at_slot( state=state, config=config, state_machine=fixture_sm_class( chaindb, block, ), attestation_slot=attestation_slot, beacon_block_root=block.signed_root, keymap=keymap, voted_attesters_ratio=1.0, ) attestations_map[attestation_slot] = attestations assert state.slot == chain_length + genesis_slot assert isinstance(sm.block, SerenityBeaconBlock) # Justification assertions assert state.current_justified_epoch == 2 + genesis_epoch assert state.finalized_epoch == 1 + genesis_epoch
def test_demo(base_db, validator_count, keymap, pubkeys, fork_choice_scoring): bls.use_noop_backend() config = MINIMAL_SERENITY_CONFIG override_lengths(config) fixture_sm_class = SerenityStateMachine.configure( __name__="SerenityStateMachineForTesting", config=config) genesis_slot = config.GENESIS_SLOT genesis_epoch = config.GENESIS_EPOCH chaindb = BeaconChainDB(base_db, config) genesis_state, genesis_block = create_mock_genesis( pubkeys=pubkeys[:validator_count], config=config, keymap=keymap, genesis_block_class=SerenityBeaconBlock, ) for i in range(validator_count): assert genesis_state.validators[i].is_active(genesis_slot) chaindb.persist_block( SerenitySignedBeaconBlock.create(message=genesis_block), SerenitySignedBeaconBlock, fork_choice_scoring, ) chaindb.persist_state(genesis_state) state = genesis_state block = SerenitySignedBeaconBlock.create(message=genesis_block) chain_length = 4 * config.SLOTS_PER_EPOCH blocks = (block, ) attestations_map = {} # Dict[Slot, Sequence[Attestation]] for current_slot in range(genesis_slot + 1, genesis_slot + chain_length + 1): if current_slot > genesis_slot + config.MIN_ATTESTATION_INCLUSION_DELAY: attestations = attestations_map[ current_slot - config.MIN_ATTESTATION_INCLUSION_DELAY] else: attestations = () block = create_mock_block( state=state, config=config, state_machine=fixture_sm_class(chaindb), signed_block_class=SerenitySignedBeaconBlock, parent_block=block, keymap=keymap, slot=current_slot, attestations=attestations, ) # Get state machine instance sm = fixture_sm_class(chaindb) state, _ = sm.import_block(block, state) chaindb.persist_state(state) chaindb.persist_block(block, SerenitySignedBeaconBlock, fork_choice_scoring) blocks += (block, ) # Mock attestations attestation_slot = current_slot attestations = create_mock_signed_attestations_at_slot( state=state, config=config, state_machine=fixture_sm_class(chaindb), attestation_slot=attestation_slot, beacon_block_root=block.signing_root, keymap=keymap, voted_attesters_ratio=1.0, ) attestations_map[attestation_slot] = attestations assert state.slot == chain_length + genesis_slot # Justification assertions # NOTE: why are the number `2` or `3` used in the checks below? # Answer: # "We do not check any justification and finality during epochs 0 or 1. We do check for # justification and finality from epoch 2 onward." # [epoch 0]------[epoch 1]------> # # "In epoch 2, we justify the current epoch. This epoch is in fact justified but we do not # recognize it in the protocol due to an artifact of the construction of the genesis state # (using the `zero` value for `Checkpoint` type)." # [epoch 0]------[epoch 1]------[epoch 2]*------> # []*: checkpoint justified # []**: checkpoint finalized # # "In epoch 3, we have the previous justified checkpoint at the prior current justified # checkpoint (so `GENESIS_EPOCH + 2`) and we justify this current epoch. we check finality here # and see that we finalize the prior justified checkpoint at epoch 2." # [epoch 0]------[epoch 1]------[epoch 2]**------[epoch 3]*------> # # "Given the way we handle epoch processing (i.e. process a given epoch at the start of # the next epoch), we need to transition through `4 * SLOTS_PER_EPOCH` worth of slots to # include the processing of epoch 3." # # source: https://github.com/ethereum/trinity/pull/1214#issuecomment-546184080 # # epoch | prev_justified_checkpoint | cur_justified_checkpoint | finalized_checkpoint # ------|---------------------------|--------------------------|--------------------- # 0 | 0 | 0 | 0 # 1 | 0 | 0 | 0 # 2 | 0 | 0 | 0 # 3 | 0 | 2 | 0 # 4 | 2 | 3 | 2 assert state.previous_justified_checkpoint.epoch == 2 + genesis_epoch assert state.current_justified_checkpoint.epoch == 3 + genesis_epoch assert state.finalized_checkpoint.epoch == 2 + genesis_epoch
def test_per_slot_transition(base_db, genesis_block, genesis_state, fixture_sm_class, config, state_slot, keymap): chaindb = BeaconChainDB(base_db) chaindb.persist_block(genesis_block, SerenityBeaconBlock) chaindb.persist_state(genesis_state) state = genesis_state # Create a block block = create_mock_block( state=state, config=config, state_machine=fixture_sm_class( chaindb, genesis_block, ), block_class=SerenityBeaconBlock, parent_block=genesis_block, keymap=keymap, slot=state_slot, ) # Store in chaindb chaindb.persist_block(block, SerenityBeaconBlock) # Get state machine instance sm = fixture_sm_class( chaindb, block, ) # Get state transition instance st = sm.state_transition_class(sm.config) updated_state = st.per_slot_transition(state, block.parent_root) # Ensure that slot gets increased by 1 assert updated_state.slot == state.slot + 1 # Validator Registry # Tweaking the slot, so that we get the correct proposer index beacon_proposer_index = get_beacon_proposer_index( state, state.slot + 1, st.config.GENESIS_EPOCH, st.config.EPOCH_LENGTH, st.config.TARGET_COMMITTEE_SIZE, st.config.SHARD_COUNT, ) for validator_index, _ in enumerate(updated_state.validator_registry): if validator_index != beacon_proposer_index: # Validator Record shouldn't change if not proposer assert (updated_state.validator_registry[validator_index] == state.validator_registry[validator_index]) else: # randao layers of proposer's record should increase by 1 assert ( updated_state.validator_registry[validator_index].randao_layers == state.validator_registry[validator_index].randao_layers + 1) # latest_randao_mixes assert ( updated_state.latest_randao_mixes[updated_state.slot % st.config.LATEST_RANDAO_MIXES_LENGTH] == state.latest_randao_mixes[(state.slot) % st.config.LATEST_RANDAO_MIXES_LENGTH]) # latest_block_roots latest_block_roots_index = (updated_state.slot - 1) % st.config.LATEST_BLOCK_ROOTS_LENGTH assert updated_state.latest_block_roots[ latest_block_roots_index] == block.parent_root # batched_block_roots if updated_state.slot % st.config.LATEST_BLOCK_ROOTS_LENGTH == 0: assert updated_state.batched_block_roots[-1] == get_merkle_root( updated_state.latest_block_roots) else: assert updated_state.batched_block_roots == state.batched_block_roots
def test_demo(base_db, keymap): slots_per_epoch = 8 config = SERENITY_CONFIG._replace( SLOTS_PER_EPOCH=slots_per_epoch, GENESIS_EPOCH=slot_to_epoch(SERENITY_CONFIG.GENESIS_SLOT, slots_per_epoch), TARGET_COMMITTEE_SIZE=3, SHARD_COUNT=2, MIN_ATTESTATION_INCLUSION_DELAY=2, ) fixture_sm_class = SerenityStateMachine.configure( __name__='SerenityStateMachineForTesting', config=config, ) num_validators = 40 genesis_slot = config.GENESIS_SLOT genesis_epoch = config.GENESIS_EPOCH chaindb = BeaconChainDB(base_db, config) genesis_state, genesis_block = create_mock_genesis( num_validators=num_validators, config=config, keymap=keymap, genesis_block_class=SerenityBeaconBlock, ) for i in range(num_validators): assert genesis_state.validator_registry[i].is_active(genesis_slot) chaindb.persist_block(genesis_block, SerenityBeaconBlock) chaindb.persist_state(genesis_state) state = genesis_state block = genesis_block chain_length = 3 * config.SLOTS_PER_EPOCH blocks = (block, ) attestations_map = {} # Dict[Slot, Sequence[Attestation]] for current_slot in range(genesis_slot + 1, genesis_slot + chain_length + 1): if current_slot > genesis_slot + config.MIN_ATTESTATION_INCLUSION_DELAY: attestations = attestations_map[ current_slot - config.MIN_ATTESTATION_INCLUSION_DELAY] else: attestations = () block = create_mock_block( state=state, config=config, state_machine=fixture_sm_class( chaindb, blocks[-1], ), block_class=SerenityBeaconBlock, parent_block=block, keymap=keymap, slot=current_slot, attestations=attestations, ) # Get state machine instance sm = fixture_sm_class( chaindb, blocks[-1], ) state, _ = sm.import_block(block) chaindb.persist_state(state) chaindb.persist_block(block, SerenityBeaconBlock) blocks += (block, ) # Mock attestations attestation_slot = current_slot attestations = create_mock_signed_attestations_at_slot( state=state, config=config, state_machine=fixture_sm_class( chaindb, block, ), attestation_slot=attestation_slot, beacon_block_root=block.signing_root, keymap=keymap, voted_attesters_ratio=1.0, ) attestations_map[attestation_slot] = attestations assert state.slot == chain_length + genesis_slot assert isinstance(sm.block, SerenityBeaconBlock) # Justification assertions assert state.current_justified_epoch == 2 + genesis_epoch assert state.finalized_epoch == 1 + genesis_epoch
def test_demo(base_db, num_validators, config, keymap, fixture_sm_class): chaindb = BeaconChainDB(base_db) genesis_state, genesis_block = create_mock_genesis( num_validators=num_validators, config=config, keymap=keymap, genesis_block_class=SerenityBeaconBlock, ) for i in range(num_validators): assert genesis_state.validator_registry[i].is_active(0) chaindb.persist_block(genesis_block, SerenityBeaconBlock) chaindb.persist_state(genesis_state) state = genesis_state current_slot = 1 chain_length = 3 * config.EPOCH_LENGTH attestations = () for current_slot in range(chain_length): # two epochs block = create_mock_block( state=state, config=config, block_class=SerenityBeaconBlock, parent_block=genesis_block, keymap=keymap, slot=current_slot, attestations=attestations, ) block = block.copy( body=block.body.copy( attestations=attestations, ) ) # Get state machine instance sm = fixture_sm_class( chaindb, block, parent_block_class=SerenityBeaconBlock, ) state, _ = sm.import_block(block) # TODO: move to chain level? block = block.copy( state_root=state.root, ) chaindb.persist_state(state) chaindb.persist_block(block, SerenityBeaconBlock) if current_slot > config.MIN_ATTESTATION_INCLUSION_DELAY: attestation_slot = current_slot - config.MIN_ATTESTATION_INCLUSION_DELAY attestations = create_mock_signed_attestations_at_slot( state, config, attestation_slot, keymap, 1.0, ) else: attestations = () assert state.slot == chain_length - 1 assert isinstance(sm.block, SerenityBeaconBlock)