コード例 #1
0
ファイル: test_kademlia.py プロジェクト: jonnycrunch/trinity
def test_kbucket_replacement_cache():
    # Check that the replacement cache has a limited size and doesn't contain duplicates.
    # The min/max IDs are irrelevant here as we'll forcibly add nodes to the bucket.
    bucket = KBucket(0, 10, size=10)
    for node in NodeFactory.create_batch(bucket.size):
        bucket.add(node)
    assert bucket.replacement_cache == []

    # Our bucket is now full, so new entries will go to the replacement cache in the order they
    # were added.
    assert bucket.is_full
    overflow_nodes = NodeFactory.create_batch(bucket.size)
    for node in overflow_nodes:
        bucket.add(node)
    assert bucket.replacement_cache == overflow_nodes

    # If we try to add a node that is already in the replacement cache, it is simply moved to the
    # tail of the list.
    bucket.add(overflow_nodes[3])
    assert bucket.replacement_cache.index(overflow_nodes[3]) == bucket.size - 1

    # Adding a fresh batch of nodes will cause the ones currently in the replacement cache to be
    # discarded.
    cache_overflow_nodes = NodeFactory.create_batch(bucket.size)
    for node in cache_overflow_nodes:
        bucket.add(node)
        assert bucket.replacement_cache[-1] == node
    assert bucket.replacement_cache == cache_overflow_nodes
コード例 #2
0
ファイル: test_kademlia.py プロジェクト: jonnycrunch/trinity
def test_kbucket_remove():
    bucket = KBucket(0, 100, size=25)

    nodes = NodeFactory.create_batch(bucket.size)
    for node in nodes:
        bucket.add(node)
    assert bucket.nodes == nodes
    assert bucket.replacement_cache == []

    replacement_count = 10
    replacement_nodes = NodeFactory.create_batch(replacement_count)
    for replacement_node in replacement_nodes:
        bucket.add(replacement_node)
    assert bucket.nodes == nodes
    assert bucket.replacement_cache == replacement_nodes

    for node in nodes:
        bucket.remove_node(node)
    assert bucket.nodes == list(reversed(replacement_nodes))
    assert bucket.replacement_cache == []

    for replacement_node in replacement_nodes:
        bucket.remove_node(replacement_node)
    assert bucket.nodes == []
    assert bucket.replacement_cache == []
コード例 #3
0
async def test_aurora_tally():
    proto = AuroraDiscoveryProtocolFactory.from_seed(b'foo')
    m = Mock()
    m.side_effect = [
        (0.8, "block_a", set(NodeFactory.create_batch(16))),
        (0.9, "block_b", set(NodeFactory.create_batch(16))),
        (0.7, "block_c", set(NodeFactory.create_batch(16))),
    ]
    proto.aurora_walk = m
    result_key, _ = proto.aurora_tally(NodeFactory(), 10, 50, 16, 3)
    assert result_key == "block_b"
    assert m.call_count == 3
コード例 #4
0
async def test_update_routing_table_triggers_bond_if_eviction_candidate(
        manually_driven_discovery, monkeypatch):
    discovery = manually_driven_discovery
    old_node, new_node = NodeFactory.create_batch(2)

    bond_called = False

    async def bond(node_id):
        nonlocal bond_called
        bond_called = True
        assert node_id == old_node.id

    monkeypatch.setattr(discovery, 'bond', bond)
    # Pretend our routing table failed to add the new node by returning the least recently seen
    # node for an eviction check.
    monkeypatch.setattr(discovery.routing, 'update', lambda n: old_node.id)

    discovery.update_routing_table(new_node)

    assert not discovery.routing._contains(new_node.id, include_replacement_cache=False)
    # The update_routing_table() call above will have scheduled a future call to discovery.bond() so
    # we need to wait a bit here to give it a chance to run.
    with trio.fail_after(0.5):
        while not bond_called:
            await trio.sleep(0.001)
コード例 #5
0
async def test_protocol_bootstrap(monkeypatch):
    node1, node2 = NodeFactory.create_batch(2)
    discovery = MockDiscoveryService([node1, node2])
    invalidated_bonds = []

    def invalidate_bond(node_id):
        invalidated_bonds.append(node_id)

    async def bond(node_id):
        assert discovery.routing.update(node_id) is None
        return True

    monkeypatch.setattr(discovery, 'invalidate_bond', invalidate_bond)
    # Pretend we bonded successfully with our bootstrap nodes.
    monkeypatch.setattr(discovery, 'bond', bond)

    await discovery.bootstrap()

    assert sorted(invalidated_bonds) == sorted([node.id for node in [node1, node2]])
    assert len(discovery.messages) == 2
    # We don't care in which order the bootstrap nodes are contacted, nor which node_id was used
    # in the find_node request, so we just assert that we sent find_node msgs to both nodes.
    assert sorted([(node, cmd) for (node, cmd, _) in discovery.messages]) == sorted([
        (node1, 'find_node'),
        (node2, 'find_node')])
