def test_ensure_update_eth1_vote_if_exists(genesis_state, config,
                                           vote_offsets):
    # one less than a majority is the majority divided by 2
    threshold = config.SLOTS_PER_ETH1_VOTING_PERIOD // 2
    data_votes = tuple(
        concat((Eth1Data.create(block_hash=(i).to_bytes(32, "little")), ) *
               (threshold + offset) for i, offset in enumerate(vote_offsets)))
    state = genesis_state

    for vote in data_votes:
        state = process_eth1_data(
            state,
            BeaconBlock.create(body=BeaconBlockBody.create(eth1_data=vote)),
            config,
        )

    if not vote_offsets:
        assert state.eth1_data == genesis_state.eth1_data

    # we should update the 'latest' entry if we have a majority
    for offset in vote_offsets:
        if offset <= 0:
            assert genesis_state.eth1_data == state.eth1_data
        else:
            assert state.eth1_data == data_votes[0]
Beispiel #2
0
def create_block_proposal(
    slot: Slot,
    parent_root: Root,
    randao_reveal: BLSSignature,
    eth1_data: Eth1Data,
    attestations: Sequence[Attestation],
    state: BeaconState,
    state_machine: BaseBeaconStateMachine,
) -> BeaconBlock:
    config = state_machine.config
    state_at_slot, _ = state_machine.apply_state_transition(state,
                                                            future_slot=slot)
    proposer_index = get_beacon_proposer_index(state_at_slot, config)

    block_body = BeaconBlockBody.create(randao_reveal=randao_reveal,
                                        eth1_data=eth1_data,
                                        attestations=attestations)
    proposal = BeaconBlock.create(
        slot=slot,
        parent_root=parent_root,
        body=block_body,
        proposer_index=proposer_index,
    )
    block_with_empty_signature = SignedBeaconBlock.create(
        message=proposal, signature=EMPTY_SIGNATURE)
    post_state, block_with_state_root = state_machine.apply_state_transition(
        state, block_with_empty_signature, check_proposer_signature=False)
    return block_with_state_root.message
def test_process_eth1_data(
    original_votes,
    block_data,
    expected_votes,
    sample_beacon_state_params,
    sample_beacon_block_params,
    sample_beacon_block_body_params,
    config,
):
    eth1_data_votes = tuple(mapcat(_expand_eth1_votes, original_votes))
    state = BeaconState.create(**sample_beacon_state_params).set(
        "eth1_data_votes", eth1_data_votes)

    block_body = BeaconBlockBody.create(
        **sample_beacon_block_body_params).mset(
            "eth1_data", Eth1Data.create(block_hash=block_data))

    block = BeaconBlock.create(**sample_beacon_block_params).set(
        "body", block_body)

    updated_state = process_eth1_data(state, block, config)
    updated_votes = updated_state.eth1_data_votes
    expanded_expected_votes = tuple(mapcat(_expand_eth1_votes, expected_votes))

    assert tuple(updated_votes) == expanded_expected_votes
Beispiel #4
0
 def run_with(
     cls,
     inputs: Tuple[BeaconState, OperationOrBlockHeader],
     config: Optional[Eth2Config],
 ) -> BeaconState:
     state, operation = inputs
     # NOTE: we do not have an easy way to evaluate a single operation on the state
     # So, we wrap it in a beacon block. The following statement lets us rely on
     # the config given in a particular handler class while working w/in the
     # update API provided by `py-ssz`.
     # NOTE: we ignore the type here, otherwise need to spell out each of the keyword
     # arguments individually... save some work and just build them dynamically
     block = BeaconBlock.create(body=BeaconBlockBody.create(
         **{f"{cls.name}s": (operation, )}  # type: ignore
     ))
     try:
         return cls.processor(state, block, config)
     except ValidationError as e:
         # if already a ValidationError, re-raise
         raise e
     except Exception as e:
         # check if the exception is expected...
         for exception in cls.expected_exceptions:
             if isinstance(e, exception):
                 raise ValidationError() from e
         # else raise (and fail the pytest test case ...)
         raise e
Beispiel #5
0
def _mk_minimum_viable_signed_beacon_blocks(slots, state_machine_provider,
                                            state, block):
    for slot in slots:
        message = BeaconBlock.create(slot=slot,
                                     parent_root=block.message.hash_tree_root)
        block = SignedBeaconBlock.create(message=message)
        state, block = state_machine_provider(slot).import_block(block, state)
        yield block
