示例#1
0
def test_basic(spec, state):
    spec.PHASE_1_GENESIS_SLOT = 0  # NOTE: mock genesis slot here
    state = spec.upgrade_to_phase1(state)
    shard = spec.Shard(1)

    # Initialization
    store = spec.get_forkchoice_store(state)
    anchor_root = get_anchor_root(spec, state)
    assert spec.get_head(store) == anchor_root

    shard_store = spec.get_forkchoice_shard_store(state, shard)
    shard_head_root = spec.get_shard_head(store, shard_store)
    assert shard_head_root == state.shard_states[shard].latest_block_root
    assert shard_store.block_states[shard_head_root].slot == 1
    assert shard_store.block_states[shard_head_root] == state.shard_states[
        shard]

    # For mainnet config, it's possible that only one committee of `shard` per epoch.
    # we set this counter to test more rounds.
    shard_committee_counter = 2
    shard_blocks_buffer = []
    while shard_committee_counter > 0:
        has_shard_committee = apply_shard_and_beacon(spec, state, store,
                                                     shard_store,
                                                     shard_blocks_buffer)
        if has_shard_committee:
            shard_committee_counter -= 1
示例#2
0
def test_chain_no_attestations(spec, state):
    test_steps = []
    # Initialization
    store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state)
    yield 'anchor_state', state
    yield 'anchor_block', anchor_block

    anchor_root = get_anchor_root(spec, state)
    assert spec.get_head(store) == anchor_root
    test_steps.append(
        {'checks': {
            'head': get_formatted_head_output(spec, store),
        }})

    # On receiving a block of `GENESIS_SLOT + 1` slot
    block_1 = build_empty_block_for_next_slot(spec, state)
    signed_block_1 = state_transition_and_sign_block(spec, state, block_1)
    yield from tick_and_add_block(spec, store, signed_block_1, test_steps)

    # On receiving a block of next epoch
    block_2 = build_empty_block_for_next_slot(spec, state)
    signed_block_2 = state_transition_and_sign_block(spec, state, block_2)
    yield from tick_and_add_block(spec, store, signed_block_2, test_steps)

    assert spec.get_head(store) == spec.hash_tree_root(block_2)
    test_steps.append(
        {'checks': {
            'head': get_formatted_head_output(spec, store),
        }})

    yield 'steps', test_steps
def test_shorter_chain_but_heavier_weight(spec, state):
    genesis_state = state.copy()

    # Initialization
    store = get_genesis_forkchoice_store(spec, state)
    anchor_root = get_anchor_root(spec, state)
    assert spec.get_head(store) == anchor_root

    # build longer tree
    long_state = genesis_state.copy()
    for _ in range(3):
        long_block = build_empty_block_for_next_slot(spec, long_state)
        signed_long_block = state_transition_and_sign_block(spec, long_state, long_block)
        add_block_to_store(spec, store, signed_long_block)

    # build short tree
    short_state = genesis_state.copy()
    short_block = build_empty_block_for_next_slot(spec, short_state)
    short_block.body.graffiti = b'\x42' * 32
    signed_short_block = state_transition_and_sign_block(spec, short_state, short_block)
    add_block_to_store(spec, store, signed_short_block)

    short_attestation = get_valid_attestation(spec, short_state, short_block.slot, signed=True)
    add_attestation_to_store(spec, store, short_attestation)

    assert spec.get_head(store) == spec.hash_tree_root(short_block)
def initialize_store(spec, state, shards):
    store = get_genesis_forkchoice_store(spec, state)
    anchor_root = get_anchor_root(spec, state)
    assert spec.get_head(store) == anchor_root

    for shard in shards:
        shard_head_root = spec.get_shard_head(store, shard)
        assert shard_head_root == state.shard_states[shard].latest_block_root
        shard_store = store.shard_stores[shard]
        assert shard_store.block_states[shard_head_root].slot == 0
        assert shard_store.block_states[shard_head_root] == state.shard_states[shard]

    return store
