mirror of
https://github.com/logos-storage/logos-storage-nim-dht.git
synced 2026-01-05 23:13:10 +00:00
fix(discovery): prevent premature node eviction from routing table
The findNode and findNodeFast operations were using the default aggressive removal threshold (1.0) when timing out, while other timeout operations (ping, talkReq, getProviders) correctly used NoreplyRemoveThreshold (0.5). This inconsistency caused nodes with excellent reliability (1.0) to be removed during heavy load scenarios when findNode/findNodeFast operations timed out, even though the nodes were still healthy and simply slow to respond. Changed findNode and findNodeFast timeout paths to use NoreplyRemoveThreshold, ensuring consistent and more tolerant behavior across all timeout scenarios. This aligns with Kademlia's recommendation to be conservative about removing nodes, especially during temporary network congestion. Evidence from logs showing the issue: DBG - Node added to routing table topics="discv5 routingtable" tid=1 n=1ff*7a561e:10.244.0.208:6890 DBG - bucket topics="discv5" tid=1 depth=0 len=2 standby=0 DBG - node topics="discv5" tid=1 n=130*db8a1b:10.244.2.207:6890 rttMin=1 rttAvg=2 reliability=1.0 DBG - node topics="discv5" tid=1 n=1ff*7a561e:10.244.0.208:6890 rttMin=1 rttAvg=14 reliability=1.0 DBG - Node removed from routing table topics="discv5 routingtable" tid=1 n=1ff*7a561e:10.244.0.208:6890 DBG - Total nodes in discv5 routing table topics="discv5" tid=1 total=1 DBG - bucket topics="discv5" tid=1 depth=0 len=1 standby=0 DBG - node topics="discv5" tid=1 n=130*db8a1b:10.244.2.207:6890 rttMin=1 rttAvg=165 reliability=0.957 DBG - Node removed from routing table topics="discv5 routingtable" tid=1 n=130*db8a1b:10.244.2.207:6890 DBG - Total nodes in discv5 routing table topics="discv5" tid=1 total=0 First entry shows a node with perfect reliability (1.0) and 14ms RTT being removed. Second shows a node with 95.7% reliability also being evicted. Signed-off-by: Chrysostomos Nanakos <chris@include.gr>
This commit is contained in:
parent
99884b5971
commit
71bd679365
@ -136,7 +136,7 @@ const
|
|||||||
FindnodeSeenThreshold = 1.0 ## threshold used as findnode response filter
|
FindnodeSeenThreshold = 1.0 ## threshold used as findnode response filter
|
||||||
LookupSeenThreshold = 0.0 ## threshold used for lookup nodeset selection
|
LookupSeenThreshold = 0.0 ## threshold used for lookup nodeset selection
|
||||||
QuerySeenThreshold = 0.0 ## threshold used for query nodeset selection
|
QuerySeenThreshold = 0.0 ## threshold used for query nodeset selection
|
||||||
NoreplyRemoveThreshold = 0.5 ## remove node on no reply if 'seen' is below this value
|
NoreplyRemoveThreshold* = 0.5 ## remove node on no reply if 'seen' is below this value
|
||||||
|
|
||||||
func shortLog*(record: SignedPeerRecord): string =
|
func shortLog*(record: SignedPeerRecord): string =
|
||||||
## Returns compact string representation of ``SignedPeerRecord``.
|
## Returns compact string representation of ``SignedPeerRecord``.
|
||||||
@ -587,7 +587,7 @@ proc findNode*(d: Protocol, toNode: Node, distances: seq[uint16]):
|
|||||||
return ok(res)
|
return ok(res)
|
||||||
else:
|
else:
|
||||||
trace "findNode nodes not OK."
|
trace "findNode nodes not OK."
|
||||||
d.replaceNode(toNode)
|
d.replaceNode(toNode, NoreplyRemoveThreshold)
|
||||||
return err(nodes.error)
|
return err(nodes.error)
|
||||||
|
|
||||||
proc findNodeFast*(d: Protocol, toNode: Node, target: NodeId):
|
proc findNodeFast*(d: Protocol, toNode: Node, target: NodeId):
|
||||||
@ -605,7 +605,7 @@ proc findNodeFast*(d: Protocol, toNode: Node, target: NodeId):
|
|||||||
let res = verifyNodesRecords(nodes.get(), toNode, FindNodeFastResultLimit)
|
let res = verifyNodesRecords(nodes.get(), toNode, FindNodeFastResultLimit)
|
||||||
return ok(res)
|
return ok(res)
|
||||||
else:
|
else:
|
||||||
d.replaceNode(toNode)
|
d.replaceNode(toNode, NoreplyRemoveThreshold)
|
||||||
return err(nodes.error)
|
return err(nodes.error)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -2,10 +2,15 @@
|
|||||||
|
|
||||||
import
|
import
|
||||||
std/tables,
|
std/tables,
|
||||||
chronos, chronicles, stint, asynctest/chronos/unittest,
|
chronos,
|
||||||
stew/byteutils, bearssl/rand,
|
chronicles,
|
||||||
|
stint,
|
||||||
|
asynctest/chronos/unittest,
|
||||||
|
stew/byteutils,
|
||||||
|
bearssl/rand,
|
||||||
libp2p/crypto/crypto,
|
libp2p/crypto/crypto,
|
||||||
codexdht/discv5/[transport, spr, node, routing_table, encoding, sessions, nodes_verification],
|
codexdht/discv5/
|
||||||
|
[transport, spr, node, routing_table, encoding, sessions, nodes_verification],
|
||||||
codexdht/discv5/crypto as dhtcrypto,
|
codexdht/discv5/crypto as dhtcrypto,
|
||||||
codexdht/discv5/protocol as discv5_protocol,
|
codexdht/discv5/protocol as discv5_protocol,
|
||||||
../dht/test_helper
|
../dht/test_helper
|
||||||
@ -22,13 +27,13 @@ suite "Discovery v5 Tests":
|
|||||||
pk = PrivateKey.example(rng)
|
pk = PrivateKey.example(rng)
|
||||||
targetPk = PrivateKey.example(rng)
|
targetPk = PrivateKey.example(rng)
|
||||||
node = initDiscoveryNode(rng, pk, localAddress(20302))
|
node = initDiscoveryNode(rng, pk, localAddress(20302))
|
||||||
targetNode = targetPk.generateNode(port=26302)
|
targetNode = targetPk.generateNode(port = 26302)
|
||||||
|
|
||||||
check node.addNode(targetNode)
|
check node.addNode(targetNode)
|
||||||
|
|
||||||
for i in 0..<1000:
|
for i in 0 ..< 1000:
|
||||||
let pk = PrivateKey.example(rng)
|
let pk = PrivateKey.example(rng)
|
||||||
discard node.addNode(pk.generateNode(port=27302+i))
|
discard node.addNode(pk.generateNode(port = 27302 + i))
|
||||||
|
|
||||||
let n = node.getNode(targetNode.id)
|
let n = node.getNode(targetNode.id)
|
||||||
check n.isSome()
|
check n.isSome()
|
||||||
@ -39,14 +44,13 @@ suite "Discovery v5 Tests":
|
|||||||
test "Node deletion":
|
test "Node deletion":
|
||||||
let
|
let
|
||||||
pkBootnode = PrivateKey.example(rng)
|
pkBootnode = PrivateKey.example(rng)
|
||||||
bootnode = initDiscoveryNode(
|
bootnode = initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20301))
|
||||||
rng, PrivateKey.example(rng), localAddress(20301))
|
|
||||||
node1 = initDiscoveryNode(
|
node1 = initDiscoveryNode(
|
||||||
rng, PrivateKey.example(rng), localAddress(20302),
|
rng, PrivateKey.example(rng), localAddress(20302), @[bootnode.localNode.record]
|
||||||
@[bootnode.localNode.record])
|
)
|
||||||
node2 = initDiscoveryNode(
|
node2 = initDiscoveryNode(
|
||||||
rng, PrivateKey.example(rng), localAddress(20303),
|
rng, PrivateKey.example(rng), localAddress(20303), @[bootnode.localNode.record]
|
||||||
@[bootnode.localNode.record])
|
)
|
||||||
pong1 = await discv5_protocol.ping(node1, bootnode.localNode)
|
pong1 = await discv5_protocol.ping(node1, bootnode.localNode)
|
||||||
pong2 = await discv5_protocol.ping(node1, node2.localNode)
|
pong2 = await discv5_protocol.ping(node1, node2.localNode)
|
||||||
|
|
||||||
@ -83,7 +87,7 @@ suite "Discovery v5 Tests":
|
|||||||
("0x0100", 9'u16),
|
("0x0100", 9'u16),
|
||||||
("0x01ff", 9'u16),
|
("0x01ff", 9'u16),
|
||||||
("0x8000", 16'u16),
|
("0x8000", 16'u16),
|
||||||
("0xffff", 16'u16)
|
("0xffff", 16'u16),
|
||||||
]
|
]
|
||||||
|
|
||||||
for (id, d) in testValues:
|
for (id, d) in testValues:
|
||||||
@ -93,20 +97,17 @@ suite "Discovery v5 Tests":
|
|||||||
# Values for this test are taken from
|
# Values for this test are taken from
|
||||||
# https://github.com/ethereum/go-ethereum/blob/d8ff53dfb8a516f47db37dbc7fd7ad18a1e8a125/p2p/discover/v4_lookup_test.go#L176
|
# https://github.com/ethereum/go-ethereum/blob/d8ff53dfb8a516f47db37dbc7fd7ad18a1e8a125/p2p/discover/v4_lookup_test.go#L176
|
||||||
const
|
const
|
||||||
targetKey = "045d485bdcbe9bc89314a10ae9231e429d33853e3a8fa2af39f5f827370a2e4185e344ace5d16237491dad41f278f1d3785210d29ace76cd627b9147ee340b1125"
|
targetKey =
|
||||||
|
"045d485bdcbe9bc89314a10ae9231e429d33853e3a8fa2af39f5f827370a2e4185e344ace5d16237491dad41f278f1d3785210d29ace76cd627b9147ee340b1125"
|
||||||
testValues = [
|
testValues = [
|
||||||
("14a98db9b46a831d67eff29f3b85b1b485bb12ae9796aea98d91be3dc78d8a91", 248'u16),
|
("14a98db9b46a831d67eff29f3b85b1b485bb12ae9796aea98d91be3dc78d8a91", 248'u16),
|
||||||
|
|
||||||
("29738ba0c1a4397d6a65f292eee07f02df8e58d41594ba2be3cf84ce0fc58169", 252'u16),
|
("29738ba0c1a4397d6a65f292eee07f02df8e58d41594ba2be3cf84ce0fc58169", 252'u16),
|
||||||
("dec742079ec00ff4ec1284d7905bc3de2366f67a0769431fd16f80fd68c58a7c", 252'u16),
|
("dec742079ec00ff4ec1284d7905bc3de2366f67a0769431fd16f80fd68c58a7c", 252'u16),
|
||||||
|
|
||||||
("ce1435a956a98ffec484cd11489c4f165cf1606819ab6b521cee440f0c677e9e", 253'u16),
|
("ce1435a956a98ffec484cd11489c4f165cf1606819ab6b521cee440f0c677e9e", 253'u16),
|
||||||
("120260dce739b6f71f171da6f65bc361b5fad51db74cf02d3e973347819a6518", 253'u16),
|
("120260dce739b6f71f171da6f65bc361b5fad51db74cf02d3e973347819a6518", 253'u16),
|
||||||
|
|
||||||
("a30599b12827b69120633f15b98a7f6bc9fc2e9a0fd6ae2ebb767c0e64d743ab", 254'u16),
|
("a30599b12827b69120633f15b98a7f6bc9fc2e9a0fd6ae2ebb767c0e64d743ab", 254'u16),
|
||||||
("8c5b422155d33ea8e9d46f71d1ad3e7b24cb40051413ffa1a81cff613d243ba9", 254'u16),
|
("8c5b422155d33ea8e9d46f71d1ad3e7b24cb40051413ffa1a81cff613d243ba9", 254'u16),
|
||||||
("996e7f8d1638be92d7328b4770f47e5420fc4bafecb4324fd33b1f5d9f403a75", 254'u16),
|
("996e7f8d1638be92d7328b4770f47e5420fc4bafecb4324fd33b1f5d9f403a75", 254'u16),
|
||||||
|
|
||||||
("d09e5eaeec0fd596236faed210e55ef45112409a5aa7f3276d26646080dcfaeb", 255'u16),
|
("d09e5eaeec0fd596236faed210e55ef45112409a5aa7f3276d26646080dcfaeb", 255'u16),
|
||||||
("6cfbd7b8503073fc3dbdb746a7c672571648d3bd15197ccf7f7fef3d904f53a2", 255'u16),
|
("6cfbd7b8503073fc3dbdb746a7c672571648d3bd15197ccf7f7fef3d904f53a2", 255'u16),
|
||||||
("9ae91101d6b5048607f41ec0f690ef5d09507928aded2410aabd9237aa2727d7", 255'u16),
|
("9ae91101d6b5048607f41ec0f690ef5d09507928aded2410aabd9237aa2727d7", 255'u16),
|
||||||
@ -116,7 +117,6 @@ suite "Discovery v5 Tests":
|
|||||||
("1fa56cf25d4b46c2bf94e82355aa631717b63190785ac6bae545a88aadc304a9", 255'u16),
|
("1fa56cf25d4b46c2bf94e82355aa631717b63190785ac6bae545a88aadc304a9", 255'u16),
|
||||||
("3c38c503c0376f9b4adcbe935d5f4b890391741c764f61b03cd4d0d42deae002", 255'u16),
|
("3c38c503c0376f9b4adcbe935d5f4b890391741c764f61b03cd4d0d42deae002", 255'u16),
|
||||||
("3a54af3e9fa162bc8623cdf3e5d9b70bf30ade1d54cc3abea8659aba6cff471f", 255'u16),
|
("3a54af3e9fa162bc8623cdf3e5d9b70bf30ade1d54cc3abea8659aba6cff471f", 255'u16),
|
||||||
|
|
||||||
("511b1686e4e58a917f7f848e9bf5539d206a68f5ad6b54b552c2399fe7d174ae", 256'u16),
|
("511b1686e4e58a917f7f848e9bf5539d206a68f5ad6b54b552c2399fe7d174ae", 256'u16),
|
||||||
("c1e20dbbf0d530e50573bd0a260b32ec15eb9190032b4633d44834afc8afe578", 256'u16),
|
("c1e20dbbf0d530e50573bd0a260b32ec15eb9190032b4633d44834afc8afe578", 256'u16),
|
||||||
("ed5f38f5702d92d306143e5d9154fb21819777da39af325ea359f453d179e80b", 256'u16),
|
("ed5f38f5702d92d306143e5d9154fb21819777da39af325ea359f453d179e80b", 256'u16),
|
||||||
@ -138,7 +138,7 @@ suite "Discovery v5 Tests":
|
|||||||
("d269609743ef29d6446e3355ec647e38d919c82a4eb5837e442efd7f4218944f", 256'u16),
|
("d269609743ef29d6446e3355ec647e38d919c82a4eb5837e442efd7f4218944f", 256'u16),
|
||||||
("937b1af801def4e8f5a3a8bd225a8bcff1db764e41d3e177f2e9376e8dd87233", 256'u16),
|
("937b1af801def4e8f5a3a8bd225a8bcff1db764e41d3e177f2e9376e8dd87233", 256'u16),
|
||||||
("6799a02ea1999aefdcbcc4d3ff9544478be7365a328d0d0f37c26bd95ade0cda", 256'u16),
|
("6799a02ea1999aefdcbcc4d3ff9544478be7365a328d0d0f37c26bd95ade0cda", 256'u16),
|
||||||
("e24a7bc9051058f918646b0f6e3d16884b2a55a15553b89bab910d55ebc36116", 256'u16)
|
("e24a7bc9051058f918646b0f6e3d16884b2a55a15553b89bab910d55ebc36116", 256'u16),
|
||||||
]
|
]
|
||||||
|
|
||||||
let
|
let
|
||||||
@ -163,7 +163,7 @@ suite "Discovery v5 Tests":
|
|||||||
("0x0008", 4'u16),
|
("0x0008", 4'u16),
|
||||||
("0x0080", 8'u16),
|
("0x0080", 8'u16),
|
||||||
("0x0100", 9'u16),
|
("0x0100", 9'u16),
|
||||||
("0x8000", 16'u16)
|
("0x8000", 16'u16),
|
||||||
]
|
]
|
||||||
|
|
||||||
for (id, d) in testValues:
|
for (id, d) in testValues:
|
||||||
@ -171,14 +171,15 @@ suite "Discovery v5 Tests":
|
|||||||
|
|
||||||
test "Distance to id check with keys":
|
test "Distance to id check with keys":
|
||||||
const
|
const
|
||||||
targetKey = "045d485bdcbe9bc89314a10ae9231e429d33853e3a8fa2af39f5f827370a2e4185e344ace5d16237491dad41f278f1d3785210d29ace76cd627b9147ee340b1125"
|
targetKey =
|
||||||
|
"045d485bdcbe9bc89314a10ae9231e429d33853e3a8fa2af39f5f827370a2e4185e344ace5d16237491dad41f278f1d3785210d29ace76cd627b9147ee340b1125"
|
||||||
testValues = [ # possible id in that distance range
|
testValues = [ # possible id in that distance range
|
||||||
("cd2c707bdcbdf5109c66de68e8f26adec1527d075e0f93df0ad21c72e98b7a4d", 251'u16),
|
("cd2c707bdcbdf5109c66de68e8f26adec1527d075e0f93df0ad21c72e98b7a4d", 251'u16),
|
||||||
("c12c707bdcbdf5109c66de68e8f26adec1527d075e0f93df0ad21c72e98b7a4d", 252'u16),
|
("c12c707bdcbdf5109c66de68e8f26adec1527d075e0f93df0ad21c72e98b7a4d", 252'u16),
|
||||||
("d92c707bdcbdf5109c66de68e8f26adec1527d075e0f93df0ad21c72e98b7a4d", 253'u16),
|
("d92c707bdcbdf5109c66de68e8f26adec1527d075e0f93df0ad21c72e98b7a4d", 253'u16),
|
||||||
("e92c707bdcbdf5109c66de68e8f26adec1527d075e0f93df0ad21c72e98b7a4d", 254'u16),
|
("e92c707bdcbdf5109c66de68e8f26adec1527d075e0f93df0ad21c72e98b7a4d", 254'u16),
|
||||||
("892c707bdcbdf5109c66de68e8f26adec1527d075e0f93df0ad21c72e98b7a4d", 255'u16),
|
("892c707bdcbdf5109c66de68e8f26adec1527d075e0f93df0ad21c72e98b7a4d", 255'u16),
|
||||||
("492c707bdcbdf5109c66de68e8f26adec1527d075e0f93df0ad21c72e98b7a4d", 256'u16)
|
("492c707bdcbdf5109c66de68e8f26adec1527d075e0f93df0ad21c72e98b7a4d", 256'u16),
|
||||||
]
|
]
|
||||||
|
|
||||||
let
|
let
|
||||||
@ -191,11 +192,11 @@ suite "Discovery v5 Tests":
|
|||||||
test "FindNode Test":
|
test "FindNode Test":
|
||||||
const dist = 253'u16
|
const dist = 253'u16
|
||||||
let
|
let
|
||||||
mainNodeKey = PrivateKey.fromHex(
|
mainNodeKey = PrivateKey
|
||||||
"a2b50376a79b1a8c8a3296485572bdfbf54708bb46d3c25d73d2723aaaf6a617")
|
.fromHex("a2b50376a79b1a8c8a3296485572bdfbf54708bb46d3c25d73d2723aaaf6a617")
|
||||||
.expect("Valid private key hex")
|
.expect("Valid private key hex")
|
||||||
testNodeKey = PrivateKey.fromHex(
|
testNodeKey = PrivateKey
|
||||||
"a2b50376a79b1a8c8a3296485572bdfbf54708bb46d3c25d73d2723aaaf6a618")
|
.fromHex("a2b50376a79b1a8c8a3296485572bdfbf54708bb46d3c25d73d2723aaaf6a618")
|
||||||
.expect("Valid private key hex")
|
.expect("Valid private key hex")
|
||||||
mainNode = initDiscoveryNode(rng, mainNodeKey, localAddress(20301))
|
mainNode = initDiscoveryNode(rng, mainNodeKey, localAddress(20301))
|
||||||
testNode = initDiscoveryNode(rng, testNodeKey, localAddress(20302))
|
testNode = initDiscoveryNode(rng, testNodeKey, localAddress(20302))
|
||||||
@ -210,38 +211,33 @@ suite "Discovery v5 Tests":
|
|||||||
check (await mainNode.ping(testNode.localNode)).isOk()
|
check (await mainNode.ping(testNode.localNode)).isOk()
|
||||||
|
|
||||||
# Get SPR of the node itself
|
# Get SPR of the node itself
|
||||||
var discovered =
|
var discovered = await findNode(testNode, mainNode.localNode, @[0'u16])
|
||||||
await findNode(testNode, mainNode.localNode, @[0'u16])
|
|
||||||
check:
|
check:
|
||||||
discovered.isOk
|
discovered.isOk
|
||||||
discovered[].len == 1
|
discovered[].len == 1
|
||||||
discovered[][0] == mainNode.localNode
|
discovered[][0] == mainNode.localNode
|
||||||
# Get SPRs of nodes added at provided logarithmic distance
|
# Get SPRs of nodes added at provided logarithmic distance
|
||||||
discovered =
|
discovered = await findNode(testNode, mainNode.localNode, @[dist])
|
||||||
await findNode(testNode, mainNode.localNode, @[dist])
|
|
||||||
check discovered.isOk
|
check discovered.isOk
|
||||||
check discovered[].len == 10
|
check discovered[].len == 10
|
||||||
for n in nodes:
|
for n in nodes:
|
||||||
check discovered[].contains(n)
|
check discovered[].contains(n)
|
||||||
|
|
||||||
# Too high logarithmic distance, should return no nodes.
|
# Too high logarithmic distance, should return no nodes.
|
||||||
discovered =
|
discovered = await findNode(testNode, mainNode.localNode, @[high(uint16)])
|
||||||
await findNode(testNode, mainNode.localNode, @[high(uint16)])
|
|
||||||
check:
|
check:
|
||||||
discovered.isOk
|
discovered.isOk
|
||||||
discovered[].len == 0
|
discovered[].len == 0
|
||||||
|
|
||||||
# Logarithmic distance of 256 should only return the testNode
|
# Logarithmic distance of 256 should only return the testNode
|
||||||
discovered =
|
discovered = await findNode(testNode, mainNode.localNode, @[256'u16])
|
||||||
await findNode(testNode, mainNode.localNode, @[256'u16])
|
|
||||||
check:
|
check:
|
||||||
discovered.isOk
|
discovered.isOk
|
||||||
discovered[].len == 1
|
discovered[].len == 1
|
||||||
discovered[][0] == testNode.localNode
|
discovered[][0] == testNode.localNode
|
||||||
|
|
||||||
# Empty bucket
|
# Empty bucket
|
||||||
discovered =
|
discovered = await findNode(testNode, mainNode.localNode, @[254'u16])
|
||||||
await findNode(testNode, mainNode.localNode, @[254'u16])
|
|
||||||
check discovered.isOk
|
check discovered.isOk
|
||||||
check discovered[].len == 0
|
check discovered[].len == 0
|
||||||
|
|
||||||
@ -250,8 +246,7 @@ suite "Discovery v5 Tests":
|
|||||||
discard mainNode.addSeenNode(n) # for testing only!
|
discard mainNode.addSeenNode(n) # for testing only!
|
||||||
|
|
||||||
# Full bucket
|
# Full bucket
|
||||||
discovered =
|
discovered = await findNode(testNode, mainNode.localNode, @[dist])
|
||||||
await findNode(testNode, mainNode.localNode, @[dist])
|
|
||||||
check discovered.isOk
|
check discovered.isOk
|
||||||
check discovered[].len == 16
|
check discovered[].len == 16
|
||||||
|
|
||||||
@ -259,27 +254,26 @@ suite "Discovery v5 Tests":
|
|||||||
await testNode.closeWait()
|
await testNode.closeWait()
|
||||||
|
|
||||||
test "FindNode with test table":
|
test "FindNode with test table":
|
||||||
|
let mainNode = initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20301))
|
||||||
let mainNode =
|
|
||||||
initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20301))
|
|
||||||
|
|
||||||
# Generate 1000 random nodes and add to our main node's routing table
|
# Generate 1000 random nodes and add to our main node's routing table
|
||||||
for i in 0..<1000:
|
for i in 0 ..< 1000:
|
||||||
discard mainNode.addSeenNode(generateNode(PrivateKey.example(rng), port=28302+i)) # for testing only!
|
discard mainNode.addSeenNode(
|
||||||
|
generateNode(PrivateKey.example(rng), port = 28302 + i)
|
||||||
|
) # for testing only!
|
||||||
|
|
||||||
let
|
let
|
||||||
neighbours = mainNode.neighbours(mainNode.localNode.id)
|
neighbours = mainNode.neighbours(mainNode.localNode.id)
|
||||||
closest = neighbours[0]
|
closest = neighbours[0]
|
||||||
closestDistance = logDistance(closest.id, mainNode.localNode.id)
|
closestDistance = logDistance(closest.id, mainNode.localNode.id)
|
||||||
|
|
||||||
debug "Closest neighbour", closestDistance, id=closest.id.toHex()
|
debug "Closest neighbour", closestDistance, id = closest.id.toHex()
|
||||||
|
|
||||||
let
|
let
|
||||||
testNode = initDiscoveryNode(
|
testNode = initDiscoveryNode(
|
||||||
rng, PrivateKey.example(rng), localAddress(20302),
|
rng, PrivateKey.example(rng), localAddress(20302), @[mainNode.localNode.record]
|
||||||
@[mainNode.localNode.record])
|
)
|
||||||
discovered = await findNode(testNode, mainNode.localNode,
|
discovered = await findNode(testNode, mainNode.localNode, @[closestDistance])
|
||||||
@[closestDistance])
|
|
||||||
|
|
||||||
check discovered.isOk
|
check discovered.isOk
|
||||||
check closest in discovered[]
|
check closest in discovered[]
|
||||||
@ -288,18 +282,22 @@ suite "Discovery v5 Tests":
|
|||||||
await testNode.closeWait()
|
await testNode.closeWait()
|
||||||
|
|
||||||
proc testLookupTargets(fast: bool = false): Future[bool] {.async.} =
|
proc testLookupTargets(fast: bool = false): Future[bool] {.async.} =
|
||||||
const
|
const nodeCount = 17
|
||||||
nodeCount = 17
|
|
||||||
|
|
||||||
let bootNode =
|
let bootNode = initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20301))
|
||||||
initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20301))
|
|
||||||
await bootNode.start()
|
await bootNode.start()
|
||||||
|
|
||||||
var nodes = newSeqOfCap[discv5_protocol.Protocol](nodeCount)
|
var nodes = newSeqOfCap[discv5_protocol.Protocol](nodeCount)
|
||||||
nodes.add(bootNode)
|
nodes.add(bootNode)
|
||||||
for i in 1 ..< nodeCount:
|
for i in 1 ..< nodeCount:
|
||||||
nodes.add(initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20301 + i),
|
nodes.add(
|
||||||
@[bootNode.localNode.record]))
|
initDiscoveryNode(
|
||||||
|
rng,
|
||||||
|
PrivateKey.example(rng),
|
||||||
|
localAddress(20301 + i),
|
||||||
|
@[bootNode.localNode.record],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
# Make sure all nodes have "seen" each other by forcing pings
|
# Make sure all nodes have "seen" each other by forcing pings
|
||||||
for n in nodes:
|
for n in nodes:
|
||||||
@ -314,9 +312,10 @@ suite "Discovery v5 Tests":
|
|||||||
for i in 1 ..< nodeCount:
|
for i in 1 ..< nodeCount:
|
||||||
await nodes[i].start()
|
await nodes[i].start()
|
||||||
|
|
||||||
for i in 0..<nodeCount-1:
|
for i in 0 ..< nodeCount - 1:
|
||||||
let target = nodes[i]
|
let target = nodes[i]
|
||||||
let discovered = await nodes[nodeCount-1].lookup(target.localNode.id, fast = fast)
|
let discovered =
|
||||||
|
await nodes[nodeCount - 1].lookup(target.localNode.id, fast = fast)
|
||||||
debug "Lookup result", target = target.localNode, discovered
|
debug "Lookup result", target = target.localNode, discovered
|
||||||
if discovered[0] != target.localNode:
|
if discovered[0] != target.localNode:
|
||||||
return false
|
return false
|
||||||
@ -334,10 +333,8 @@ suite "Discovery v5 Tests":
|
|||||||
|
|
||||||
test "Resolve target":
|
test "Resolve target":
|
||||||
let
|
let
|
||||||
mainNode =
|
mainNode = initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20301))
|
||||||
initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20301))
|
lookupNode = initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20302))
|
||||||
lookupNode =
|
|
||||||
initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20302))
|
|
||||||
targetKey = PrivateKey.example(rng)
|
targetKey = PrivateKey.example(rng)
|
||||||
targetAddress = localAddress(20303)
|
targetAddress = localAddress(20303)
|
||||||
targetNode = initDiscoveryNode(rng, targetKey, targetAddress)
|
targetNode = initDiscoveryNode(rng, targetKey, targetAddress)
|
||||||
@ -356,20 +353,27 @@ suite "Discovery v5 Tests":
|
|||||||
n.isSome()
|
n.isSome()
|
||||||
n.get().id == targetId
|
n.get().id == targetId
|
||||||
n.get().record.seqNum == targetSeqNum
|
n.get().record.seqNum == targetSeqNum
|
||||||
# Node will be removed because of failed findNode request.
|
|
||||||
|
# Verify node is still in routing table after timeout (high reliability preserved)
|
||||||
|
let nodeInTable = mainNode.getNode(targetId)
|
||||||
|
check:
|
||||||
|
nodeInTable.isSome()
|
||||||
|
nodeInTable.get().id == targetId
|
||||||
|
nodeInTable.get().record.seqNum == targetSeqNum
|
||||||
|
|
||||||
# Bring target back online, update seqNum in SPR, check if we get the
|
# Bring target back online, update seqNum in SPR, check if we get the
|
||||||
# updated SPR.
|
# updated SPR.
|
||||||
block:
|
block:
|
||||||
targetNode.open()
|
targetNode.open()
|
||||||
# Request the target SPR and manually add it to the routing table.
|
# Request the target SPR and manually add/update it in the routing table.
|
||||||
# Ping for handshake based SPR passing will not work as our previous
|
# Ping for handshake based SPR passing will not work as our previous
|
||||||
# session will still be in the LRU cache.
|
# session will still be in the LRU cache.
|
||||||
let nodes = await mainNode.findNode(targetNode.localNode, @[0'u16])
|
let nodes = await mainNode.findNode(targetNode.localNode, @[0'u16])
|
||||||
check:
|
check:
|
||||||
nodes.isOk()
|
nodes.isOk()
|
||||||
nodes[].len == 1
|
nodes[].len == 1
|
||||||
mainNode.addNode(nodes[][0])
|
# Add/update from findNode result - false because node already exists
|
||||||
|
mainNode.addNode(nodes[][0]) == false
|
||||||
|
|
||||||
targetSeqNum.inc()
|
targetSeqNum.inc()
|
||||||
# need to add something to get the spr sequence number incremented
|
# need to add something to get the spr sequence number incremented
|
||||||
@ -387,9 +391,8 @@ suite "Discovery v5 Tests":
|
|||||||
n.isSome()
|
n.isSome()
|
||||||
n.get().id == targetId
|
n.get().id == targetId
|
||||||
n.get().record.seqNum == targetSeqNum
|
n.get().record.seqNum == targetSeqNum
|
||||||
|
# Add the updated version - node already exsists, just updating
|
||||||
# Add the updated version
|
mainNode.addNode(n.get()) == false
|
||||||
discard mainNode.addNode(n.get())
|
|
||||||
|
|
||||||
# Update seqNum in SPR again, ping lookupNode to be added in routing table,
|
# Update seqNum in SPR again, ping lookupNode to be added in routing table,
|
||||||
# close targetNode, resolve should lookup, check if we get updated SPR.
|
# close targetNode, resolve should lookup, check if we get updated SPR.
|
||||||
@ -403,6 +406,12 @@ suite "Discovery v5 Tests":
|
|||||||
# ping node so that it becomes "seen" and thus will be forwarded on a
|
# ping node so that it becomes "seen" and thus will be forwarded on a
|
||||||
# findNode request
|
# findNode request
|
||||||
check (await lookupNode.ping(targetNode.localNode)).isOk()
|
check (await lookupNode.ping(targetNode.localNode)).isOk()
|
||||||
|
|
||||||
|
# lower reliability so timeout will trigger removal with 0.5 threshold
|
||||||
|
let existingNode = mainNode.getNode(targetId)
|
||||||
|
if existingNode.isSome():
|
||||||
|
existingNode.get().seen = 0.3 # below NoreplyRemoveThreshold (0.5)
|
||||||
|
|
||||||
await targetNode.closeWait()
|
await targetNode.closeWait()
|
||||||
|
|
||||||
check mainNode.addNode(lookupNode.localNode.record)
|
check mainNode.addNode(lookupNode.localNode.record)
|
||||||
@ -412,9 +421,79 @@ suite "Discovery v5 Tests":
|
|||||||
n.get().id == targetId
|
n.get().id == targetId
|
||||||
n.get().record.seqNum == targetSeqNum
|
n.get().record.seqNum == targetSeqNum
|
||||||
|
|
||||||
|
# Demonstrate seen degradation via repeated findNode failures
|
||||||
|
# Node was re-added by lookup with seen=1.0, now repeatedly timeout to degrade
|
||||||
|
block:
|
||||||
|
var attempt = 0
|
||||||
|
while true:
|
||||||
|
attempt.inc()
|
||||||
|
|
||||||
|
let nodeBeforeTimeout = mainNode.getNode(targetId)
|
||||||
|
if nodeBeforeTimeout.isNone():
|
||||||
|
break
|
||||||
|
|
||||||
|
discard await mainNode.findNode(nodeBeforeTimeout.get(), @[0'u16])
|
||||||
|
|
||||||
|
if attempt > 10:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Verify node was eventually removed due to degraded reliability
|
||||||
|
let finalCheck = mainNode.getNode(targetId)
|
||||||
|
check finalCheck.isNone()
|
||||||
|
|
||||||
await mainNode.closeWait()
|
await mainNode.closeWait()
|
||||||
await lookupNode.closeWait()
|
await lookupNode.closeWait()
|
||||||
|
|
||||||
|
test "FindNode timeout preserves high reliability nodes":
|
||||||
|
# Nodes with reliability > NoreplyRemoveThreshold are kept when no replacements available
|
||||||
|
let
|
||||||
|
mainNode = initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20401))
|
||||||
|
targetNode = initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20402))
|
||||||
|
targetId = targetNode.localNode.id
|
||||||
|
|
||||||
|
# add node to routing table via ping
|
||||||
|
check (await mainNode.ping(targetNode.localNode)).isOk()
|
||||||
|
check mainNode.addNode(targetNode.localNode.record)
|
||||||
|
|
||||||
|
var n = mainNode.getNode(targetId)
|
||||||
|
check n.isSome()
|
||||||
|
n.get().seen = 1.8 * discv5_protocol.NoreplyRemoveThreshold
|
||||||
|
|
||||||
|
# close node to trigger timeout
|
||||||
|
await targetNode.closeWait()
|
||||||
|
|
||||||
|
discard await mainNode.findNode(n.get(), @[0'u16])
|
||||||
|
|
||||||
|
# verify node still in routing table
|
||||||
|
n = mainNode.getNode(targetId)
|
||||||
|
check n.isSome()
|
||||||
|
|
||||||
|
await mainNode.closeWait()
|
||||||
|
|
||||||
|
test "FindNode timeout removes low reliability nodes":
|
||||||
|
# Nodes with reliability <= NoreplyRemoveThreshold are removed on timeout
|
||||||
|
let
|
||||||
|
mainNode = initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20403))
|
||||||
|
targetNode = initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20404))
|
||||||
|
targetId = targetNode.localNode.id
|
||||||
|
|
||||||
|
check (await mainNode.ping(targetNode.localNode)).isOk()
|
||||||
|
check mainNode.addNode(targetNode.localNode.record)
|
||||||
|
|
||||||
|
var n = mainNode.getNode(targetId)
|
||||||
|
check n.isSome()
|
||||||
|
n.get().seen = 0.01 * discv5_protocol.NoreplyRemoveThreshold
|
||||||
|
|
||||||
|
await targetNode.closeWait()
|
||||||
|
|
||||||
|
discard await mainNode.findNode(n.get(), @[0'u16])
|
||||||
|
|
||||||
|
# verify node removed from routing table
|
||||||
|
n = mainNode.getNode(targetId)
|
||||||
|
check n.isNone()
|
||||||
|
|
||||||
|
await mainNode.closeWait()
|
||||||
|
|
||||||
test "Random nodes, also with filter":
|
test "Random nodes, also with filter":
|
||||||
let
|
let
|
||||||
lookupNode = initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20301))
|
lookupNode = initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20301))
|
||||||
@ -429,11 +508,18 @@ suite "Discovery v5 Tests":
|
|||||||
|
|
||||||
let discovered = lookupNode.randomNodes(10)
|
let discovered = lookupNode.randomNodes(10)
|
||||||
check discovered.len == 3
|
check discovered.len == 3
|
||||||
let discoveredFiltered = lookupNode.randomNodes(10,
|
let discoveredFiltered = lookupNode.randomNodes(
|
||||||
proc(n: Node) : bool = n.address.get.port == Port(20302))
|
10,
|
||||||
check discoveredFiltered.len == 1 and discoveredFiltered.contains(targetNode.localNode)
|
proc(n: Node): bool =
|
||||||
let discoveredEmpty = lookupNode.randomNodes(10,
|
n.address.get.port == Port(20302),
|
||||||
proc(n: Node) : bool = n.address.get.port == Port(20305))
|
)
|
||||||
|
check discoveredFiltered.len == 1 and
|
||||||
|
discoveredFiltered.contains(targetNode.localNode)
|
||||||
|
let discoveredEmpty = lookupNode.randomNodes(
|
||||||
|
10,
|
||||||
|
proc(n: Node): bool =
|
||||||
|
n.address.get.port == Port(20305),
|
||||||
|
)
|
||||||
check discoveredEmpty.len == 0
|
check discoveredEmpty.len == 0
|
||||||
|
|
||||||
await lookupNode.closeWait()
|
await lookupNode.closeWait()
|
||||||
@ -441,22 +527,41 @@ suite "Discovery v5 Tests":
|
|||||||
await otherNode.closeWait()
|
await otherNode.closeWait()
|
||||||
await anotherNode.closeWait()
|
await anotherNode.closeWait()
|
||||||
|
|
||||||
|
|
||||||
test "New protocol with spr":
|
test "New protocol with spr":
|
||||||
let
|
let
|
||||||
privKey = PrivateKey.example(rng)
|
privKey = PrivateKey.example(rng)
|
||||||
ip = some(parseIpAddress("127.0.0.1"))
|
ip = some(parseIpAddress("127.0.0.1"))
|
||||||
port = Port(20301)
|
port = Port(20301)
|
||||||
node = newProtocol(privKey, ip, some(port), some(port), bindPort = port,
|
node =
|
||||||
rng = rng)
|
newProtocol(privKey, ip, some(port), some(port), bindPort = port, rng = rng)
|
||||||
noUpdatesNode = newProtocol(privKey, ip, some(port), some(port),
|
noUpdatesNode = newProtocol(
|
||||||
bindPort = port, rng = rng, previousRecord = some(node.getRecord()))
|
privKey,
|
||||||
updatesNode = newProtocol(privKey, ip, some(port), some(Port(20302)),
|
ip,
|
||||||
bindPort = port, rng = rng,
|
some(port),
|
||||||
previousRecord = some(noUpdatesNode.getRecord()))
|
some(port),
|
||||||
moreUpdatesNode = newProtocol(privKey, ip, some(port), some(port),
|
bindPort = port,
|
||||||
bindPort = port, rng = rng, localEnrFields = {"addfield": @[byte 0]},
|
rng = rng,
|
||||||
previousRecord = some(updatesNode.getRecord()))
|
previousRecord = some(node.getRecord()),
|
||||||
|
)
|
||||||
|
updatesNode = newProtocol(
|
||||||
|
privKey,
|
||||||
|
ip,
|
||||||
|
some(port),
|
||||||
|
some(Port(20302)),
|
||||||
|
bindPort = port,
|
||||||
|
rng = rng,
|
||||||
|
previousRecord = some(noUpdatesNode.getRecord()),
|
||||||
|
)
|
||||||
|
moreUpdatesNode = newProtocol(
|
||||||
|
privKey,
|
||||||
|
ip,
|
||||||
|
some(port),
|
||||||
|
some(port),
|
||||||
|
bindPort = port,
|
||||||
|
rng = rng,
|
||||||
|
localEnrFields = {"addfield": @[byte 0]},
|
||||||
|
previousRecord = some(updatesNode.getRecord()),
|
||||||
|
)
|
||||||
check:
|
check:
|
||||||
node.getRecord().seqNum == 1
|
node.getRecord().seqNum == 1
|
||||||
noUpdatesNode.getRecord().seqNum == 1
|
noUpdatesNode.getRecord().seqNum == 1
|
||||||
@ -465,16 +570,20 @@ suite "Discovery v5 Tests":
|
|||||||
|
|
||||||
# Defect (for now?) on incorrect key use
|
# Defect (for now?) on incorrect key use
|
||||||
expect ResultDefect:
|
expect ResultDefect:
|
||||||
let incorrectKeyUpdates = newProtocol(PrivateKey.example(rng),
|
let incorrectKeyUpdates = newProtocol(
|
||||||
ip, some(port), some(port), bindPort = port, rng = rng,
|
PrivateKey.example(rng),
|
||||||
previousRecord = some(updatesNode.getRecord()))
|
ip,
|
||||||
|
some(port),
|
||||||
|
some(port),
|
||||||
|
bindPort = port,
|
||||||
|
rng = rng,
|
||||||
|
previousRecord = some(updatesNode.getRecord()),
|
||||||
|
)
|
||||||
|
|
||||||
test "Update node record with revalidate":
|
test "Update node record with revalidate":
|
||||||
let
|
let
|
||||||
mainNode =
|
mainNode = initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20301))
|
||||||
initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20301))
|
testNode = initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20302))
|
||||||
testNode =
|
|
||||||
initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20302))
|
|
||||||
testNodeId = testNode.localNode.id
|
testNodeId = testNode.localNode.id
|
||||||
|
|
||||||
check:
|
check:
|
||||||
@ -505,14 +614,13 @@ suite "Discovery v5 Tests":
|
|||||||
|
|
||||||
test "Update node record with handshake":
|
test "Update node record with handshake":
|
||||||
let
|
let
|
||||||
mainNode =
|
mainNode = initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20301))
|
||||||
initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20301))
|
testNode = initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20302))
|
||||||
testNode =
|
|
||||||
initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20302))
|
|
||||||
testNodeId = testNode.localNode.id
|
testNodeId = testNode.localNode.id
|
||||||
|
|
||||||
# Add the node (from the record, so new node!) so no handshake is done yet.
|
# Add the node (from the record, so new node!) so no handshake is done yet.
|
||||||
check: mainNode.addNode(testNode.localNode.record)
|
check:
|
||||||
|
mainNode.addNode(testNode.localNode.record)
|
||||||
|
|
||||||
check:
|
check:
|
||||||
testNode.updateRecord().isOk()
|
testNode.updateRecord().isOk()
|
||||||
@ -539,9 +647,13 @@ suite "Discovery v5 Tests":
|
|||||||
test "Verify records of nodes message":
|
test "Verify records of nodes message":
|
||||||
let
|
let
|
||||||
port = Port(9000)
|
port = Port(9000)
|
||||||
fromNoderecord = SignedPeerRecord.init(1, PrivateKey.example(rng),
|
fromNoderecord = SignedPeerRecord.init(
|
||||||
|
1,
|
||||||
|
PrivateKey.example(rng),
|
||||||
some(parseIpAddress("11.12.13.14")),
|
some(parseIpAddress("11.12.13.14")),
|
||||||
some(port), some(port))[]
|
some(port),
|
||||||
|
some(port),
|
||||||
|
)[]
|
||||||
fromNode = newNode(fromNoderecord)[]
|
fromNode = newNode(fromNoderecord)[]
|
||||||
privKey = PrivateKey.example(rng)
|
privKey = PrivateKey.example(rng)
|
||||||
pubKey = privKey.getPublicKey.expect("Valid private key for public key")
|
pubKey = privKey.getPublicKey.expect("Valid private key for public key")
|
||||||
@ -550,10 +662,9 @@ suite "Discovery v5 Tests":
|
|||||||
limit = 16
|
limit = 16
|
||||||
|
|
||||||
block: # Duplicates
|
block: # Duplicates
|
||||||
let
|
let record = SignedPeerRecord.init(
|
||||||
record = SignedPeerRecord.init(
|
1, privKey, some(parseIpAddress("12.13.14.15")), some(port), some(port)
|
||||||
1, privKey, some(parseIpAddress("12.13.14.15")),
|
)[]
|
||||||
some(port), some(port))[]
|
|
||||||
|
|
||||||
# Exact duplicates
|
# Exact duplicates
|
||||||
var records = @[record, record]
|
var records = @[record, record]
|
||||||
@ -562,16 +673,16 @@ suite "Discovery v5 Tests":
|
|||||||
|
|
||||||
# Node id duplicates
|
# Node id duplicates
|
||||||
let recordSameId = SignedPeerRecord.init(
|
let recordSameId = SignedPeerRecord.init(
|
||||||
1, privKey, some(parseIpAddress("212.13.14.15")),
|
1, privKey, some(parseIpAddress("212.13.14.15")), some(port), some(port)
|
||||||
some(port), some(port))[]
|
)[]
|
||||||
records.add(recordSameId)
|
records.add(recordSameId)
|
||||||
nodes = verifyNodesRecords(records, fromNode, limit, targetDistance)
|
nodes = verifyNodesRecords(records, fromNode, limit, targetDistance)
|
||||||
check nodes.len == 1
|
check nodes.len == 1
|
||||||
|
|
||||||
block: # No address
|
block: # No address
|
||||||
let
|
let
|
||||||
recordNoAddress = SignedPeerRecord.init(
|
recordNoAddress =
|
||||||
1, privKey, none(IpAddress), some(port), some(port))[]
|
SignedPeerRecord.init(1, privKey, none(IpAddress), some(port), some(port))[]
|
||||||
records = [recordNoAddress]
|
records = [recordNoAddress]
|
||||||
test = verifyNodesRecords(records, fromNode, limit, targetDistance)
|
test = verifyNodesRecords(records, fromNode, limit, targetDistance)
|
||||||
check test.len == 0
|
check test.len == 0
|
||||||
@ -579,8 +690,8 @@ suite "Discovery v5 Tests":
|
|||||||
block: # Invalid address - site local
|
block: # Invalid address - site local
|
||||||
let
|
let
|
||||||
recordInvalidAddress = SignedPeerRecord.init(
|
recordInvalidAddress = SignedPeerRecord.init(
|
||||||
1, privKey, some(parseIpAddress("10.1.2.3")),
|
1, privKey, some(parseIpAddress("10.1.2.3")), some(port), some(port)
|
||||||
some(port), some(port))[]
|
)[]
|
||||||
records = [recordInvalidAddress]
|
records = [recordInvalidAddress]
|
||||||
test = verifyNodesRecords(records, fromNode, limit, targetDistance)
|
test = verifyNodesRecords(records, fromNode, limit, targetDistance)
|
||||||
check test.len == 0
|
check test.len == 0
|
||||||
@ -588,8 +699,8 @@ suite "Discovery v5 Tests":
|
|||||||
block: # Invalid address - loopback
|
block: # Invalid address - loopback
|
||||||
let
|
let
|
||||||
recordInvalidAddress = SignedPeerRecord.init(
|
recordInvalidAddress = SignedPeerRecord.init(
|
||||||
1, privKey, some(parseIpAddress("127.0.0.1")),
|
1, privKey, some(parseIpAddress("127.0.0.1")), some(port), some(port)
|
||||||
some(port), some(port))[]
|
)[]
|
||||||
records = [recordInvalidAddress]
|
records = [recordInvalidAddress]
|
||||||
test = verifyNodesRecords(records, fromNode, limit, targetDistance)
|
test = verifyNodesRecords(records, fromNode, limit, targetDistance)
|
||||||
check test.len == 0
|
check test.len == 0
|
||||||
@ -597,8 +708,8 @@ suite "Discovery v5 Tests":
|
|||||||
block: # Invalid distance
|
block: # Invalid distance
|
||||||
let
|
let
|
||||||
recordInvalidDistance = SignedPeerRecord.init(
|
recordInvalidDistance = SignedPeerRecord.init(
|
||||||
1, privKey, some(parseIpAddress("12.13.14.15")),
|
1, privKey, some(parseIpAddress("12.13.14.15")), some(port), some(port)
|
||||||
some(port), some(port))[]
|
)[]
|
||||||
records = [recordInvalidDistance]
|
records = [recordInvalidDistance]
|
||||||
test = verifyNodesRecords(records, fromNode, limit, @[0'u16])
|
test = verifyNodesRecords(records, fromNode, limit, @[0'u16])
|
||||||
check test.len == 0
|
check test.len == 0
|
||||||
@ -606,8 +717,8 @@ suite "Discovery v5 Tests":
|
|||||||
block: # Invalid distance but distance validation is disabled
|
block: # Invalid distance but distance validation is disabled
|
||||||
let
|
let
|
||||||
recordInvalidDistance = SignedPeerRecord.init(
|
recordInvalidDistance = SignedPeerRecord.init(
|
||||||
1, privKey, some(parseIpAddress("12.13.14.15")),
|
1, privKey, some(parseIpAddress("12.13.14.15")), some(port), some(port)
|
||||||
some(port), some(port))[]
|
)[]
|
||||||
records = [recordInvalidDistance]
|
records = [recordInvalidDistance]
|
||||||
test = verifyNodesRecords(records, fromNode, limit)
|
test = verifyNodesRecords(records, fromNode, limit)
|
||||||
check test.len == 1
|
check test.len == 1
|
||||||
@ -623,8 +734,8 @@ suite "Discovery v5 Tests":
|
|||||||
|
|
||||||
test "Handshake cleanup: different ids":
|
test "Handshake cleanup: different ids":
|
||||||
# Node to test the handshakes on.
|
# Node to test the handshakes on.
|
||||||
let receiveNode = initDiscoveryNode(
|
let receiveNode =
|
||||||
rng, PrivateKey.example(rng), localAddress(20302))
|
initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20302))
|
||||||
|
|
||||||
# Create random packets with same ip but different node ids
|
# Create random packets with same ip but different node ids
|
||||||
# and "receive" them on receiveNode
|
# and "receive" them on receiveNode
|
||||||
@ -632,14 +743,22 @@ suite "Discovery v5 Tests":
|
|||||||
for i in 0 ..< 5:
|
for i in 0 ..< 5:
|
||||||
let
|
let
|
||||||
privKey = PrivateKey.example(rng)
|
privKey = PrivateKey.example(rng)
|
||||||
enrRec = SignedPeerRecord.init(1, privKey,
|
enrRec = SignedPeerRecord
|
||||||
some(parseIpAddress("127.0.0.1")), some(Port(9000)),
|
.init(
|
||||||
some(Port(9000))).expect("Properly intialized private key")
|
1,
|
||||||
|
privKey,
|
||||||
|
some(parseIpAddress("127.0.0.1")),
|
||||||
|
some(Port(9000)),
|
||||||
|
some(Port(9000)),
|
||||||
|
)
|
||||||
|
.expect("Properly intialized private key")
|
||||||
sendNode = newNode(enrRec).expect("Properly initialized record")
|
sendNode = newNode(enrRec).expect("Properly initialized record")
|
||||||
var codec = Codec(localNode: sendNode, privKey: privKey, sessions: Sessions.init(5))
|
var codec =
|
||||||
|
Codec(localNode: sendNode, privKey: privKey, sessions: Sessions.init(5))
|
||||||
|
|
||||||
let (packet, _, _) = encodeMessagePacket(rng[], codec,
|
let (packet, _, _) = encodeMessagePacket(
|
||||||
receiveNode.localNode.id, receiveNode.localNode.address.get(), @[])
|
rng[], codec, receiveNode.localNode.id, receiveNode.localNode.address.get(), @[]
|
||||||
|
)
|
||||||
receiveNode.transport.receive(a, packet)
|
receiveNode.transport.receive(a, packet)
|
||||||
|
|
||||||
# Checking different nodeIds but same address
|
# Checking different nodeIds but same address
|
||||||
@ -654,22 +773,29 @@ suite "Discovery v5 Tests":
|
|||||||
|
|
||||||
test "Handshake cleanup: different ips":
|
test "Handshake cleanup: different ips":
|
||||||
# Node to test the handshakes on.
|
# Node to test the handshakes on.
|
||||||
let receiveNode = initDiscoveryNode(
|
let receiveNode =
|
||||||
rng, PrivateKey.example(rng), localAddress(20302))
|
initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20302))
|
||||||
|
|
||||||
# Create random packets with same node ids but different ips
|
# Create random packets with same node ids but different ips
|
||||||
# and "receive" them on receiveNode
|
# and "receive" them on receiveNode
|
||||||
let
|
let
|
||||||
privKey = PrivateKey.example(rng)
|
privKey = PrivateKey.example(rng)
|
||||||
enrRec = SignedPeerRecord.init(1, privKey,
|
enrRec = SignedPeerRecord
|
||||||
some(parseIpAddress("127.0.0.1")), some(Port(9000)),
|
.init(
|
||||||
some(Port(9000))).expect("Properly intialized private key")
|
1,
|
||||||
|
privKey,
|
||||||
|
some(parseIpAddress("127.0.0.1")),
|
||||||
|
some(Port(9000)),
|
||||||
|
some(Port(9000)),
|
||||||
|
)
|
||||||
|
.expect("Properly intialized private key")
|
||||||
sendNode = newNode(enrRec).expect("Properly initialized record")
|
sendNode = newNode(enrRec).expect("Properly initialized record")
|
||||||
var codec = Codec(localNode: sendNode, privKey: privKey, sessions: Sessions.init(5))
|
var codec = Codec(localNode: sendNode, privKey: privKey, sessions: Sessions.init(5))
|
||||||
for i in 0 ..< 5:
|
for i in 0 ..< 5:
|
||||||
let a = localAddress(20303 + i)
|
let a = localAddress(20303 + i)
|
||||||
let (packet, _, _) = encodeMessagePacket(rng[], codec,
|
let (packet, _, _) = encodeMessagePacket(
|
||||||
receiveNode.localNode.id, receiveNode.localNode.address.get(), @[])
|
rng[], codec, receiveNode.localNode.id, receiveNode.localNode.address.get(), @[]
|
||||||
|
)
|
||||||
receiveNode.transport.receive(a, packet)
|
receiveNode.transport.receive(a, packet)
|
||||||
|
|
||||||
# Checking different nodeIds but same address
|
# Checking different nodeIds but same address
|
||||||
@ -684,24 +810,31 @@ suite "Discovery v5 Tests":
|
|||||||
|
|
||||||
test "Handshake duplicates":
|
test "Handshake duplicates":
|
||||||
# Node to test the handshakes on.
|
# Node to test the handshakes on.
|
||||||
let receiveNode = initDiscoveryNode(
|
let receiveNode =
|
||||||
rng, PrivateKey.example(rng), localAddress(20302))
|
initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20302))
|
||||||
|
|
||||||
# Create random packets with same node ids and same ips
|
# Create random packets with same node ids and same ips
|
||||||
# and "receive" them on receiveNode
|
# and "receive" them on receiveNode
|
||||||
let
|
let
|
||||||
a = localAddress(20303)
|
a = localAddress(20303)
|
||||||
privKey = PrivateKey.example(rng)
|
privKey = PrivateKey.example(rng)
|
||||||
enrRec = SignedPeerRecord.init(1, privKey,
|
enrRec = SignedPeerRecord
|
||||||
some(parseIpAddress("127.0.0.1")), some(Port(9000)),
|
.init(
|
||||||
some(Port(9000))).expect("Properly intialized private key")
|
1,
|
||||||
|
privKey,
|
||||||
|
some(parseIpAddress("127.0.0.1")),
|
||||||
|
some(Port(9000)),
|
||||||
|
some(Port(9000)),
|
||||||
|
)
|
||||||
|
.expect("Properly intialized private key")
|
||||||
sendNode = newNode(enrRec).expect("Properly initialized record")
|
sendNode = newNode(enrRec).expect("Properly initialized record")
|
||||||
var codec = Codec(localNode: sendNode, privKey: privKey, sessions: Sessions.init(5))
|
var codec = Codec(localNode: sendNode, privKey: privKey, sessions: Sessions.init(5))
|
||||||
|
|
||||||
var firstRequestNonce: AESGCMNonce
|
var firstRequestNonce: AESGCMNonce
|
||||||
for i in 0 ..< 5:
|
for i in 0 ..< 5:
|
||||||
let (packet, requestNonce, _) = encodeMessagePacket(rng[], codec,
|
let (packet, requestNonce, _) = encodeMessagePacket(
|
||||||
receiveNode.localNode.id, receiveNode.localNode.address.get(), @[])
|
rng[], codec, receiveNode.localNode.id, receiveNode.localNode.address.get(), @[]
|
||||||
|
)
|
||||||
receiveNode.transport.receive(a, packet)
|
receiveNode.transport.receive(a, packet)
|
||||||
if i == 0:
|
if i == 0:
|
||||||
firstRequestNonce = requestNonce
|
firstRequestNonce = requestNonce
|
||||||
@ -717,12 +850,10 @@ suite "Discovery v5 Tests":
|
|||||||
|
|
||||||
test "Talkreq no protocol":
|
test "Talkreq no protocol":
|
||||||
let
|
let
|
||||||
node1 = initDiscoveryNode(
|
node1 = initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20302))
|
||||||
rng, PrivateKey.example(rng), localAddress(20302))
|
node2 = initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20303))
|
||||||
node2 = initDiscoveryNode(
|
talkresp =
|
||||||
rng, PrivateKey.example(rng), localAddress(20303))
|
await discv5_protocol.talkReq(node1, node2.localNode, @[byte 0x01], @[])
|
||||||
talkresp = await discv5_protocol.talkReq(node1, node2.localNode,
|
|
||||||
@[byte 0x01], @[])
|
|
||||||
|
|
||||||
check:
|
check:
|
||||||
talkresp.isOk()
|
talkresp.isOk()
|
||||||
@ -733,21 +864,24 @@ suite "Discovery v5 Tests":
|
|||||||
|
|
||||||
test "Talkreq echo protocol":
|
test "Talkreq echo protocol":
|
||||||
let
|
let
|
||||||
node1 = initDiscoveryNode(
|
node1 = initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20302))
|
||||||
rng, PrivateKey.example(rng), localAddress(20302))
|
node2 = initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20303))
|
||||||
node2 = initDiscoveryNode(
|
|
||||||
rng, PrivateKey.example(rng), localAddress(20303))
|
|
||||||
talkProtocol = "echo".toBytes()
|
talkProtocol = "echo".toBytes()
|
||||||
|
|
||||||
proc handler(protocol: TalkProtocol, request: seq[byte], fromId: NodeId, fromUdpAddress: Address): seq[byte]
|
proc handler(
|
||||||
{.gcsafe, raises: [Defect].} =
|
protocol: TalkProtocol,
|
||||||
|
request: seq[byte],
|
||||||
|
fromId: NodeId,
|
||||||
|
fromUdpAddress: Address,
|
||||||
|
): seq[byte] {.gcsafe, raises: [Defect].} =
|
||||||
request
|
request
|
||||||
|
|
||||||
let echoProtocol = TalkProtocol(protocolHandler: handler)
|
let echoProtocol = TalkProtocol(protocolHandler: handler)
|
||||||
|
|
||||||
check node2.registerTalkProtocol(talkProtocol, echoProtocol).isOk()
|
check node2.registerTalkProtocol(talkProtocol, echoProtocol).isOk()
|
||||||
let talkresp = await discv5_protocol.talkReq(node1, node2.localNode,
|
let talkresp = await discv5_protocol.talkReq(
|
||||||
talkProtocol, "hello".toBytes())
|
node1, node2.localNode, talkProtocol, "hello".toBytes()
|
||||||
|
)
|
||||||
|
|
||||||
check:
|
check:
|
||||||
talkresp.isOk()
|
talkresp.isOk()
|
||||||
@ -758,14 +892,16 @@ suite "Discovery v5 Tests":
|
|||||||
|
|
||||||
test "Talkreq register protocols":
|
test "Talkreq register protocols":
|
||||||
let
|
let
|
||||||
node1 = initDiscoveryNode(
|
node1 = initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20302))
|
||||||
rng, PrivateKey.example(rng), localAddress(20302))
|
node2 = initDiscoveryNode(rng, PrivateKey.example(rng), localAddress(20303))
|
||||||
node2 = initDiscoveryNode(
|
|
||||||
rng, PrivateKey.example(rng), localAddress(20303))
|
|
||||||
talkProtocol = "echo".toBytes()
|
talkProtocol = "echo".toBytes()
|
||||||
|
|
||||||
proc handler(protocol: TalkProtocol, request: seq[byte], fromId: NodeId, fromUdpAddress: Address): seq[byte]
|
proc handler(
|
||||||
{.gcsafe, raises: [Defect].} =
|
protocol: TalkProtocol,
|
||||||
|
request: seq[byte],
|
||||||
|
fromId: NodeId,
|
||||||
|
fromUdpAddress: Address,
|
||||||
|
): seq[byte] {.gcsafe, raises: [Defect].} =
|
||||||
request
|
request
|
||||||
|
|
||||||
let echoProtocol = TalkProtocol(protocolHandler: handler)
|
let echoProtocol = TalkProtocol(protocolHandler: handler)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user