Beispiel #6
0
 async def _get_block_proposal(self, request: web.Request) -> web.Response:
     slot = Slot(int(request.query["slot"]))
     randao_reveal = BLSSignature(
         decode_hex(request.query["randao_reveal"]).ljust(96, b"\x00"))
     block = BeaconBlock.create(
         slot=slot,
         body=BeaconBlockBody.create(randao_reveal=randao_reveal))
     return web.json_response(to_formatted_dict(block))
Beispiel #7
0
def test_higher_slot_fork_choice_scoring(slot):
    block = BeaconBlock.create(slot=slot)

    expected_score = HigherSlotScore(slot)

    scoring = HigherSlotScoring()
    score = scoring.score(block)

    assert score == expected_score
Beispiel #8
0
def test_update_attestations(sample_attestation_params,
                             sample_beacon_block_params):
    block = BeaconBlock.create(**sample_beacon_block_params)
    attestations = block.body.attestations
    attestations = list(attestations)
    attestations.append(Attestation.create(**sample_attestation_params))
    body2 = block.body.set("attestations", attestations)
    block2 = block.set("body", body2)
    assert len(block2.body.attestations) == 1
Beispiel #9
0
def test_higher_slot_fork_choice_scoring(sample_beacon_block_params, slot):
    block = BeaconBlock.create(**sample_beacon_block_params).set("slot", slot)

    expected_score = HigherSlotScore(slot)

    scoring = HigherSlotScoring()
    score = scoring.score(block)

    assert score == expected_score
Beispiel #10
0
def _mk_block(block_params, slot, parent, block_offset):
    return BeaconBlock.create(**block_params).mset(
        "slot",
        slot,
        "parent_root",
        parent.signing_root,
        # mix in something unique
        "state_root",
        block_offset.to_bytes(32, byteorder="big"),
    )
Beispiel #11
0
def _mk_block(block_params, slot, parent, block_offset):
    block = BeaconBlock.create(**block_params).mset(
        "slot",
        slot,
        "parent_root",
        parent.message.hash_tree_root,
        # mix in something unique
        "state_root",
        block_offset.to_bytes(32, byteorder="big"),
    )
    return SignedBeaconBlock.create(message=block)
Beispiel #12
0
def _mk_minimum_viable_signed_beacon_blocks(slots, state_machine_provider,
                                            state, block, config):
    for slot in slots:
        future_state, _ = state_machine_provider(slot).apply_state_transition(
            state, future_slot=block.slot + 1)
        proposer_index = get_beacon_proposer_index(future_state, config)
        message = BeaconBlock.create(
            slot=slot,
            parent_root=block.message.hash_tree_root,
            proposer_index=proposer_index,
        )
        block = SignedBeaconBlock.create(message=message)
        state, block = state_machine_provider(slot).apply_state_transition(
            state, block)
        yield block
def test_validate_block_slot(
    sample_beacon_state_params,
    sample_beacon_block_params,
    state_slot,
    block_slot,
    expected,
):
    state = BeaconState.create(**sample_beacon_state_params).set(
        "slot", state_slot)
    block = BeaconBlock.create(**sample_beacon_block_params).set(
        "slot", block_slot)
    if isinstance(expected, Exception):
        with pytest.raises(ValidationError):
            validate_block_slot(state, block)
    else:
        validate_block_slot(state, block)
