Skip to content

Commit 69d9524

Browse files
authored
chore: saving peers enr capabilities (#3127)
1 parent dbf0222 commit 69d9524

File tree

16 files changed

+209
-50
lines changed

16 files changed

+209
-50
lines changed

tests/test_waku_enr.nim

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{.used.}
22

33
import std/[options, sequtils], stew/results, testutils/unittests
4-
import waku/waku_core, waku/waku_enr, ./testlib/wakucore
4+
import waku/waku_core, waku/waku_enr, ./testlib/wakucore, waku/waku_core/codecs
55

66
suite "Waku ENR - Capabilities bitfield":
77
test "check capabilities support":
@@ -97,6 +97,28 @@ suite "Waku ENR - Capabilities bitfield":
9797
bitfield.supportsCapability(Capabilities.Lightpush) == false
9898
bitfield.toCapabilities() == @[Capabilities.Relay, Capabilities.Store]
9999

100+
test "get capabilities codecs from record":
101+
## Given
102+
let
103+
enrSeqNum = 1u64
104+
enrPrivKey = generatesecp256k1key()
105+
106+
## When
107+
var builder = EnrBuilder.init(enrPrivKey, seqNum = enrSeqNum)
108+
builder.withWakuCapabilities(Capabilities.Relay, Capabilities.Store)
109+
110+
let recordRes = builder.build()
111+
112+
## Then
113+
assert recordRes.isOk(), $recordRes.error
114+
let record = recordRes.tryGet()
115+
116+
let codecs = record.getCapabilitiesCodecs()
117+
check:
118+
codecs.len == 2
119+
codecs.contains(WakuRelayCodec)
120+
codecs.contains(WakuStoreCodec)
121+
100122
test "check capabilities on a non-waku node record":
101123
## Given
102124
# non waku enr, i.e. Ethereum one

tests/waku_core/test_peers.nim

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
{.used.}
22

33
import
4-
stew/results, testutils/unittests, libp2p/multiaddress, libp2p/peerid, libp2p/errors
5-
import waku/waku_core
4+
stew/results,
5+
testutils/unittests,
6+
libp2p/multiaddress,
7+
libp2p/peerid,
8+
libp2p/errors,
9+
confutils/toml/std/net
10+
import waku/[waku_core, waku_core/codecs, waku_enr], ../testlib/wakucore
611

712
suite "Waku Core - Peers":
813
test "Peer info parses correctly":
@@ -141,3 +146,34 @@ suite "Waku Core - Peers":
141146
## Then
142147
check:
143148
parsePeerInfo(address).isErr()
149+
150+
test "ENRs capabilities are filled when creating RemotePeerInfo":
151+
let
152+
enrSeqNum = 1u64
153+
enrPrivKey = generatesecp256k1key()
154+
155+
## When
156+
var builder = EnrBuilder.init(enrPrivKey, seqNum = enrSeqNum)
157+
builder.withIpAddressAndPorts(
158+
ipAddr = some(parseIpAddress("127.0.0.1")),
159+
tcpPort = some(Port(0)),
160+
udpPort = some(Port(0)),
161+
)
162+
builder.withWakuCapabilities(Capabilities.Relay, Capabilities.Store)
163+
164+
let recordRes = builder.build()
165+
166+
## Then
167+
assert recordRes.isOk(), $recordRes.error
168+
let record = recordRes.tryGet()
169+
170+
let remotePeerInfoRes = record.toRemotePeerInfo()
171+
assert remotePeerInfoRes.isOk(),
172+
"failed creating RemotePeerInfo: " & $remotePeerInfoRes.error()
173+
174+
let remotePeerInfo = remotePeerInfoRes.get()
175+
176+
check:
177+
remotePeerInfo.protocols.len == 2
178+
remotePeerInfo.protocols.contains(WakuRelayCodec)
179+
remotePeerInfo.protocols.contains(WakuStoreCodec)

tests/waku_discv5/test_waku_discv5.nim

Lines changed: 73 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,26 @@ import
1212

1313
import
1414
waku/[waku_core/topics, waku_enr, discovery/waku_discv5, common/enr],
15-
../testlib/[wakucore, testasync, assertions, futures],
15+
../testlib/[wakucore, testasync, assertions, futures, wakunode],
1616
../waku_enr/utils,
1717
./utils
1818

1919
import eth/p2p/discoveryv5/enr as ethEnr
2020

21-
procSuite "Waku Discovery v5":
21+
include waku/factory/waku
22+
23+
suite "Waku Discovery v5":
24+
const validEnr =
25+
"enr:-K64QGAvsATunmvMT5c3LFjKS0tG39zlQ1195Z2pWu6RoB5fWP3EXz9QPlRXN" &
26+
"wOtDoRLgm4bATUB53AC8uml-ZtUE_kBgmlkgnY0gmlwhApkZgOKbXVsdGlhZGRyc4" &
27+
"CCcnOTAAAIAAAAAQACAAMABAAFAAYAB4lzZWNwMjU2azGhAwG-CMmXpAPj84f6dCt" &
28+
"MZ6xVYOa6bdmgAiKYG6LKGQlbg3RjcILqYIV3YWt1MgE"
29+
2230
let
2331
rng = eth_keys.newRng()
2432
pk1 = eth_keys.PrivateKey.random(rng[])
2533
pk2 = eth_keys.PrivateKey.random(rng[])
2634

27-
enrNoCapabilities =
28-
initRecord(1, pk1, {"rs": @[0.byte, 0.byte, 1.byte, 0.byte, 0.byte]}).value()
29-
enrRelay = initRecord(
30-
1, pk2, {"waku2": @[1.byte], "rs": @[0.byte, 1.byte, 1.byte, 0.byte, 1.byte]}
31-
)
32-
.value()
33-
enrNoShardingInfo = initRecord(1, pk1, {"waku2": @[1.byte]}).value()
34-
3535
suite "shardingPredicate":
3636
var
3737
recordCluster21 {.threadvar.}: Record
@@ -120,6 +120,14 @@ procSuite "Waku Discovery v5":
120120

121121
asyncTest "filter peer per bootnode":
122122
let
123+
enrRelay = initRecord(
124+
1,
125+
pk2,
126+
{"waku2": @[1.byte], "rs": @[0.byte, 1.byte, 1.byte, 0.byte, 1.byte]},
127+
)
128+
.value()
129+
enrNoCapabilities =
130+
initRecord(1, pk1, {"rs": @[0.byte, 0.byte, 1.byte, 0.byte, 0.byte]}).value()
123131
predicateNoCapabilities =
124132
shardingPredicate(enrNoCapabilities, @[enrNoCapabilities]).get()
125133
predicateNoCapabilitiesWithBoth =
@@ -151,8 +159,10 @@ procSuite "Waku Discovery v5":
151159
predicateRecord.isNone()
152160

153161
asyncTest "no relay sharding info":
154-
let predicateNoShardingInfo =
155-
shardingPredicate(enrNoShardingInfo, @[enrNoShardingInfo])
162+
let
163+
enrNoShardingInfo = initRecord(1, pk1, {"waku2": @[1.byte]}).value()
164+
predicateNoShardingInfo =
165+
shardingPredicate(enrNoShardingInfo, @[enrNoShardingInfo])
156166

157167
check:
158168
predicateNoShardingInfo.isNone()
@@ -166,7 +176,7 @@ procSuite "Waku Discovery v5":
166176
indices: seq[uint64] = @[],
167177
recordFlags: Option[CapabilitiesBitfield] = none(CapabilitiesBitfield),
168178
bootstrapRecords: seq[waku_enr.Record] = @[],
169-
): (WakuDiscoveryV5, Record) =
179+
): (WakuDiscoveryV5, Record) {.raises: [ValueError, LPError].} =
170180
let
171181
privKey = generateSecp256k1Key()
172182
record = newTestEnrRecord(
@@ -188,17 +198,6 @@ procSuite "Waku Discovery v5":
188198

189199
(node, record)
190200

191-
let filterForStore: WakuDiscv5Predicate = proc(record: waku_enr.Record): bool =
192-
let typedRecord = record.toTyped()
193-
if typedRecord.isErr():
194-
return false
195-
196-
let capabilities = typedRecord.value.waku2
197-
if capabilities.isNone():
198-
return false
199-
200-
return capabilities.get().supportsCapability(Capabilities.Store)
201-
202201
asyncTest "find random peers without predicate":
203202
# Given 3 nodes
204203
let
@@ -234,6 +233,17 @@ procSuite "Waku Discovery v5":
234233
await allFutures(node1.stop(), node2.stop(), node3.stop())
235234

236235
asyncTest "find random peers with parameter predicate":
236+
let filterForStore: WakuDiscv5Predicate = proc(record: waku_enr.Record): bool =
237+
let typedRecord = record.toTyped()
238+
if typedRecord.isErr():
239+
return false
240+
241+
let capabilities = typedRecord.value.waku2
242+
if capabilities.isNone():
243+
return false
244+
245+
return capabilities.get().supportsCapability(Capabilities.Store)
246+
237247
# Given 4 nodes
238248
let
239249
(node3, record3) = buildNode(
@@ -346,11 +356,6 @@ procSuite "Waku Discovery v5":
346356
await allFutures(node1.stop(), node2.stop(), node3.stop(), node4.stop())
347357

348358
suite "addBoostrapNode":
349-
let validEnr =
350-
"enr:-I-4QG3mX250ArniAs2DLpW-QHOLKSD5x_Ibp8AYcQZbz1HhHFJtl2dNDGcha" &
351-
"U5ugLbDKRgtTDZH8NsxXlTXDpYAgzgBgmlkgnY0gnJzjwAVBgABAAIABQAHAAkAC4" &
352-
"lzZWNwMjU2azGhA4_KwN0NRRmmfQ-B9B2h2PZjoJvBnaIOi6sR_b2UTQBBhXdha3U" & "yAQ"
353-
354359
asyncTest "address is valid":
355360
# Given an empty list of enrs
356361
var enrs: seq[Record] = @[]
@@ -400,3 +405,42 @@ procSuite "Waku Discovery v5":
400405
# Then the enr is not added to the list
401406
check:
402407
enrs.len == 0
408+
409+
suite "waku discv5 initialization":
410+
asyncTest "Discv5 bootstrap nodes should be added to the peer store":
411+
var conf = defaultTestWakuNodeConf()
412+
413+
conf.discv5BootstrapNodes = @[validEnr]
414+
415+
let waku = Waku.init(conf).valueOr:
416+
raiseAssert error
417+
418+
discard setupDiscoveryV5(
419+
waku.node.enr, waku.node.peerManager, waku.node.topicSubscriptionQueue,
420+
waku.conf, waku.dynamicBootstrapNodes, waku.rng, waku.key,
421+
)
422+
423+
check:
424+
waku.node.peerManager.wakuPeerStore.peers().anyIt(
425+
it.enr.isSome() and it.enr.get().toUri() == validEnr
426+
)
427+
428+
asyncTest "Invalid discv5 bootstrap node ENRs are ignored":
429+
var conf = defaultTestWakuNodeConf()
430+
431+
let invalidEnr = "invalid-enr"
432+
433+
conf.discv5BootstrapNodes = @[invalidEnr]
434+
435+
let waku = Waku.init(conf).valueOr:
436+
raiseAssert error
437+
438+
discard setupDiscoveryV5(
439+
waku.node.enr, waku.node.peerManager, waku.node.topicSubscriptionQueue,
440+
waku.conf, waku.dynamicBootstrapNodes, waku.rng, waku.key,
441+
)
442+
443+
check:
444+
not waku.node.peerManager.wakuPeerStore.peers().anyIt(
445+
it.enr.isSome() and it.enr.get().toUri() == invalidEnr
446+
)

waku/discovery/waku_discv5.nim

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,14 @@ proc setupDiscoveryV5*(
381381
for enrUri in conf.discv5BootstrapNodes:
382382
addBootstrapNode(enrUri, discv5BootstrapEnrs)
383383

384+
for enr in discv5BootstrapEnrs:
385+
let peerInfoRes = enr.toRemotePeerInfo()
386+
if peerInfoRes.isOk():
387+
nodePeerManager.addPeer(peerInfoRes.get(), PeerOrigin.Discv5)
388+
else:
389+
debug "could not convert discv5 bootstrap node to peerInfo, not adding peer to Peer Store",
390+
enr = enr.toUri(), error = peerInfoRes.error
391+
384392
discv5BootstrapEnrs.add(dynamicBootstrapEnrs)
385393

386394
let discv5Config = DiscoveryConfig.init(

waku/factory/node_factory.nim

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,12 +399,18 @@ proc startNode*(
399399

400400
# Connect to configured static nodes
401401
if conf.staticnodes.len > 0:
402+
if not conf.relay:
403+
return err("waku relay (--relay=true) should be set when configuring staticnodes")
402404
try:
403405
await connectToNodes(node, conf.staticnodes, "static")
404406
except CatchableError:
405407
return err("failed to connect to static nodes: " & getCurrentExceptionMsg())
406408

407409
if dynamicBootstrapNodes.len > 0:
410+
if not conf.relay:
411+
return err(
412+
"waku relay (--relay=true) should be set when configuring dynamicBootstrapNodes"
413+
)
408414
info "Connecting to dynamic bootstrap peers"
409415
try:
410416
await connectToNodes(node, dynamicBootstrapNodes, "dynamic bootstrap")

waku/waku_core/codecs.nim

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const
2+
WakuRelayCodec* = "/vac/waku/relay/2.0.0"
3+
WakuStoreCodec* = "/vac/waku/store-query/3.0.0"
4+
WakuFilterSubscribeCodec* = "/vac/waku/filter-subscribe/2.0.0-beta1"
5+
WakuFilterPushCodec* = "/vac/waku/filter-push/2.0.0-beta1"
6+
WakuLightPushCodec* = "/vac/waku/lightpush/2.0.0-beta1"
7+
WakuSyncCodec* = "/vac/waku/sync/1.0.0"
8+
WakuMetadataCodec* = "/vac/waku/metadata/1.0.0"
9+
WakuPeerExchangeCodec* = "/vac/waku/peer-exchange/2.0.0-alpha1"
10+
WakuLegacyStoreCodec* = "/vac/waku/store/2.0.0-beta4"

waku/waku_core/peers.nim

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import
44
std/[options, sequtils, strutils, uri, net],
55
results,
66
chronos,
7+
chronicles,
78
eth/keys,
89
eth/p2p/discoveryv5/enr,
910
eth/net/utils,
@@ -16,6 +17,7 @@ import
1617
libp2p/peerinfo,
1718
libp2p/routing_record,
1819
json_serialization
20+
import ../waku_enr/capabilities
1921

2022
type
2123
Connectedness* = enum
@@ -243,7 +245,17 @@ proc toRemotePeerInfo*(enr: enr.Record): Result[RemotePeerInfo, cstring] =
243245
if addrs.len == 0:
244246
return err("enr: no addresses in record")
245247

246-
return ok(RemotePeerInfo.init(peerId, addrs, some(enr)))
248+
let protocolsRes = catch:
249+
enr.getCapabilitiesCodecs()
250+
251+
var protocols: seq[string]
252+
if not protocolsRes.isErr():
253+
protocols = protocolsRes.get()
254+
else:
255+
error "Could not retrieve supported protocols from enr",
256+
peerId = peerId, msg = protocolsRes.error.msg
257+
258+
return ok(RemotePeerInfo.init(peerId, addrs, some(enr), protocols))
247259

248260
converter toRemotePeerInfo*(peerRecord: PeerRecord): RemotePeerInfo =
249261
## Converts peer records to dialable RemotePeerInfo
@@ -256,7 +268,7 @@ converter toRemotePeerInfo*(peerInfo: PeerInfo): RemotePeerInfo =
256268
RemotePeerInfo(
257269
peerId: peerInfo.peerId,
258270
addrs: peerInfo.listenAddrs,
259-
enr: none(Record),
271+
enr: none(enr.Record),
260272
protocols: peerInfo.protocols,
261273
agent: peerInfo.agentVersion,
262274
protoVersion: peerInfo.protoVersion,

waku/waku_enr/capabilities.nim

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
{.push raises: [].}
22

3-
import std/[options, bitops, sequtils, net], results, eth/keys, libp2p/crypto/crypto
4-
import ../common/enr
3+
import
4+
std/[options, bitops, sequtils, net, tables], results, eth/keys, libp2p/crypto/crypto
5+
import ../common/enr, ../waku_core/codecs
56

67
const CapabilitiesEnrField* = "waku2"
78

@@ -20,6 +21,14 @@ type
2021
Lightpush = 3
2122
Sync = 4
2223

24+
const capabilityToCodec = {
25+
Capabilities.Relay: WakuRelayCodec,
26+
Capabilities.Store: WakuStoreCodec,
27+
Capabilities.Filter: WakuFilterSubscribeCodec,
28+
Capabilities.Lightpush: WakuLightPushCodec,
29+
Capabilities.Sync: WakuSyncCodec,
30+
}.toTable
31+
2332
func init*(
2433
T: type CapabilitiesBitfield, lightpush, filter, store, relay, sync: bool = false
2534
): T =
@@ -101,3 +110,7 @@ proc getCapabilities*(r: Record): seq[Capabilities] =
101110

102111
let bitfield = bitfieldOpt.get()
103112
bitfield.toCapabilities()
113+
114+
proc getCapabilitiesCodecs*(r: Record): seq[string] {.raises: [ValueError].} =
115+
let capabilities = r.getCapabilities()
116+
return capabilities.mapIt(capabilityToCodec[it])

waku/waku_filter_v2/common.nim

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@
22

33
import results
44

5-
const
6-
WakuFilterSubscribeCodec* = "/vac/waku/filter-subscribe/2.0.0-beta1"
7-
WakuFilterPushCodec* = "/vac/waku/filter-push/2.0.0-beta1"
5+
from ../waku_core/codecs import WakuFilterSubscribeCodec, WakuFilterPushCodec
6+
export WakuFilterSubscribeCodec, WakuFilterPushCodec
87

98
type
109
FilterSubscribeErrorKind* {.pure.} = enum

waku/waku_lightpush/common.nim

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
import results, chronos, libp2p/peerid
44
import ../waku_core
55

6-
const WakuLightPushCodec* = "/vac/waku/lightpush/2.0.0-beta1"
6+
from ../waku_core/codecs import WakuLightPushCodec
7+
export WakuLightPushCodec
78

89
type WakuLightPushResult*[T] = Result[T, string]
910

0 commit comments

Comments
 (0)