# Nimbus - Portal Network # Copyright (c) 2021 Status Research & Development GmbH # Licensed and distributed under either of # * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). # * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). # at your option. This file may not be copied, modified, or distributed except according to those terms. {.used.} import chronos, testutils/unittests, stew/shims/net, eth/keys, eth/p2p/discoveryv5/routing_table, eth/p2p/discoveryv5/protocol as discv5_protocol, ../network/state/portal_protocol, ./test_helpers proc random(T: type UInt256, rng: var BrHmacDrbgContext): T = var key: UInt256 brHmacDrbgGenerate(addr rng, addr key, csize_t(sizeof(key))) key type Default2NodeTest = ref object node1: discv5_protocol.Protocol node2: discv5_protocol.Protocol proto1: PortalProtocol proto2: PortalProtocol proc defaultTestCase(rng: ref BrHmacDrbgContext): Default2NodeTest = let node1 = initDiscoveryNode( rng, PrivateKey.random(rng[]), localAddress(20302)) node2 = initDiscoveryNode( rng, PrivateKey.random(rng[]), localAddress(20303)) proto1 = PortalProtocol.new(node1) proto2 = PortalProtocol.new(node2) Default2NodeTest(node1: node1, node2: node2, proto1: proto1, proto2: proto2) proc stopTest(test: Default2NodeTest) {.async.} = test.proto1.stop() test.proto2.stop() await test.node1.closeWait() await test.node2.closeWait() procSuite "Portal Tests": let rng = newRng() asyncTest "Portal Ping/Pong": let test = defaultTestCase(rng) let pong = await test.proto1.ping(test.proto2.baseProtocol.localNode) check: pong.isOk() pong.get().enrSeq == 1'u64 pong.get().dataRadius == UInt256.high() await test.stopTest() asyncTest "Portal correctly mark node as seen after request": let test = defaultTestCase(rng) let initialNeighbours = test.proto1.neighbours(test.proto1.baseProtocol.localNode.id, seenOnly = false) check: len(initialNeighbours) == 0 discard test.proto1.addNode(test.proto2.baseProtocol.localNode) let allNeighboursAfterAdd = test.proto1.neighbours(test.proto1.baseProtocol.localNode.id, seenOnly = false) let seenNeighboursAfterAdd = test.proto1.neighbours(test.proto1.baseProtocol.localNode.id, seenOnly = true) check: len(allNeighboursAfterAdd) == 1 len(seenNeighboursAfterAdd) == 0 let pong = await test.proto1.ping(test.proto2.baseProtocol.localNode) let allNeighboursAfterPing = test.proto1.neighbours(test.proto1.baseProtocol.localNode.id, seenOnly = false) let seenNeighboursAfterPing = test.proto1.neighbours(test.proto1.baseProtocol.localNode.id, seenOnly = true) check: pong.isOk() len(allNeighboursAfterPing) == 1 len(seenNeighboursAfterPing) == 1 await test.stopTest() asyncTest "Portal FindNode/Nodes": let test = defaultTestCase(rng) block: # Find itself let nodes = await test.proto1.findNode(test.proto2.baseProtocol.localNode, List[uint16, 256](@[0'u16])) check: nodes.isOk() nodes.get().total == 1'u8 nodes.get().enrs.len() == 1 block: # Find nothing: this should result in nothing as we haven't started # the seeding of the portal protocol routing table yet. let nodes = await test.proto1.findNode(test.proto2.baseProtocol.localNode, List[uint16, 256](@[])) check: nodes.isOk() nodes.get().total == 1'u8 nodes.get().enrs.len() == 0 block: # Find for distance # ping in one direction to add, ping in the other to update as seen, # adding the node in the discovery v5 routing table. Could also launch # with bootstrap node instead. check (await test.node1.ping(test.node2.localNode)).isOk() check (await test.node2.ping(test.node1.localNode)).isOk() # Start the portal protocol to seed nodes from the discoveryv5 routing # table. test.proto2.start() let distance = logDist(test.node1.localNode.id, test.node2.localNode.id) let nodes = await test.proto1.findNode(test.proto2.baseProtocol.localNode, List[uint16, 256](@[distance])) check: nodes.isOk() nodes.get().total == 1'u8 nodes.get().enrs.len() == 1 await test.stopTest() asyncTest "Portal FindContent/FoundContent - send enrs": let test = defaultTestCase(rng) # ping in one direction to add, ping in the other to update as seen. check (await test.node1.ping(test.node2.localNode)).isOk() check (await test.node2.ping(test.node1.localNode)).isOk() # Start the portal protocol to seed nodes from the discoveryv5 routing # table. test.proto2.start() var nodeHash: NodeHash let contentKey = ContentKey(networkId: 0'u16, contentType: ContentType.Account, nodeHash: nodeHash) # content does not exist so this should provide us with the closest nodes # to the content, which is the only node in the routing table. let foundContent = await test.proto1.findContent(test.proto2.baseProtocol.localNode, contentKey) check: foundContent.isOk() foundContent.get().enrs.len() == 1 foundContent.get().payload.len() == 0 await test.stopTest()