Beispiel #14
0
async def test_hosts_can_do_req_resp(host_factory):
    host_a_blocks = set()
    host_a, host_a_listen_maddr = host_factory("c", host_a_blocks)

    host_b_blocks = set(
        [SignedBeaconBlock.create(message=BeaconBlock.create(slot=0))])
    host_b, host_b_listen_maddr = host_factory("d", host_b_blocks)

    with trio.move_on_after(2 * 60):
        async with _run_host(host_a, host_a_listen_maddr):
            async with _run_host(host_b, host_b_listen_maddr):
                await host_b.add_peer_from_maddr(host_a_listen_maddr)
                assert len(host_a.get_network().connections) == 1
                assert len(host_b.get_network().connections) == 1

                peer_b = host_b.get_id()

                status_b = await host_a.exchange_status(
                    peer_b, host_a._status_provider())
                assert status_b

                some_blocks = set()
                async for block in host_a.get_blocks_by_range(peer_b, 0, 20):
                    some_blocks.add(block)
                assert len(some_blocks) == 1

                no_blocks = set()
                async for block in host_a.get_blocks_by_range(peer_b, 30, 3):
                    no_blocks.add(block)
                assert len(no_blocks) == 0

                a_block = some_blocks.pop()
                the_same_block = await host_a.get_blocks_by_root(
                    peer_b, a_block.message.hash_tree_root).__anext__()
                assert a_block == the_same_block

                b_seq_number = await host_a.send_ping(peer_b)
                assert b_seq_number == ord("d")

                b_metadata = await host_a.get_metadata(peer_b)
                assert b_metadata.seq_number == b_seq_number

                await host_a.send_goodbye_to(peer_b,
                                             GoodbyeReason.shutting_down)
                assert len(host_a.get_network().connections) == 0
                assert len(host_b.get_network().connections) == 0
Beispiel #15
0
def test_chain2_at_genesis(base_db, genesis_state, genesis_block, config):
    genesis_block = genesis_block.message
    chain_db = BeaconChainDB.from_genesis(base_db, genesis_state,
                                          SignedBeaconBlock, config)

    block_at_genesis = chain_db.get_block_by_slot(GENESIS_SLOT, BeaconBlock)
    assert block_at_genesis == genesis_block

    block_at_genesis = chain_db.get_block_by_root(genesis_block.hash_tree_root,
                                                  BeaconBlock)
    assert block_at_genesis == genesis_block

    genesis_signature = chain_db.get_block_signature_by_root(
        genesis_block.hash_tree_root)
    assert genesis_signature == EMPTY_SIGNATURE

    state_at_genesis = chain_db.get_state_by_slot(GENESIS_SLOT, BeaconState)
    assert state_at_genesis == genesis_state

    state_at_genesis = chain_db.get_state_by_root(genesis_state.hash_tree_root,
                                                  BeaconState)
    assert state_at_genesis == genesis_state

    finalized_head = chain_db.get_finalized_head(BeaconBlock)
    assert finalized_head == genesis_block

    some_future_slot = Slot(22)
    assert not chain_db.get_block_by_slot(some_future_slot, BeaconBlock)
    assert not chain_db.get_state_by_slot(some_future_slot, BeaconState)

    block_at_future_slot = SignedBeaconBlock.create(message=BeaconBlock.create(
        slot=some_future_slot))
    chain_db.persist_block(block_at_future_slot)
    future_block = chain_db.get_block_by_root(
        block_at_future_slot.message.hash_tree_root, BeaconBlock)
    assert block_at_future_slot.message == future_block

    # NOTE: only finalized blocks are stored by slot in the DB
    # non-finalized but canonical blocks are determined by fork choice, separately from the DB
    assert not chain_db.get_block_by_slot(some_future_slot, BeaconBlock)

    # assume the fork choice did finalize this block...
    chain_db.mark_canonical_block(block_at_future_slot.message)
    assert chain_db.get_block_by_slot(some_future_slot,
                                      BeaconBlock) == future_block
Beispiel #16
0
def create_block_proposal(
    slot: Slot,
    parent_root: Root,
    randao_reveal: BLSSignature,
    eth1_data: Eth1Data,
    state: BeaconState,
    state_machine: BaseBeaconStateMachine,
) -> BeaconBlock:
    proposal = BeaconBlock.create(
        slot=slot,
        parent_root=parent_root,
        body=BeaconBlockBody.create(randao_reveal=randao_reveal, eth1_data=eth1_data),
    )
    signed_block = SignedBeaconBlock.create(message=proposal, signature=EMPTY_SIGNATURE)
    post_state, signed_block = state_machine.import_block(
        signed_block, state, check_proposer_signature=False
    )
    return signed_block.message