示例#5
0
def test_shorter_chain_but_heavier_weight(spec, state):
    test_steps = []
    genesis_state = state.copy()

    # Initialization
    store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state)
    yield 'anchor_state', state
    yield 'anchor_block', anchor_block
    anchor_root = get_anchor_root(spec, state)
    assert spec.get_head(store) == anchor_root
    test_steps.append(
        {'checks': {
            'head': get_formatted_head_output(spec, store),
        }})

    # build longer tree
    long_state = genesis_state.copy()
    for _ in range(3):
        long_block = build_empty_block_for_next_slot(spec, long_state)
        signed_long_block = state_transition_and_sign_block(
            spec, long_state, long_block)
        yield from tick_and_add_block(spec, store, signed_long_block,
                                      test_steps)

    # build short tree
    short_state = genesis_state.copy()
    short_block = build_empty_block_for_next_slot(spec, short_state)
    short_block.body.graffiti = b'\x42' * 32
    signed_short_block = state_transition_and_sign_block(
        spec, short_state, short_block)
    yield from tick_and_add_block(spec, store, signed_short_block, test_steps)

    # Since the long chain has higher proposer_score at slot 1, the latest long block is the head
    assert spec.get_head(store) == spec.hash_tree_root(long_block)

    short_attestation = get_valid_attestation(spec,
                                              short_state,
                                              short_block.slot,
                                              signed=True)
    yield from tick_and_run_on_attestation(spec, store, short_attestation,
                                           test_steps)

    assert spec.get_head(store) == spec.hash_tree_root(short_block)
    test_steps.append(
        {'checks': {
            'head': get_formatted_head_output(spec, store),
        }})

    yield 'steps', test_steps
def test_chain_no_attestations(spec, state):
    # Initialization
    store = get_genesis_forkchoice_store(spec, state)
    anchor_root = get_anchor_root(spec, state)
    assert spec.get_head(store) == anchor_root

    # On receiving a block of `GENESIS_SLOT + 1` slot
    block_1 = build_empty_block_for_next_slot(spec, state)
    signed_block_1 = state_transition_and_sign_block(spec, state, block_1)
    add_block_to_store(spec, store, signed_block_1)

    # On receiving a block of next epoch
    block_2 = build_empty_block_for_next_slot(spec, state)
    signed_block_2 = state_transition_and_sign_block(spec, state, block_2)
    add_block_to_store(spec, store, signed_block_2)

    assert spec.get_head(store) == spec.hash_tree_root(block_2)
示例#7
0
def test_split_tie_breaker_no_attestations(spec, state):
    test_steps = []
    genesis_state = state.copy()

    # Initialization
    store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state)
    yield 'anchor_state', state
    yield 'anchor_block', anchor_block
    anchor_root = get_anchor_root(spec, state)
    assert spec.get_head(store) == anchor_root
    test_steps.append(
        {'checks': {
            'head': get_formatted_head_output(spec, store),
        }})

    # Create block at slot 1
    block_1_state = genesis_state.copy()
    block_1 = build_empty_block_for_next_slot(spec, block_1_state)
    signed_block_1 = state_transition_and_sign_block(spec, block_1_state,
                                                     block_1)

    # Create additional block at slot 1
    block_2_state = genesis_state.copy()
    block_2 = build_empty_block_for_next_slot(spec, block_2_state)
    block_2.body.graffiti = b'\x42' * 32
    signed_block_2 = state_transition_and_sign_block(spec, block_2_state,
                                                     block_2)

    # Tick time past slot 1 so proposer score boost does not apply
    time = store.genesis_time + (block_2.slot +
                                 1) * spec.config.SECONDS_PER_SLOT
    on_tick_and_append_step(spec, store, time, test_steps)

    yield from add_block(spec, store, signed_block_1, test_steps)
    yield from add_block(spec, store, signed_block_2, test_steps)

    highest_root = max(spec.hash_tree_root(block_1),
                       spec.hash_tree_root(block_2))
    assert spec.get_head(store) == highest_root
    test_steps.append(
        {'checks': {
            'head': get_formatted_head_output(spec, store),
        }})

    yield 'steps', test_steps
示例#8
0
def test_genesis(spec, state):
    test_steps = []
    # Initialization
    store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state)
    yield 'anchor_state', state
    yield 'anchor_block', anchor_block

    anchor_root = get_anchor_root(spec, state)
    assert spec.get_head(store) == anchor_root
    test_steps.append({
        'checks': {
            'genesis_time': int(store.genesis_time),
            'head': get_formatted_head_output(spec, store),
        }
    })

    yield 'steps', test_steps

    if is_post_altair(spec):
        yield 'description', 'meta', f"Although it's not phase 0, we may use {spec.fork} spec to start testnets."
