예제 #1
0
def test_block_is_not_genesis():
    genesis_block = SignedBeaconBlock.create().transform(
        ("message", "parent_root"), GENESIS_PARENT_ROOT)
    another_block = SignedBeaconBlock.from_parent(genesis_block,
                                                  FromBlockParams())
    assert genesis_block.is_genesis
    assert not another_block.is_genesis
예제 #2
0
async def test_hosts_can_gossip_blocks(host_factory):
    host_a_blocks = set()
    host_a, host_a_listen_maddr = host_factory("a", host_a_blocks)

    host_b_blocks = set()
    host_b, host_b_listen_maddr = host_factory("b", 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)
                await host_a.subscribe_gossip_channels()
                await host_b.subscribe_gossip_channels()

                # NOTE: subscription fails to register if we do not sleep here...
                # Need to debug inside `libp2p`...
                await trio.sleep(1)

                block = SignedBeaconBlock.create(signature=b"\xcc" * 96)
                await host_a.broadcast_block(block)
                block_source = host_b.stream_block_gossip()
                gossiped_block = await block_source.__anext__()

                assert gossiped_block == block

                # NOTE: the following is racy...
                # Need to debug inside `libp2p`...
                await host_a.unsubscribe_gossip_channels()
                await trio.sleep(1)
                await host_b.unsubscribe_gossip_channels()
예제 #3
0
def test_get_state_root_at_slot(
    sample_beacon_state_params,
    current_slot,
    target_slot,
    success,
    slots_per_epoch,
    slots_per_historical_root,
):
    blocks, _, state_roots = generate_mock_latest_historical_roots(
        SignedBeaconBlock.create(),
        current_slot,
        slots_per_epoch,
        slots_per_historical_root,
    )
    state = BeaconState.create(**sample_beacon_state_params).mset(
        "slot", current_slot, "state_roots", state_roots
    )
    blocks[current_slot].message.state_root = state.hash_tree_root

    if success:
        state_root = get_state_root_at_slot(
            state, target_slot, slots_per_historical_root
        )
        assert state_root == blocks[target_slot].message.state_root
    else:
        with pytest.raises(ValidationError):
            get_state_root_at_slot(state, target_slot, slots_per_historical_root)
예제 #4
0
 def _find_present_ancestor_state(
         self, block_root: Root
 ) -> Tuple[BeaconState, Tuple[SignedBeaconBlock, ...]]:
     """
     Find the first state we have persisted that is an ancestor of ``target_block``.
     """
     try:
         block = self._chain_db.get_block_by_root(block_root, BeaconBlock)
         blocks: Tuple[SignedBeaconBlock, ...] = ()
         # NOTE: re: bounds here; worst case, we return the genesis state.
         for slot in range(block.slot, GENESIS_SLOT - 1, -1):
             try:
                 state_machine = self.get_state_machine(Slot(slot))
                 state = self._chain_db.get_state_by_root(
                     block.state_root,
                     state_machine.state_class,
                     state_machine.config,
                 )
                 return (state, blocks)
             except StateNotFound:
                 signature = self._chain_db.get_block_signature_by_root(
                     block.hash_tree_root)
                 blocks += (SignedBeaconBlock.create(message=block,
                                                     signature=signature), )
                 block = self._chain_db.get_block_by_root(
                     block.parent_root, BeaconBlock)
     except BlockNotFound:
         raise Exception(
             "invariant violated: querying a block that has not been persisted"
         )
     # NOTE: `mypy` complains without this although execution should never get here...
     return (None, ())
예제 #5
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
예제 #6
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
예제 #7
0
 def _get_block_by_root(self, root: Root) -> Optional[SignedBeaconBlock]:
     try:
         block = self._chain.db.get_block_by_root(root, BeaconBlock)
         signature = self._chain.db.get_block_signature_by_root(
             block.hash_tree_root)
         return SignedBeaconBlock.create(message=block, signature=signature)
     except BlockNotFound:
         return None
예제 #8
0
def get_pseudo_chain(length, genesis_block):
    """
    Get a pseudo chain, only slot and parent_root are valid.
    """
    block = genesis_block
    yield genesis_block
    for slot in range(1, length * 3):
        block = SignedBeaconBlock.from_parent(block, FromBlockParams(slot=slot))
        yield block
예제 #9
0
 def _get_block_by_slot(
     self, slot: Slot, block_class: Type[SignedBeaconBlock]
 ) -> Optional[SignedBeaconBlock]:
     # check in db first, implying a finalized chain
     block = self._chain_db.get_block_by_slot(slot, block_class.block_class)
     if block:
         signature = self._chain_db.get_block_signature_by_root(block.hash_tree_root)
         return SignedBeaconBlock.create(message=block, signature=signature)
     else:
         # check in the canonical chain according to fork choice
         # NOTE: likely want a more efficient way to determine block by slot...
         for block in self._fork_choice.get_canonical_chain():
             if block.slot == slot:
                 signature = self._chain_db.get_block_signature_by_root(
                     block.hash_tree_root
                 )
                 return SignedBeaconBlock.create(message=block, signature=signature)
         else:
             return None