コード例 #6
0
async def test_wait_neighbours(nursery):
    service = MockDiscoveryService([])
    node = NodeFactory()

    # Schedule a call to service.recv_neighbours_v4() simulating a neighbours response from the
    # node we expect.
    neighbours = tuple(NodeFactory.create_batch(3))
    neighbours_msg_payload = [
        [n.address.to_endpoint() + [n.pubkey.to_bytes()] for n in neighbours],
        discovery._get_msg_expiration()]

    async def recv_neighbours() -> None:
        service.recv_neighbours_v4(node, neighbours_msg_payload, b'')
    nursery.start_soon(recv_neighbours)

    received_neighbours = await service.wait_neighbours(node)

    assert neighbours == received_neighbours
    # Ensure wait_neighbours() cleaned up after itself.
    assert node not in service.neighbours_callbacks

    # If wait_neighbours() times out, we get an empty list of neighbours.
    received_neighbours = await service.wait_neighbours(node)

    assert received_neighbours == tuple()
    assert node not in service.neighbours_callbacks
コード例 #7
0
ファイル: test_discovery.py プロジェクト: teotoplak/trinity
async def test_wait_neighbours():
    proto = MockDiscoveryProtocol([])
    node = NodeFactory()

    # Schedule a call to proto.recv_neighbours_v4() simulating a neighbours response from the node
    # we expect.
    neighbours = tuple(NodeFactory.create_batch(3))
    neighbours_msg_payload = [[
        n.address.to_endpoint() + [n.pubkey.to_bytes()] for n in neighbours
    ],
                              discovery._get_msg_expiration()]
    recv_neighbours_coroutine = asyncio.coroutine(
        lambda: proto.recv_neighbours_v4(node, neighbours_msg_payload, b''))
    asyncio.ensure_future(recv_neighbours_coroutine())

    received_neighbours = await proto.wait_neighbours(node)

    assert neighbours == received_neighbours
    # Ensure wait_neighbours() cleaned up after itself.
    assert node not in proto.neighbours_callbacks

    # If wait_neighbours() times out, we get an empty list of neighbours.
    received_neighbours = await proto.wait_neighbours(node)

    assert received_neighbours == tuple()
    assert node not in proto.neighbours_callbacks
コード例 #8
0
async def test_aurora_walk(network_size, malpn, malpg, mistake_threshold,
                           test_runs):
    """ TODO this is a non-deterministic test, should be changed"""
    response_size = constants.KADEMLIA_BUCKET_SIZE
    batch = NodeFactory.create_batch(network_size)
    pubkey_honesty: Dict[any, Tuple[NodeAPI, bool]] = {}
    honest_nodes: Set[NodeAPI] = set()
    malicious_nodes: Set[NodeAPI] = set()
    for index, node in enumerate(batch):
        if index < network_size * malpn:
            pubkey_honesty.update({node.pubkey: False})
            malicious_nodes.add(node)
        else:
            pubkey_honesty.update({node.pubkey: True})
            honest_nodes.add(node)
    proto = MockDiscoveryProtocolAurora(batch, honest_nodes, malicious_nodes,
                                        malpg)

    hit_number = 0
    miss_number = 0
    for _ in range(test_runs):
        entry_node = random.choice(tuple(malicious_nodes))
        _, result_pubkey, _ = await proto.aurora_walk(entry_node, network_size,
                                                      response_size,
                                                      mistake_threshold)
        if pubkey_honesty[result_pubkey]:
            hit_number += 1
        else:
            miss_number += 1
    assert hit_number > miss_number
コード例 #9
0
async def test_aurora_pick_existing_candidates():
    candidates = NodeFactory.create_batch(4)
    node1, node2, *other_nodes = candidates
    exclusion_candidates = {node1, node2}
    result = aurora_pick(set(candidates), exclusion_candidates)

    assert result in candidates
    assert result not in exclusion_candidates
コード例 #10
0
def test_multiplexer_pair_factory():
    alice_remote, bob_remote = NodeFactory.create_batch(2)
    alice_multiplexer, bob_multiplexer = MultiplexerPairFactory(
        alice_remote=alice_remote,
        bob_remote=bob_remote,
    )
    assert alice_multiplexer.remote == bob_remote
    assert bob_multiplexer.remote == alice_remote

    assert alice_multiplexer.get_base_protocol().version == DEVP2P_V5
    assert bob_multiplexer.get_base_protocol().version == DEVP2P_V5