示例#9
0
def test_split_tie_breaker_no_attestations(spec, state):
    test_steps = []
    genesis_state = state.copy()

    # Initialization
    store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state)
    yield 'anchor_state', state
    yield 'anchor_block', anchor_block
    anchor_root = get_anchor_root(spec, state)
    assert spec.get_head(store) == anchor_root
    test_steps.append(
        {'checks': {
            'head': get_formatted_head_output(spec, store),
        }})

    # block at slot 1
    block_1_state = genesis_state.copy()
    block_1 = build_empty_block_for_next_slot(spec, block_1_state)
    signed_block_1 = state_transition_and_sign_block(spec, block_1_state,
                                                     block_1)
    yield from tick_and_run_on_block(spec, store, signed_block_1, test_steps)

    # additional block at slot 1
    block_2_state = genesis_state.copy()
    block_2 = build_empty_block_for_next_slot(spec, block_2_state)
    block_2.body.graffiti = b'\x42' * 32
    signed_block_2 = state_transition_and_sign_block(spec, block_2_state,
                                                     block_2)
    yield from tick_and_run_on_block(spec, store, signed_block_2, test_steps)

    highest_root = max(spec.hash_tree_root(block_1),
                       spec.hash_tree_root(block_2))
    assert spec.get_head(store) == highest_root
    test_steps.append(
        {'checks': {
            'head': get_formatted_head_output(spec, store),
        }})

    yield 'steps', test_steps
def test_split_tie_breaker_no_attestations(spec, state):
    genesis_state = state.copy()

    # Initialization
    store = get_genesis_forkchoice_store(spec, state)
    anchor_root = get_anchor_root(spec, state)
    assert spec.get_head(store) == anchor_root

    # block at slot 1
    block_1_state = genesis_state.copy()
    block_1 = build_empty_block_for_next_slot(spec, block_1_state)
    signed_block_1 = state_transition_and_sign_block(spec, block_1_state, block_1)
    add_block_to_store(spec, store, signed_block_1)

    # additional block at slot 1
    block_2_state = genesis_state.copy()
    block_2 = build_empty_block_for_next_slot(spec, block_2_state)
    block_2.body.graffiti = b'\x42' * 32
    signed_block_2 = state_transition_and_sign_block(spec, block_2_state, block_2)
    add_block_to_store(spec, store, signed_block_2)

    highest_root = max(spec.hash_tree_root(block_1), spec.hash_tree_root(block_2))

    assert spec.get_head(store) == highest_root
