2021-07-15 13:12:33 +00:00
|
|
|
# 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,
|
2021-11-18 11:06:53 +00:00
|
|
|
testutils/unittests, chronos,
|
2022-09-03 18:15:35 +00:00
|
|
|
eth/[common/eth_hash, keys, trie/db, trie/hexary],
|
2021-09-02 12:35:25 +00:00
|
|
|
eth/p2p/discoveryv5/protocol as discv5_protocol, eth/p2p/discoveryv5/routing_table,
|
2022-12-02 04:39:12 +00:00
|
|
|
../../nimbus/[config, db/db_chain, db/state_db],
|
|
|
|
../../nimbus/common/[chain_config, genesis],
|
2022-08-17 07:32:06 +00:00
|
|
|
../network/wire/[portal_protocol, portal_stream],
|
2021-10-09 11:22:03 +00:00
|
|
|
../network/state/[state_content, state_network],
|
2021-09-28 17:58:41 +00:00
|
|
|
../content_db,
|
2021-07-15 13:12:33 +00:00
|
|
|
./test_helpers
|
|
|
|
|
|
|
|
proc genesisToTrie(filePath: string): HexaryTrie =
|
|
|
|
# TODO: Doing our best here with API that exists, to be improved.
|
2021-09-16 15:59:46 +00:00
|
|
|
var cn: NetworkParams
|
|
|
|
if not loadNetworkParams(filePath, cn):
|
2021-07-15 13:12:33 +00:00
|
|
|
quit(1)
|
|
|
|
|
2022-12-02 04:39:12 +00:00
|
|
|
let sdb = newStateDB(newMemoryDB(), false)
|
|
|
|
let map = toForkToBlockNumber(cn.config)
|
|
|
|
let fork = map.toHardFork(0.toBlockNumber)
|
|
|
|
discard toGenesisHeader(cn.genesis, sdb, fork)
|
2022-02-15 03:22:05 +00:00
|
|
|
|
|
|
|
sdb.getTrie
|
2021-07-15 13:12:33 +00:00
|
|
|
|
2021-09-22 15:07:14 +00:00
|
|
|
procSuite "State Content Network":
|
2021-07-15 13:12:33 +00:00
|
|
|
let rng = newRng()
|
|
|
|
asyncTest "Test Share Full State":
|
|
|
|
let
|
2021-09-03 08:57:19 +00:00
|
|
|
trie = genesisToTrie("fluffy" / "tests" / "custom_genesis" / "chainid7.json")
|
|
|
|
|
2021-07-15 13:12:33 +00:00
|
|
|
node1 = initDiscoveryNode(
|
|
|
|
rng, PrivateKey.random(rng[]), localAddress(20302))
|
2022-08-17 07:32:06 +00:00
|
|
|
sm1 = StreamManager.new(node1)
|
2021-07-15 13:12:33 +00:00
|
|
|
node2 = initDiscoveryNode(
|
|
|
|
rng, PrivateKey.random(rng[]), localAddress(20303))
|
2022-08-17 07:32:06 +00:00
|
|
|
sm2 = StreamManager.new(node2)
|
2021-07-15 13:12:33 +00:00
|
|
|
|
2022-08-17 07:32:06 +00:00
|
|
|
proto1 = StateNetwork.new(node1, ContentDB.new("", uint32.high, inMemory = true), sm1)
|
|
|
|
proto2 = StateNetwork.new(node2, ContentDB.new("", uint32.high, inMemory = true), sm2)
|
2021-07-15 13:12:33 +00:00
|
|
|
|
2021-09-03 08:57:19 +00:00
|
|
|
check proto2.portalProtocol.addNode(node1.localNode) == Added
|
2021-07-15 13:12:33 +00:00
|
|
|
|
|
|
|
var keys: seq[seq[byte]]
|
|
|
|
for k, v in trie.replicate:
|
|
|
|
keys.add(k)
|
|
|
|
|
2021-09-28 17:58:41 +00:00
|
|
|
var nodeHash: NodeHash
|
|
|
|
copyMem(nodeHash.data.addr, unsafeAddr k[0], sizeof(nodeHash.data))
|
|
|
|
|
|
|
|
let
|
2021-11-17 16:11:17 +00:00
|
|
|
# TODO: add stateRoot, and path eventually
|
|
|
|
accountTrieNodeKey = AccountTrieNodeKey(nodeHash: nodeHash)
|
2021-09-28 17:58:41 +00:00
|
|
|
contentKey = ContentKey(
|
2021-11-17 16:11:17 +00:00
|
|
|
contentType: accountTrieNode, accountTrieNodeKey: accountTrieNodeKey)
|
2021-09-28 17:58:41 +00:00
|
|
|
contentId = toContentId(contentKey)
|
|
|
|
|
2022-05-09 15:18:57 +00:00
|
|
|
discard proto1.contentDB.put(contentId, v, proto1.portalProtocol.localNode.id)
|
2021-09-28 17:58:41 +00:00
|
|
|
|
2021-07-15 13:12:33 +00:00
|
|
|
for key in keys:
|
2021-07-20 12:04:57 +00:00
|
|
|
var nodeHash: NodeHash
|
|
|
|
copyMem(nodeHash.data.addr, unsafeAddr key[0], sizeof(nodeHash.data))
|
|
|
|
|
2021-07-15 13:12:33 +00:00
|
|
|
let
|
2021-11-17 16:11:17 +00:00
|
|
|
accountTrieNodeKey = AccountTrieNodeKey(nodeHash: nodeHash)
|
2021-07-15 13:12:33 +00:00
|
|
|
contentKey = ContentKey(
|
2021-11-17 16:11:17 +00:00
|
|
|
contentType: accountTrieNode, accountTrieNodeKey: accountTrieNodeKey)
|
|
|
|
contentId = toContentId(contentKey)
|
2021-07-15 13:12:33 +00:00
|
|
|
|
2021-09-24 09:22:07 +00:00
|
|
|
# Note: GetContent and thus the lookup here is not really needed, as we
|
|
|
|
# only have to request data to one node.
|
2021-09-03 08:57:19 +00:00
|
|
|
let foundContent = await proto2.getContent(contentKey)
|
2021-07-15 13:12:33 +00:00
|
|
|
|
|
|
|
check:
|
2021-09-03 08:57:19 +00:00
|
|
|
foundContent.isSome()
|
2021-07-15 13:12:33 +00:00
|
|
|
|
2022-09-03 18:15:35 +00:00
|
|
|
let hash = keccakHash(foundContent.get())
|
2021-07-15 13:12:33 +00:00
|
|
|
check hash.data == key
|
2021-09-02 12:35:25 +00:00
|
|
|
|
|
|
|
await node1.closeWait()
|
|
|
|
await node2.closeWait()
|
|
|
|
|
|
|
|
asyncTest "Find content in the network via content lookup":
|
2021-09-24 09:22:07 +00:00
|
|
|
# TODO: Improve this test so it actually need to go through several
|
2021-12-08 10:54:22 +00:00
|
|
|
# findNodes request, to properly test the lookup call.
|
2021-09-02 12:35:25 +00:00
|
|
|
let
|
2021-09-03 08:57:19 +00:00
|
|
|
trie = genesisToTrie("fluffy" / "tests" / "custom_genesis" / "chainid7.json")
|
2021-09-02 12:35:25 +00:00
|
|
|
node1 = initDiscoveryNode(
|
|
|
|
rng, PrivateKey.random(rng[]), localAddress(20302))
|
2022-08-17 07:32:06 +00:00
|
|
|
sm1 = StreamManager.new(node1)
|
2021-09-02 12:35:25 +00:00
|
|
|
node2 = initDiscoveryNode(
|
|
|
|
rng, PrivateKey.random(rng[]), localAddress(20303))
|
2022-08-17 07:32:06 +00:00
|
|
|
sm2 = StreamManager.new(node2)
|
2021-09-02 12:35:25 +00:00
|
|
|
node3 = initDiscoveryNode(
|
|
|
|
rng, PrivateKey.random(rng[]), localAddress(20304))
|
2022-08-17 07:32:06 +00:00
|
|
|
sm3 = StreamManager.new(node3)
|
2021-09-02 12:35:25 +00:00
|
|
|
|
2022-08-17 07:32:06 +00:00
|
|
|
proto1 = StateNetwork.new(node1, ContentDB.new("", uint32.high, inMemory = true), sm1)
|
|
|
|
proto2 = StateNetwork.new(node2, ContentDB.new("", uint32.high, inMemory = true), sm2)
|
|
|
|
proto3 = StateNetwork.new(node3, ContentDB.new("", uint32.high, inMemory = true), sm3)
|
2021-09-02 12:35:25 +00:00
|
|
|
|
|
|
|
# Node1 knows about Node2, and Node2 knows about Node3 which hold all content
|
2021-09-03 08:57:19 +00:00
|
|
|
check proto1.portalProtocol.addNode(node2.localNode) == Added
|
|
|
|
check proto2.portalProtocol.addNode(node3.localNode) == Added
|
2021-09-02 12:35:25 +00:00
|
|
|
|
2021-09-03 08:57:19 +00:00
|
|
|
check (await proto2.portalProtocol.ping(node3.localNode)).isOk()
|
2021-09-02 12:35:25 +00:00
|
|
|
|
|
|
|
var keys: seq[seq[byte]]
|
|
|
|
for k, v in trie.replicate:
|
|
|
|
keys.add(k)
|
|
|
|
|
2021-09-28 17:58:41 +00:00
|
|
|
var nodeHash: NodeHash
|
|
|
|
copyMem(nodeHash.data.addr, unsafeAddr k[0], sizeof(nodeHash.data))
|
|
|
|
|
|
|
|
let
|
2021-11-17 16:11:17 +00:00
|
|
|
accountTrieNodeKey = AccountTrieNodeKey(nodeHash: nodeHash)
|
2021-09-28 17:58:41 +00:00
|
|
|
contentKey = ContentKey(
|
2021-11-17 16:11:17 +00:00
|
|
|
contentType: accountTrieNode, accountTrieNodeKey: accountTrieNodeKey)
|
2021-09-28 17:58:41 +00:00
|
|
|
contentId = toContentId(contentKey)
|
|
|
|
|
2022-05-09 15:18:57 +00:00
|
|
|
discard proto2.contentDB.put(contentId, v, proto2.portalProtocol.localNode.id)
|
2021-09-28 17:58:41 +00:00
|
|
|
# Not needed right now as 1 node is enough considering node 1 is connected
|
|
|
|
# to both.
|
2022-05-09 15:18:57 +00:00
|
|
|
discard proto3.contentDB.put(contentId, v, proto3.portalProtocol.localNode.id)
|
2021-09-28 17:58:41 +00:00
|
|
|
|
2021-09-02 12:35:25 +00:00
|
|
|
# Get first key
|
|
|
|
var nodeHash: NodeHash
|
|
|
|
let firstKey = keys[0]
|
|
|
|
copyMem(nodeHash.data.addr, unsafeAddr firstKey[0], sizeof(nodeHash.data))
|
|
|
|
|
2021-11-17 16:11:17 +00:00
|
|
|
let
|
|
|
|
accountTrieNodeKey = AccountTrieNodeKey(nodeHash: nodeHash)
|
|
|
|
contentKey = ContentKey(
|
|
|
|
contentType: accountTrieNode, accountTrieNodeKey: accountTrieNodeKey)
|
2021-09-02 12:35:25 +00:00
|
|
|
|
2021-09-03 08:57:19 +00:00
|
|
|
let foundContent = await proto1.getContent(contentKey)
|
2021-09-02 12:35:25 +00:00
|
|
|
|
|
|
|
check:
|
|
|
|
foundContent.isSome()
|
|
|
|
|
2022-09-03 18:15:35 +00:00
|
|
|
let hash = keccakHash(foundContent.get())
|
2021-09-02 12:35:25 +00:00
|
|
|
|
|
|
|
check hash.data == firstKey
|
|
|
|
|
2021-08-27 16:04:55 +00:00
|
|
|
await node1.closeWait()
|
|
|
|
await node2.closeWait()
|
2021-09-02 12:35:25 +00:00
|
|
|
await node3.closeWait()
|
2021-10-05 19:16:33 +00:00
|
|
|
|
|
|
|
asyncTest "Find other nodes in state network with correct custom distance":
|
|
|
|
let
|
|
|
|
node1 = initDiscoveryNode(
|
|
|
|
rng, PrivateKey.random(rng[]), localAddress(20302))
|
2022-08-17 07:32:06 +00:00
|
|
|
sm1 = StreamManager.new(node1)
|
2021-10-05 19:16:33 +00:00
|
|
|
node2 = initDiscoveryNode(
|
|
|
|
rng, PrivateKey.random(rng[]), localAddress(20303))
|
2022-08-17 07:32:06 +00:00
|
|
|
sm2 = StreamManager.new(node2)
|
2021-10-05 19:16:33 +00:00
|
|
|
|
2022-08-17 07:32:06 +00:00
|
|
|
proto1 = StateNetwork.new(node1, ContentDB.new("", uint32.high, inMemory = true), sm1)
|
|
|
|
proto2 = StateNetwork.new(node2, ContentDB.new("", uint32.high, inMemory = true), sm2)
|
2021-10-05 19:16:33 +00:00
|
|
|
|
|
|
|
check (await node1.ping(node2.localNode)).isOk()
|
|
|
|
check (await node2.ping(node1.localNode)).isOk()
|
|
|
|
|
|
|
|
proto2.portalProtocol.seedTable()
|
|
|
|
|
2021-10-09 11:22:03 +00:00
|
|
|
let distance = proto1.portalProtocol.routingTable.logDistance(
|
|
|
|
node1.localNode.id, node2.localNode.id)
|
2021-10-05 19:16:33 +00:00
|
|
|
|
2021-12-08 10:54:22 +00:00
|
|
|
let nodes = await proto1.portalProtocol.findNodes(
|
2022-03-19 07:54:42 +00:00
|
|
|
proto2.portalProtocol.localNode, @[distance])
|
|
|
|
|
|
|
|
# TODO: This gives an error because of the custom distances issues that
|
|
|
|
# need to be resolved first.
|
|
|
|
skip()
|
|
|
|
# check:
|
|
|
|
# nodes.isOk()
|
|
|
|
# nodes.get().len() == 1
|
2021-10-05 19:16:33 +00:00
|
|
|
|
|
|
|
await node1.closeWait()
|
|
|
|
await node2.closeWait()
|