# 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. import std/os, testutils/unittests, eth/[keys, trie/db, trie/hexary, ssz/ssz_serialization], eth/p2p/discoveryv5/protocol as discv5_protocol, eth/p2p/discoveryv5/routing_table, ../../nimbus/[genesis, chain_config, db/db_chain], ../network/state/portal_protocol, ../network/state/content, ../network/state/portal_network, ./test_helpers proc genesisToTrie(filePath: string): HexaryTrie = # TODO: Doing our best here with API that exists, to be improved. var cg: CustomGenesis if not loadCustomGenesis(filePath, cg): quit(1) var chainDB = newBaseChainDB( newMemoryDb(), pruneTrie = false ) # TODO: Can't provide this at the `newBaseChainDB` call, need to adjust API chainDB.config = cg.config # TODO: this actually also creates a HexaryTrie and AccountStateDB, which we # could skip let header = toBlock(cg.genesis, chainDB) # Trie exists already in flat db, but need to provide the root initHexaryTrie(chainDB.db, header.stateRoot, chainDB.pruneTrie) procSuite "Content Network": let rng = newRng() asyncTest "Test Share Full State": let trie = genesisToTrie("fluffy" / "tests" / "custom_genesis" / "chainid7.json") node1 = initDiscoveryNode( rng, PrivateKey.random(rng[]), localAddress(20302)) node2 = initDiscoveryNode( rng, PrivateKey.random(rng[]), localAddress(20303)) proto1 = PortalNetwork.new(node1, ContentStorage(trie: trie)) proto2 = PortalNetwork.new(node2, ContentStorage(trie: trie)) check proto2.portalProtocol.addNode(node1.localNode) == Added var keys: seq[seq[byte]] for k, v in trie.replicate: keys.add(k) for key in keys: var nodeHash: NodeHash copyMem(nodeHash.data.addr, unsafeAddr key[0], sizeof(nodeHash.data)) let contentKey = ContentKey( networkId: 0'u16, contentType: content.ContentType.Account, nodeHash: nodeHash) let foundContent = await proto2.getContent(contentKey) check: foundContent.isSome() let hash = hexary.keccak(foundContent.get()) check hash.data == key await node1.closeWait() await node2.closeWait() asyncTest "Find content in the network via content lookup": let trie = genesisToTrie("fluffy" / "tests" / "custom_genesis" / "chainid7.json") node1 = initDiscoveryNode( rng, PrivateKey.random(rng[]), localAddress(20302)) node2 = initDiscoveryNode( rng, PrivateKey.random(rng[]), localAddress(20303)) node3 = initDiscoveryNode( rng, PrivateKey.random(rng[]), localAddress(20304)) proto1 = PortalNetwork.new(node1, ContentStorage(trie: trie)) proto2 = PortalNetwork.new(node2, ContentStorage(trie: trie)) proto3 = PortalNetwork.new(node3, ContentStorage(trie: trie)) # Node1 knows about Node2, and Node2 knows about Node3 which hold all content check proto1.portalProtocol.addNode(node2.localNode) == Added check proto2.portalProtocol.addNode(node3.localNode) == Added check (await proto2.portalProtocol.ping(node3.localNode)).isOk() var keys: seq[seq[byte]] for k, v in trie.replicate: keys.add(k) # Get first key var nodeHash: NodeHash let firstKey = keys[0] copyMem(nodeHash.data.addr, unsafeAddr firstKey[0], sizeof(nodeHash.data)) let contentKey = ContentKey( networkId: 0'u16, contentType: content.ContentType.Account, nodeHash: nodeHash) let foundContent = await proto1.getContent(contentKey) check: foundContent.isSome() let hash = hexary.keccak(foundContent.get()) check hash.data == firstKey await node1.closeWait() await node2.closeWait() await node3.closeWait()