示例#11
0
def test_discard_equivocations(spec, state):
    test_steps = []
    genesis_state = state.copy()

    # Initialization
    store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state)
    yield 'anchor_state', state
    yield 'anchor_block', anchor_block
    anchor_root = get_anchor_root(spec, state)
    assert spec.get_head(store) == anchor_root
    test_steps.append(
        {'checks': {
            'head': get_formatted_head_output(spec, store),
        }})

    # Build block that serves as head before discarding equivocations
    state_1 = genesis_state.copy()
    next_slots(spec, state_1, 3)
    block_1 = build_empty_block_for_next_slot(spec, state_1)
    signed_block_1 = state_transition_and_sign_block(spec, state_1, block_1)

    # Build equivocating attestations to feed to store
    state_eqv = state_1.copy()
    block_eqv = apply_empty_block(spec, state_eqv, state_eqv.slot + 1)
    attestation_eqv = get_valid_attestation(spec,
                                            state_eqv,
                                            slot=block_eqv.slot,
                                            signed=True)

    next_slots(spec, state_1, 1)
    attestation = get_valid_attestation(spec,
                                        state_1,
                                        slot=block_eqv.slot,
                                        signed=True)
    assert spec.is_slashable_attestation_data(attestation.data,
                                              attestation_eqv.data)

    indexed_attestation = spec.get_indexed_attestation(state_1, attestation)
    indexed_attestation_eqv = spec.get_indexed_attestation(
        state_eqv, attestation_eqv)
    attester_slashing = spec.AttesterSlashing(
        attestation_1=indexed_attestation,
        attestation_2=indexed_attestation_eqv)

    # Build block that serves as head after discarding equivocations
    state_2 = genesis_state.copy()
    next_slots(spec, state_2, 2)
    block_2 = build_empty_block_for_next_slot(spec, state_2)
    signed_block_2 = state_transition_and_sign_block(spec, state_2.copy(),
                                                     block_2)
    while spec.hash_tree_root(block_1) >= spec.hash_tree_root(block_2):
        block_2.body.graffiti = spec.Bytes32(
            hex(rng.getrandbits(8 * 32))[2:].zfill(64))
        signed_block_2 = state_transition_and_sign_block(
            spec, state_2.copy(), block_2)
    assert spec.hash_tree_root(block_1) < spec.hash_tree_root(block_2)

    # Tick to (block_eqv.slot + 2) slot time
    time = store.genesis_time + (block_eqv.slot +
                                 2) * spec.config.SECONDS_PER_SLOT
    on_tick_and_append_step(spec, store, time, test_steps)

    # Process block_2
    yield from add_block(spec, store, signed_block_2, test_steps)
    assert store.proposer_boost_root == spec.Root()
    assert spec.get_head(store) == spec.hash_tree_root(block_2)

    # Process block_1
    # The head should remain block_2
    yield from add_block(spec, store, signed_block_1, test_steps)
    assert store.proposer_boost_root == spec.Root()
    assert spec.get_head(store) == spec.hash_tree_root(block_2)

    # Process attestation
    # The head should change to block_1
    yield from add_attestation(spec, store, attestation, test_steps)
    assert spec.get_head(store) == spec.hash_tree_root(block_1)

    # Process attester_slashing
    # The head should revert to block_2
    yield from add_attester_slashing(spec, store, attester_slashing,
                                     test_steps)
    assert spec.get_head(store) == spec.hash_tree_root(block_2)

    test_steps.append(
        {'checks': {
            'head': get_formatted_head_output(spec, store),
        }})

    yield 'steps', test_steps
示例#12
0
def test_proposer_boost_correct_head(spec, state):
    test_steps = []
    genesis_state = state.copy()

    # Initialization
    store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state)
    yield 'anchor_state', state
    yield 'anchor_block', anchor_block
    anchor_root = get_anchor_root(spec, state)
    assert spec.get_head(store) == anchor_root
    test_steps.append(
        {'checks': {
            'head': get_formatted_head_output(spec, store),
        }})

    # Build block that serves as head ONLY on timely arrival, and ONLY in that slot
    state_1 = genesis_state.copy()
    next_slots(spec, state_1, 3)
    block_1 = build_empty_block_for_next_slot(spec, state_1)
    signed_block_1 = state_transition_and_sign_block(spec, state_1, block_1)

    # Build block that serves as current head, and remains the head after block_1.slot
    state_2 = genesis_state.copy()
    next_slots(spec, state_2, 2)
    block_2 = build_empty_block_for_next_slot(spec, state_2)
    signed_block_2 = state_transition_and_sign_block(spec, state_2.copy(),
                                                     block_2)
    while spec.hash_tree_root(block_1) >= spec.hash_tree_root(block_2):
        block_2.body.graffiti = spec.Bytes32(
            hex(rng.getrandbits(8 * 32))[2:].zfill(64))
        signed_block_2 = state_transition_and_sign_block(
            spec, state_2.copy(), block_2)
    assert spec.hash_tree_root(block_1) < spec.hash_tree_root(block_2)

    # Tick to block_1 slot time
    time = store.genesis_time + block_1.slot * spec.config.SECONDS_PER_SLOT
    on_tick_and_append_step(spec, store, time, test_steps)

    # Process block_2
    yield from add_block(spec, store, signed_block_2, test_steps)
    assert store.proposer_boost_root == spec.Root()
    assert spec.get_head(store) == spec.hash_tree_root(block_2)

    # Process block_1 on timely arrival
    # The head should temporarily change to block_1
    yield from add_block(spec, store, signed_block_1, test_steps)
    assert store.proposer_boost_root == spec.hash_tree_root(block_1)
    assert spec.get_head(store) == spec.hash_tree_root(block_1)

    # After block_1.slot, the head should revert to block_2
    time = store.genesis_time + (block_1.slot +
                                 1) * spec.config.SECONDS_PER_SLOT
    on_tick_and_append_step(spec, store, time, test_steps)
    assert store.proposer_boost_root == spec.Root()
    assert spec.get_head(store) == spec.hash_tree_root(block_2)

    test_steps.append(
        {'checks': {
            'head': get_formatted_head_output(spec, store),
        }})

    yield 'steps', test_steps