예제 #10
0
async def test_json_rpc_http_server(aiohttp_raw_server, aiohttp_client,
                                    event_bus, base_db, ipc_path):
    manager = DBManager(base_db)
    with manager.run(ipc_path):
        # Set chaindb
        override_lengths(SERENITY_CONFIG)
        db = DBClient.connect(ipc_path)
        genesis_config = SERENITY_CONFIG
        chaindb = AsyncBeaconChainDB(db, genesis_config)

        fork_choice_scoring = HigherSlotScoring()
        genesis_state, genesis_block = create_mock_genesis(
            pubkeys=(),
            config=SERENITY_CONFIG,
            keymap=dict(),
            genesis_block_class=BeaconBlock,
            genesis_time=0,
        )

        chaindb.persist_state(genesis_state)
        chaindb.persist_block(
            SignedBeaconBlock.create(message=genesis_block),
            SignedBeaconBlock,
            fork_choice_scoring,
        )
        try:
            rpc = RPCServer(initialize_beacon_modules(chaindb, event_bus),
                            chaindb, event_bus)
            raw_server = await aiohttp_raw_server(
                RPCHandler.handle(rpc.execute))
            client = await aiohttp_client(raw_server)

            request_id = 1
            request_data = {
                "jsonrpc": "2.0",
                "method": "beacon_head",
                "params": [],
                "id": request_id,
            }

            response = await client.post("/", json=request_data)
            response_data = await response.json()

            assert response_data["id"] == request_id
            result = response_data["result"]
            assert result["slot"] == 0
            assert decode_hex(
                result["block_root"]) == genesis_block.hash_tree_root
            assert decode_hex(
                result["state_root"]) == genesis_state.hash_tree_root
        except KeyboardInterrupt:
            pass
        finally:
            await raw_server.close()
            db.close()
예제 #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)
예제 #12
0
def test_from_genesis(base_db, genesis_block, genesis_state, fixture_sm_class,
                      config):
    klass = BeaconChain.configure(__name__="TestChain",
                                  sm_configuration=((0, fixture_sm_class), ))

    assert type(genesis_block) == SerenitySignedBeaconBlock
    block = SignedBeaconBlock.create(message=genesis_block.message)
    assert type(block) == SignedBeaconBlock

    chain = klass.from_genesis(base_db, genesis_state)
    assert chain
예제 #13
0
def _attach_signature(duty: Duty, operation: Operation,
                      signature: BLSSignature) -> SignedOperation:
    if duty.duty_type == DutyType.Attestation:
        attestation = cast(Attestation, operation)
        return attestation.set("signature", signature)
    elif duty.duty_type == DutyType.BlockProposal:
        block_proposal = cast(BeaconBlock, operation)
        return SignedBeaconBlock.create(message=block_proposal,
                                        signature=signature)
    else:
        raise NotImplementedError(f"unrecognized duty type in duty {duty}")
예제 #14
0
def test_from_genesis(base_db, genesis_block, genesis_state, fixture_sm_class,
                      config):
    klass = BeaconChain.configure(__name__="TestChain",
                                  sm_configuration=((0, fixture_sm_class), ),
                                  chain_id=5566)

    assert type(genesis_block) == SerenitySignedBeaconBlock
    block = SignedBeaconBlock.create(message=genesis_block.message)
    assert type(block) == SignedBeaconBlock

    with pytest.raises(BlockClassError):
        klass.from_genesis(base_db, genesis_state, block, config)
예제 #15
0
def _build_branch_across_slots(number_of_slots, chain, config):
    head = chain.get_canonical_head()
    state = chain.db.get_state_by_root(head.state_root, BeaconState)

    head = SignedBeaconBlock.create(message=head)
    return _mk_minimum_viable_signed_beacon_blocks(
        range(head.slot + 1, head.slot + 1 + number_of_slots),
        lambda slot: chain.get_state_machine(slot),
        state,
        head,
        config,
    )
예제 #16
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
예제 #17
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
예제 #18
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
예제 #19
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
예제 #20
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
예제 #21
0
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)

    proposed_block = SignedBeaconBlock.create(
        message=block,
        signature=bls.sign(
            message_hash=block.hash_tree_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))
예제 #22
0
def sign_block(state: BeaconState, block: BeaconBlock, private_key: int,
               slots_per_epoch: int) -> SignedBeaconBlock:
    signature = get_block_signature(state, block, private_key, slots_per_epoch)
    return SignedBeaconBlock.create(message=block, signature=signature)