コード例 #11
0
async def test_topic_query(event_loop):
    bob = await get_listening_discovery_protocol(event_loop)
    les_nodes = NodeFactory.create_batch(10)
    topic = b'les'
    for n in les_nodes:
        bob.topic_table.add_node(n, topic)
    alice = await get_listening_discovery_protocol(event_loop)

    echo = alice.send_topic_query(bob.this_node, topic)
    received_nodes = await alice.wait_topic_nodes(bob.this_node, echo)

    assert len(received_nodes) == 10
    assert sorted(received_nodes) == sorted(les_nodes)
コード例 #12
0
ファイル: test_discovery.py プロジェクト: jonnycrunch/trinity
async def test_protocol_bootstrap():
    node1, node2 = NodeFactory.create_batch(2)
    discovery = MockDiscoveryService([node1, node2])

    async def bond(node):
        assert discovery.routing.add_node(node) is None
        return True

    # Pretend we bonded successfully with our bootstrap nodes.
    discovery.bond = bond

    await discovery.bootstrap()

    assert len(discovery.messages) == 2
    # We don't care in which order the bootstrap nodes are contacted, nor which node_id was used
    # in the find_node request, so we just assert that we sent find_node msgs to both nodes.
    assert sorted([(node, cmd) for (node, cmd, _) in discovery.messages
                   ]) == sorted([(node1, 'find_node'), (node2, 'find_node')])
コード例 #13
0
async def test_get_peer_candidates(manually_driven_discovery, monkeypatch):
    total_nodes = 10
    nodes = NodeFactory.create_batch(total_nodes)
    discovery = manually_driven_discovery
    for node in nodes:
        discovery.node_db.set_enr(node.enr)
        assert discovery.routing.update(node.id) is None

    discovery._random_lookup_calls = 0

    async def mock_lookup_random():
        discovery._random_lookup_calls += 1

    monkeypatch.setattr(discovery, 'lookup_random', mock_lookup_random)

    def should_skip(skip_list, candidate):
        return candidate in skip_list

    candidates = discovery.get_peer_candidates(
        functools.partial(should_skip, tuple()), total_nodes)
    assert sorted(candidates) == sorted(nodes)

    candidates = discovery.get_peer_candidates(
        functools.partial(should_skip, tuple()), total_nodes + 10)
    assert sorted(candidates) == sorted(nodes)
    # When we don't have enough candidates, a random lookup should be triggered.
    with trio.fail_after(0.5):
        while discovery._random_lookup_calls != 1:
            await trio.sleep(0.01)

    candidates = discovery.get_peer_candidates(
        functools.partial(should_skip, tuple()), total_nodes - 1)
    assert len(candidates) == total_nodes - 1

    skip_list = (nodes[0], nodes[5], nodes[8])
    candidates = discovery.get_peer_candidates(
        functools.partial(should_skip, skip_list), total_nodes)
    assert sorted(candidates) == sorted(set(nodes).difference(skip_list))
    with trio.fail_after(0.5):
        while discovery._random_lookup_calls != 2:
            await trio.sleep(0.01)
コード例 #14
0
ファイル: test_discovery.py プロジェクト: teotoplak/trinity
async def test_update_routing_table_triggers_bond_if_eviction_candidate():
    proto = MockDiscoveryProtocol([])
    old_node, new_node = NodeFactory.create_batch(2)

    bond_called = False

    def bond(node):
        nonlocal bond_called
        bond_called = True
        assert node == old_node

    proto.bond = asyncio.coroutine(bond)
    # Pretend our routing table failed to add the new node by returning the least recently seen
    # node for an eviction check.
    proto.routing.add_node = lambda n: old_node

    proto.update_routing_table(new_node)

    assert new_node not in proto.routing
    # The update_routing_table() call above will have scheduled a future call to proto.bond() so
    # we need to yield here to give it a chance to run.
    await asyncio.sleep(0.001)
    assert bond_called
コード例 #15
0
async def test_update_routing_table_triggers_bond_if_eviction_candidate(
        nursery, manually_driven_discovery, monkeypatch):
    discovery = manually_driven_discovery
    old_node, new_node = NodeFactory.create_batch(2)

    bond_called = False

    async def bond(node):
        nonlocal bond_called
        bond_called = True
        assert node == old_node

    monkeypatch.setattr(discovery, 'bond', bond)
    # Pretend our routing table failed to add the new node by returning the least recently seen
    # node for an eviction check.
    monkeypatch.setattr(discovery.routing, 'add_node', lambda n: old_node)

    discovery.update_routing_table(new_node)

    assert new_node not in discovery.routing
    # The update_routing_table() call above will have scheduled a future call to discovery.bond() so
    # we need to yield here to give it a chance to run.
    await trio.sleep(0.001)
    assert bond_called
コード例 #16
0
async def test_aurora_pick_non_existing_candidates():
    candidates = set(NodeFactory.create_batch(2))
    exclusion_candidates = candidates
    result = aurora_pick(candidates, exclusion_candidates)

    assert result in exclusion_candidates