示例#13
0
def test_filtered_block_tree(spec, state):
    test_steps = []
    # Initialization
    store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state)
    yield 'anchor_state', state
    yield 'anchor_block', anchor_block
    anchor_root = get_anchor_root(spec, state)
    assert spec.get_head(store) == anchor_root
    test_steps.append(
        {'checks': {
            'head': get_formatted_head_output(spec, store),
        }})

    # transition state past initial couple of epochs
    next_epoch(spec, state)
    next_epoch(spec, state)
    # fill in attestations for entire epoch, justifying the recent epoch
    prev_state, signed_blocks, state = next_epoch_with_attestations(
        spec, state, True, False)
    assert state.current_justified_checkpoint.epoch > prev_state.current_justified_checkpoint.epoch

    # tick time forward and add blocks and attestations to store
    current_time = state.slot * spec.config.SECONDS_PER_SLOT + store.genesis_time
    on_tick_and_append_step(spec, store, current_time, test_steps)
    for signed_block in signed_blocks:
        yield from add_block(spec, store, signed_block, test_steps)

    assert store.justified_checkpoint == state.current_justified_checkpoint

    # the last block in the branch should be the head
    expected_head_root = spec.hash_tree_root(signed_blocks[-1].message)
    assert spec.get_head(store) == expected_head_root

    test_steps.append({
        'checks': {
            'head':
            get_formatted_head_output(spec, store),
            'justified_checkpoint_root':
            encode_hex(store.justified_checkpoint.root),
        }
    })

    #
    # create branch containing the justified block but not containing enough on
    # chain votes to justify that block
    #

    # build a chain without attestations off of previous justified block
    non_viable_state = store.block_states[
        store.justified_checkpoint.root].copy()

    # ensure that next wave of votes are for future epoch
    next_epoch(spec, non_viable_state)
    next_epoch(spec, non_viable_state)
    next_epoch(spec, non_viable_state)
    assert spec.get_current_epoch(
        non_viable_state) > store.justified_checkpoint.epoch

    # create rogue block that will be attested to in this non-viable branch
    rogue_block = build_empty_block_for_next_slot(spec, non_viable_state)
    signed_rogue_block = state_transition_and_sign_block(
        spec, non_viable_state, rogue_block)

    # create an epoch's worth of attestations for the rogue block
    next_epoch(spec, non_viable_state)
    attestations = []
    for i in range(spec.SLOTS_PER_EPOCH):
        slot = rogue_block.slot + i
        for index in range(
                spec.get_committee_count_per_slot(
                    non_viable_state, spec.compute_epoch_at_slot(slot))):
            attestation = get_valid_attestation(spec,
                                                non_viable_state,
                                                slot,
                                                index,
                                                signed=True)
            attestations.append(attestation)

    # tick time forward to be able to include up to the latest attestation
    current_time = (attestations[-1].data.slot +
                    1) * spec.config.SECONDS_PER_SLOT + store.genesis_time
    on_tick_and_append_step(spec, store, current_time, test_steps)

    # include rogue block and associated attestations in the store
    yield from add_block(spec, store, signed_rogue_block, test_steps)

    for attestation in attestations:
        yield from tick_and_run_on_attestation(spec, store, attestation,
                                               test_steps)

    # ensure that get_head still returns the head from the previous branch
    assert spec.get_head(store) == expected_head_root
    test_steps.append(
        {'checks': {
            'head': get_formatted_head_output(spec, store)
        }})

    yield 'steps', test_steps
def test_genesis(spec, state):
    # Initialization
    store = get_genesis_forkchoice_store(spec, state)
    anchor_root = get_anchor_root(spec, state)
    assert spec.get_head(store) == anchor_root