def fixture_sm_class(config, fork_choice_scoring, fork_choice_scoring_class): return SerenityStateMachine.configure( __name__="SerenityStateMachineForTesting", config=config, get_fork_choice_scoring=lambda self: fork_choice_scoring, fork_choice_scoring_class=fork_choice_scoring_class, )
def execute_state_transtion(test_case, base_db): bls.use_noop_backend() dict_config = test_case['config'] verify_signatures = test_case['verify_signatures'] dict_initial_state = test_case['initial_state'] dict_blocks = test_case['blocks'] dict_expected_state = test_case['expected_state'] # TODO: make it case by case assert verify_signatures is False # Set config config = generate_config_by_dict(dict_config) # Set Vector fields override_vector_lengths(config) # Set pre_state pre_state = from_formatted_dict(dict_initial_state, BeaconState) # Set blocks blocks = () for dict_block in dict_blocks: block = from_formatted_dict(dict_block, SerenityBeaconBlock) blocks += (block, ) sm_class = SerenityStateMachine.configure( __name__='SerenityStateMachineForTesting', config=config, ) chaindb = BeaconChainDB(base_db, Eth2GenesisConfig(config)) attestation_pool = AttestationPool() post_state = pre_state.copy() for block in blocks: sm = sm_class(chaindb, attestation_pool, None, post_state) post_state, _ = sm.import_block(block) # Use dict diff, easier to see the diff dict_post_state = to_formatted_dict(post_state, BeaconState) for key, value in dict_expected_state.items(): if isinstance(value, list): value = tuple(value) assert dict_post_state[key] == value
def fixture_sm_class(config): return SerenityStateMachine.configure( __name__='SerenityStateMachineForTesting', config=config, )
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, 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 get_sm_class_of_config(config): return SerenityStateMachine.configure( __name__='SerenityStateMachineForTesting', config=config, )
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