Beispiel #17
0
def test_chain2_full(base_db, genesis_state, config):
    chain_db = BeaconChainDB.from_genesis(base_db, genesis_state,
                                          SignedBeaconBlock, config)

    state = genesis_state
    states = [genesis_state]
    blocks = {}

    num_slots = 500
    skip_slots = [5, 64, 100, 300, 301, 302, 401]
    finalized_slots = [8, 24, 32, 72, 152, 160, 328, 336, 344, 352, 400]

    # create a new state at each slot using ``_mini_stf()`` and persist it
    for _ in range(1, num_slots):
        if state.slot not in skip_slots:
            new_block = BeaconBlock.create(slot=state.slot,
                                           state_root=state.hash_tree_root)
            blocks[state.slot] = new_block
            chain_db.persist_block(SignedBeaconBlock.create(message=new_block))
        else:
            new_block = None

        state = _mini_stf(state, new_block, config)
        chain_db.persist_state(state, config)
        states.append(state)

    # test that each state created above equals the state stored at its root
    for state in states:
        # finalize a slot two epochs after processing it
        # this is here to test the reconstruction of ``state.randao_mixes``
        maybe_finalized_slot = state.slot - config.SLOTS_PER_EPOCH * 2
        if maybe_finalized_slot in finalized_slots:
            chain_db.mark_finalized_head(blocks[maybe_finalized_slot])

        retrieved_state = chain_db._read_state(state.hash_tree_root,
                                               BeaconState, config)
        assert retrieved_state == state

    for slot in range(0, num_slots):
        if slot in blocks and slot <= finalized_slots[-1]:
            assert chain_db.get_block_by_slot(Slot(slot),
                                              BeaconBlock) == blocks[slot]
        else:
            assert chain_db.get_block_by_slot(Slot(slot), BeaconBlock) is None
def test_validate_proposer_signature(
    slots_per_epoch,
    max_committees_per_slot,
    proposer_privkey,
    proposer_pubkey,
    is_valid_signature,
    sample_beacon_block_params,
    sample_beacon_state_params,
    target_committee_size,
    max_effective_balance,
    config,
):

    state = BeaconState.create(**sample_beacon_state_params).mset(
        "validators",
        tuple(
            create_mock_validator(proposer_pubkey, config) for _ in range(10)),
        "balances",
        (max_effective_balance, ) * 10,
    )

    block = BeaconBlock.create(**sample_beacon_block_params)
    header = block.header

    proposed_block = block.set(
        "signature",
        bls.sign(
            message_hash=header.signing_root,
            privkey=proposer_privkey,
            domain=get_domain(state, SignatureDomain.DOMAIN_BEACON_PROPOSER,
                              slots_per_epoch),
        ),
    )

    if is_valid_signature:
        validate_proposer_signature(state, proposed_block,
                                    CommitteeConfig(config))
    else:
        with pytest.raises(ValidationError):
            validate_proposer_signature(state, proposed_block,
                                        CommitteeConfig(config))
Beispiel #19
0
async def test_request_beacon_blocks_by_root(monkeypatch):
    async with ConnectionPairFactory() as (alice, bob):

        # Mock up block database
        head_block = BeaconBlock.create(
            slot=0,
            parent_root=ZERO_HASH32,
            state_root=ZERO_HASH32,
            signature=EMPTY_SIGNATURE,
            body=BeaconBlockBody.create(),
        )
        blocks = [head_block.set("slot", slot) for slot in range(5)]
        mock_root_to_block_db = {block.signing_root: block for block in blocks}

        def get_block_by_root(root):
            validate_word(root)
            if root in mock_root_to_block_db:
                return mock_root_to_block_db[root]
            else:
                raise BlockNotFound

        monkeypatch.setattr(bob.chain, "get_block_by_root", get_block_by_root)

        requesting_block_roots = [
            blocks[0].signing_root,
            b"\x12" * 32,  # Unknown block root
            blocks[1].signing_root,
            b"\x23" * 32,  # Unknown block root
            blocks[3].signing_root,
        ]
        requested_blocks = await alice.request_beacon_blocks_by_root(
            peer_id=bob.peer_id, block_roots=requesting_block_roots
        )

        expected_blocks = [blocks[0], blocks[1], blocks[3]]
        assert len(requested_blocks) == len(expected_blocks)
        assert set(requested_blocks) == set(expected_blocks)
Beispiel #20
0
 async def fetch_block_proposal(self, slot: Slot,
                                randao_reveal: BLSSignature) -> BeaconBlock:
     body = BeaconBlockBody.create(randao_reveal=randao_reveal)
     return BeaconBlock.create(slot=slot, body=body)
Beispiel #21
0
 async def fetch_block_proposal(self, public_key: BLSPubkey,
                                slot: Slot) -> BeaconBlock:
     return BeaconBlock.create(slot=slot)
Beispiel #22
0
def test_block_is_not_genesis(sample_beacon_block_params):
    genesis_block = BeaconBlock.create(**sample_beacon_block_params)
    another_block = BeaconBlock.from_parent(genesis_block, FromBlockParams())
    assert genesis_block.is_genesis
    assert not another_block.is_genesis
Beispiel #23
0
def test_defaults(sample_beacon_block_params):
    block = BeaconBlock.create(**sample_beacon_block_params)
    assert block.slot == sample_beacon_block_params["slot"]
    assert block.is_genesis
Beispiel #24
0
@pytest.fixture
async def http_server(chain, event_bus):
    server = RawTestServer(APIHandler.handle(chain)(event_bus))
    return server


@pytest.fixture
async def http_client(http_server):
    client = TestClient(http_server)
    asyncio.ensure_future(client.start_server())
    await asyncio.sleep(0.01)
    return client


sample_block = BeaconBlock.create()
sample_attestation = Attestation.create()


@pytest.mark.parametrize(
    'num_validators',
    (2, ),
)
@pytest.mark.parametrize('method, resource, object, json_data, status_code', (
    (GET_METHOD, 'beacon', 'head', '', 200),
    (GET_METHOD, 'beacon', 'block?slot=0', '', 200),
    (GET_METHOD, 'beacon', 'state?slot=4', '', 200),
    (GET_METHOD, 'beacon', 'state?root=AVAILABLE_STATE_ROOT', '', 200),
))
@pytest.mark.asyncio
async def test_restful_http_server(
Beispiel #25
0
def _mk_resolved_block_proposal_duty(slot, public_key):
    return (
        BlockProposalDuty(public_key, Tick(0, slot, 0, 0), Tick(0, 0, 0, 0)),
        BeaconBlock.create(slot=slot),
    )
Beispiel #26
0
def test_block_root_and_block_header_root_equivalence():
    block = BeaconBlock.create()
    header = block.header

    assert block.hash_tree_root == header.hash_tree_root
Beispiel #27
0
async def test_request_beacon_blocks_by_range_invalid_request(monkeypatch):
    async with ConnectionPairFactory() as (alice, bob):

        head_slot = 1
        request_head_block_root = b"\x56" * 32
        head_block = BeaconBlock.create(
            slot=head_slot,
            parent_root=ZERO_HASH32,
            state_root=ZERO_HASH32,
            signature=EMPTY_SIGNATURE,
            body=BeaconBlockBody.create(),
        )

        # TEST: Can not request blocks with `start_slot` greater than head block slot
        start_slot = 2

        def get_block_by_root(root):
            return head_block

        monkeypatch.setattr(bob.chain, "get_block_by_root", get_block_by_root)

        count = 1
        step = 1
        with pytest.raises(RequestFailure):
            await alice.request_beacon_blocks_by_range(
                peer_id=bob.peer_id,
                head_block_root=request_head_block_root,
                start_slot=start_slot,
                count=count,
                step=step,
            )

        # TEST: Can not request fork chain blocks with `start_slot`
        # lower than peer's latest finalized slot
        start_slot = head_slot
        state_machine = bob.chain.get_state_machine()
        old_state = bob.chain.get_head_state()
        new_checkpoint = old_state.finalized_checkpoint.set(
            "epoch", old_state.finalized_checkpoint.epoch + 1
        )

        def get_canonical_block_by_slot(slot):
            raise BlockNotFound

        monkeypatch.setattr(
            bob.chain, "get_canonical_block_by_slot", get_canonical_block_by_slot
        )

        def get_state_machine(at_slot=None):
            class MockStateMachine:
                state = old_state.set("finalized_checkpoint", new_checkpoint)
                config = state_machine.config

            return MockStateMachine()

        def get_head_state():
            return old_state.set("finalized_checkpoint", new_checkpoint)

        monkeypatch.setattr(bob.chain, "get_state_machine", get_state_machine)
        monkeypatch.setattr(bob.chain, "get_head_state", get_head_state)

        with pytest.raises(RequestFailure):
            await alice.request_beacon_blocks_by_range(
                peer_id=bob.peer_id,
                head_block_root=request_head_block_root,
                start_slot=start_slot,
                count=count,
                step=step,
            )