mirror of https://github.com/waku-org/nwaku.git
feat(discv5): advertise custom multiaddresses (#1512)
* feat(discv5): allow custom multiaddr advertisement in discv5 feat(discv5): allow custom multiaddr advertisement in discv5 feat(discv5): move discv5 setup from wakunode2 to waku_node fix(waku_node): def param test(discv5): test for ext multiaddr fix(discv5): address comments fix(discv5): address comments fix(wakunode2): discoveryconfig in var before init fix(discv5): pass multiaddr to discv5 directly fix(discv5): make multiaddrs optional fix(test): discv5 init fix(discv5): split discv5 mounting from waku_node chore(discv5): s/WakuAddressMetadata/WakuNodeAddrMeta/g * fix(waku_node): 1.25 max conns * fix(discv5): s/WakuNodeAddrMeta/NetConfig/g * fix(discv5): address reviews * fix(discv5): smaller try-catches * fix(discv5): missing arg * fix: compile error
This commit is contained in:
parent
7f2ea1caeb
commit
9ddf0fe1e2
|
@ -278,61 +278,77 @@ proc initNode(conf: WakuNodeConf,
|
||||||
|
|
||||||
let pStorage = if peerStore.isNone(): nil
|
let pStorage = if peerStore.isNone(): nil
|
||||||
else: peerStore.get()
|
else: peerStore.get()
|
||||||
|
|
||||||
|
let rng = crypto.newRng()
|
||||||
|
# Wrap in none because NetConfig does not have a default constructor
|
||||||
|
# TODO: We could change bindIp in NetConfig to be something less restrictive than ValidIpAddress,
|
||||||
|
# which doesn't allow default construction
|
||||||
|
var netConfigOpt = none(NetConfig)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
node = WakuNode.new(nodekey,
|
netConfigOpt = some(NetConfig.init(
|
||||||
conf.listenAddress, Port(uint16(conf.tcpPort) + conf.portsShift),
|
bindIp = conf.listenAddress,
|
||||||
extIp, extPort,
|
bindPort = Port(uint16(conf.tcpPort) + conf.portsShift),
|
||||||
extMultiAddrs,
|
extIp = extIp,
|
||||||
pStorage,
|
extPort = extPort,
|
||||||
conf.maxConnections.int,
|
extMultiAddrs = extMultiAddrs,
|
||||||
Port(uint16(conf.websocketPort) + conf.portsShift),
|
wsBindPort = Port(uint16(conf.websocketPort) + conf.portsShift),
|
||||||
conf.websocketSupport,
|
wsEnabled = conf.websocketSupport,
|
||||||
conf.websocketSecureSupport,
|
wssEnabled = conf.websocketSecureSupport,
|
||||||
conf.websocketSecureKeyPath,
|
dns4DomainName = dns4DomainName,
|
||||||
conf.websocketSecureCertPath,
|
discv5UdpPort = discv5UdpPort,
|
||||||
some(wakuFlags),
|
wakuFlags = some(wakuFlags),
|
||||||
dnsResolver,
|
))
|
||||||
conf.relayPeerExchange, # We send our own signed peer record when peer exchange enabled
|
|
||||||
dns4DomainName,
|
|
||||||
discv5UdpPort,
|
|
||||||
some(conf.agentString),
|
|
||||||
conf.peerStoreCapacity,
|
|
||||||
rng)
|
|
||||||
except:
|
except:
|
||||||
return err("failed to create waku node instance: " & getCurrentExceptionMsg())
|
return err("failed to create net config instance: " & getCurrentExceptionMsg())
|
||||||
|
|
||||||
|
let netConfig = netConfigOpt.get()
|
||||||
|
var wakuDiscv5 = none(WakuDiscoveryV5)
|
||||||
|
|
||||||
if conf.discv5Discovery:
|
if conf.discv5Discovery:
|
||||||
let
|
let dynamicBootstrapEnrs = dynamicBootstrapNodes
|
||||||
discoveryConfig = DiscoveryConfig.init(
|
.filterIt(it.hasUdpPort())
|
||||||
conf.discv5TableIpLimit, conf.discv5BucketIpLimit, conf.discv5BitsPerHop)
|
.mapIt(it.enr.get())
|
||||||
|
|
||||||
# select dynamic bootstrap nodes that have an ENR containing a udp port.
|
|
||||||
# Discv5 only supports UDP https://github.com/ethereum/devp2p/blob/master/discv5/discv5-theory.md)
|
|
||||||
var discv5BootstrapEnrs: seq[enr.Record]
|
var discv5BootstrapEnrs: seq[enr.Record]
|
||||||
for n in dynamicBootstrapNodes:
|
|
||||||
if n.enr.isSome():
|
|
||||||
let
|
|
||||||
enr = n.enr.get()
|
|
||||||
tenrRes = enr.toTypedRecord()
|
|
||||||
if tenrRes.isOk() and (tenrRes.get().udp.isSome() or tenrRes.get().udp6.isSome()):
|
|
||||||
discv5BootstrapEnrs.add(enr)
|
|
||||||
|
|
||||||
# parse enrURIs from the configuration and add the resulting ENRs to the discv5BootstrapEnrs seq
|
# parse enrURIs from the configuration and add the resulting ENRs to the discv5BootstrapEnrs seq
|
||||||
for enrUri in conf.discv5BootstrapNodes:
|
for enrUri in conf.discv5BootstrapNodes:
|
||||||
addBootstrapNode(enrUri, discv5BootstrapEnrs)
|
addBootstrapNode(enrUri, discv5BootstrapEnrs)
|
||||||
|
discv5BootstrapEnrs.add(dynamicBootstrapEnrs)
|
||||||
node.wakuDiscv5 = WakuDiscoveryV5.new(
|
let discv5Config = DiscoveryConfig.init(conf.discv5TableIpLimit,
|
||||||
extIP, extPort, discv5UdpPort,
|
conf.discv5BucketIpLimit,
|
||||||
conf.listenAddress,
|
conf.discv5BitsPerHop)
|
||||||
discv5UdpPort.get(),
|
try:
|
||||||
discv5BootstrapEnrs,
|
wakuDiscv5 = some(WakuDiscoveryV5.new(
|
||||||
conf.discv5EnrAutoUpdate,
|
extIp = netConfig.extIp,
|
||||||
keys.PrivateKey(nodekey.skkey),
|
extTcpPort = netConfig.extPort,
|
||||||
wakuFlags,
|
extUdpPort = netConfig.discv5UdpPort,
|
||||||
[], # Empty enr fields, for now
|
bindIp = netConfig.bindIp,
|
||||||
node.rng,
|
discv5UdpPort = netConfig.discv5UdpPort.get(),
|
||||||
discoveryConfig
|
bootstrapEnrs = discv5BootstrapEnrs,
|
||||||
)
|
enrAutoUpdate = conf.discv5EnrAutoUpdate,
|
||||||
|
privateKey = keys.PrivateKey(nodekey.skkey),
|
||||||
|
flags = netConfig.wakuFlags.get(),
|
||||||
|
multiaddrs = netConfig.enrMultiaddrs,
|
||||||
|
rng = rng,
|
||||||
|
discv5Config = discv5Config,
|
||||||
|
))
|
||||||
|
except:
|
||||||
|
return err("failed to create waku discv5 instance: " & getCurrentExceptionMsg())
|
||||||
|
try:
|
||||||
|
node = WakuNode.new(nodekey = nodekey,
|
||||||
|
netConfig = netConfig,
|
||||||
|
peerStorage = pStorage,
|
||||||
|
maxConnections = conf.maxConnections.int,
|
||||||
|
secureKey = conf.websocketSecureKeyPath,
|
||||||
|
secureCert = conf.websocketSecureCertPath,
|
||||||
|
nameResolver = dnsResolver,
|
||||||
|
sendSignedPeerRecord = conf.relayPeerExchange, # We send our own signed peer record when peer exchange enabled
|
||||||
|
wakuDiscv5 = wakuDiscv5,
|
||||||
|
agentString = some(conf.agentString),
|
||||||
|
peerStoreCapacity = conf.peerStoreCapacity,
|
||||||
|
rng = rng)
|
||||||
|
except:
|
||||||
|
return err("failed to create waku node instance: " & getCurrentExceptionMsg())
|
||||||
|
|
||||||
ok(node)
|
ok(node)
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,6 @@ proc setupAndPublish(rng: ref HmacDrbgContext) {.async.} =
|
||||||
bootstrapNodes = bootstrapNodes,
|
bootstrapNodes = bootstrapNodes,
|
||||||
privateKey = keys.PrivateKey(nodeKey.skkey),
|
privateKey = keys.PrivateKey(nodeKey.skkey),
|
||||||
flags = flags,
|
flags = flags,
|
||||||
enrFields = [],
|
|
||||||
rng = node.rng)
|
rng = node.rng)
|
||||||
|
|
||||||
await node.start()
|
await node.start()
|
||||||
|
|
|
@ -44,7 +44,6 @@ proc setupAndSubscribe(rng: ref HmacDrbgContext) {.async.} =
|
||||||
bootstrapNodes = bootstrapNodes,
|
bootstrapNodes = bootstrapNodes,
|
||||||
privateKey = keys.PrivateKey(nodeKey.skkey),
|
privateKey = keys.PrivateKey(nodeKey.skkey),
|
||||||
flags = flags,
|
flags = flags,
|
||||||
enrFields = [],
|
|
||||||
rng = node.rng)
|
rng = node.rng)
|
||||||
|
|
||||||
await node.start()
|
await node.start()
|
||||||
|
|
|
@ -22,10 +22,10 @@ procSuite "ENR utils":
|
||||||
tooShort = "0x000A047F0000010601BADD0301".hexToSeqByte()
|
tooShort = "0x000A047F0000010601BADD0301".hexToSeqByte()
|
||||||
gibberish = "0x3270ac4e5011123c".hexToSeqByte()
|
gibberish = "0x3270ac4e5011123c".hexToSeqByte()
|
||||||
empty = newSeq[byte]()
|
empty = newSeq[byte]()
|
||||||
|
|
||||||
## Note: we expect to fail optimistically, i.e. extract
|
## Note: we expect to fail optimistically, i.e. extract
|
||||||
## any addresses we can and ignore other errors.
|
## any addresses we can and ignore other errors.
|
||||||
## Worst case scenario is we return an empty `multiaddrs` seq.
|
## Worst case scenario is we return an empty `multiaddrs` seq.
|
||||||
check:
|
check:
|
||||||
# Expected cases
|
# Expected cases
|
||||||
reasonable.toMultiAddresses().contains(MultiAddress.init("/ip4/127.0.0.1/tcp/442/ws")[])
|
reasonable.toMultiAddresses().contains(MultiAddress.init("/ip4/127.0.0.1/tcp/442/ws")[])
|
||||||
|
@ -50,19 +50,19 @@ procSuite "ENR utils":
|
||||||
MultiAddress.init("/ip4/127.0.0.1/tcp/443/wss")[]]
|
MultiAddress.init("/ip4/127.0.0.1/tcp/443/wss")[]]
|
||||||
|
|
||||||
let
|
let
|
||||||
record = initEnr(enrKey, some(enrIp),
|
record = enr.Record.init(enrKey, some(enrIp),
|
||||||
some(enrTcpPort), some(enrUdpPort),
|
some(enrTcpPort), some(enrUdpPort),
|
||||||
some(wakuFlags),
|
some(wakuFlags),
|
||||||
multiaddrs)
|
multiaddrs)
|
||||||
typedRecord = record.toTypedRecord.get()
|
typedRecord = record.toTypedRecord.get()
|
||||||
|
|
||||||
# Check EIP-778 ENR fields
|
# Check EIP-778 ENR fields
|
||||||
check:
|
check:
|
||||||
@(typedRecord.secp256k1.get()) == enrKey.getPublicKey()[].getRawBytes()[]
|
@(typedRecord.secp256k1.get()) == enrKey.getPublicKey()[].getRawBytes()[]
|
||||||
ipv4(typedRecord.ip.get()) == enrIp
|
ipv4(typedRecord.ip.get()) == enrIp
|
||||||
Port(typedRecord.tcp.get()) == enrTcpPort
|
Port(typedRecord.tcp.get()) == enrTcpPort
|
||||||
Port(typedRecord.udp.get()) == enrUdpPort
|
Port(typedRecord.udp.get()) == enrUdpPort
|
||||||
|
|
||||||
# Check Waku ENR fields
|
# Check Waku ENR fields
|
||||||
let
|
let
|
||||||
decodedFlags = record.get(WAKU_ENR_FIELD, seq[byte])[]
|
decodedFlags = record.get(WAKU_ENR_FIELD, seq[byte])[]
|
||||||
|
@ -71,7 +71,7 @@ procSuite "ENR utils":
|
||||||
decodedFlags == @[wakuFlags.byte]
|
decodedFlags == @[wakuFlags.byte]
|
||||||
decodedAddrs.contains(MultiAddress.init("/ip4/127.0.0.1/tcp/442/ws")[])
|
decodedAddrs.contains(MultiAddress.init("/ip4/127.0.0.1/tcp/442/ws")[])
|
||||||
decodedAddrs.contains(MultiAddress.init("/ip4/127.0.0.1/tcp/443/wss")[])
|
decodedAddrs.contains(MultiAddress.init("/ip4/127.0.0.1/tcp/443/wss")[])
|
||||||
|
|
||||||
asyncTest "Strip multiaddr peerId":
|
asyncTest "Strip multiaddr peerId":
|
||||||
# Tests that peerId is stripped of multiaddrs as per RFC31
|
# Tests that peerId is stripped of multiaddrs as per RFC31
|
||||||
let
|
let
|
||||||
|
@ -81,7 +81,7 @@ procSuite "ENR utils":
|
||||||
multiaddrs = @[MultiAddress.init("/ip4/127.0.0.1/tcp/443/wss/p2p/16Uiu2HAm4v86W3bmT1BiH6oSPzcsSr31iDQpSN5Qa882BCjjwgrD")[]]
|
multiaddrs = @[MultiAddress.init("/ip4/127.0.0.1/tcp/443/wss/p2p/16Uiu2HAm4v86W3bmT1BiH6oSPzcsSr31iDQpSN5Qa882BCjjwgrD")[]]
|
||||||
|
|
||||||
let
|
let
|
||||||
record = initEnr(enrKey, some(enrIp),
|
record = enr.Record.init(enrKey, some(enrIp),
|
||||||
some(enrTcpPort), some(enrUdpPort),
|
some(enrTcpPort), some(enrUdpPort),
|
||||||
none(WakuEnrBitfield),
|
none(WakuEnrBitfield),
|
||||||
multiaddrs)
|
multiaddrs)
|
||||||
|
@ -89,7 +89,7 @@ procSuite "ENR utils":
|
||||||
# Check Waku ENR fields
|
# Check Waku ENR fields
|
||||||
let
|
let
|
||||||
decodedAddrs = record.get(MULTIADDR_ENR_FIELD, seq[byte])[].toMultiAddresses()
|
decodedAddrs = record.get(MULTIADDR_ENR_FIELD, seq[byte])[].toMultiAddresses()
|
||||||
|
|
||||||
check decodedAddrs.contains(MultiAddress.init("/ip4/127.0.0.1/tcp/443/wss")[]) # Peer Id has been stripped
|
check decodedAddrs.contains(MultiAddress.init("/ip4/127.0.0.1/tcp/443/wss")[]) # Peer Id has been stripped
|
||||||
|
|
||||||
asyncTest "Decode ENR with multiaddrs field":
|
asyncTest "Decode ENR with multiaddrs field":
|
||||||
|
@ -110,7 +110,7 @@ procSuite "ENR utils":
|
||||||
var enrRecord: Record
|
var enrRecord: Record
|
||||||
check:
|
check:
|
||||||
enrRecord.fromURI(knownEnr)
|
enrRecord.fromURI(knownEnr)
|
||||||
|
|
||||||
let typedRecord = enrRecord.toTypedRecord.get()
|
let typedRecord = enrRecord.toTypedRecord.get()
|
||||||
|
|
||||||
# Check EIP-778 ENR fields
|
# Check EIP-778 ENR fields
|
||||||
|
@ -118,11 +118,11 @@ procSuite "ENR utils":
|
||||||
ipv4(typedRecord.ip.get()) == knownIp
|
ipv4(typedRecord.ip.get()) == knownIp
|
||||||
typedRecord.tcp == knownTcpPort
|
typedRecord.tcp == knownTcpPort
|
||||||
typedRecord.udp == knownUdpPort
|
typedRecord.udp == knownUdpPort
|
||||||
|
|
||||||
# Check Waku ENR fields
|
# Check Waku ENR fields
|
||||||
let
|
let
|
||||||
decodedAddrs = enrRecord.get(MULTIADDR_ENR_FIELD, seq[byte])[].toMultiAddresses()
|
decodedAddrs = enrRecord.get(MULTIADDR_ENR_FIELD, seq[byte])[].toMultiAddresses()
|
||||||
|
|
||||||
for knownMultiaddr in knownMultiaddrs:
|
for knownMultiaddr in knownMultiaddrs:
|
||||||
check decodedAddrs.contains(knownMultiaddr)
|
check decodedAddrs.contains(knownMultiaddr)
|
||||||
|
|
||||||
|
@ -132,12 +132,12 @@ procSuite "ENR utils":
|
||||||
enrTcpPort, enrUdpPort = Port(60000)
|
enrTcpPort, enrUdpPort = Port(60000)
|
||||||
enrKey = wakuenr.crypto.PrivateKey.random(Secp256k1, rng[])[]
|
enrKey = wakuenr.crypto.PrivateKey.random(Secp256k1, rng[])[]
|
||||||
multiaddrs = @[MultiAddress.init("/ip4/127.0.0.1/tcp/442/ws")[]]
|
multiaddrs = @[MultiAddress.init("/ip4/127.0.0.1/tcp/442/ws")[]]
|
||||||
|
|
||||||
# TODO: Refactor initEnr, provide enums as inputs initEnr(capabilites=[Store,Filter])
|
# TODO: Refactor enr.Record.init, provide enums as inputs enr.Record.init(capabilites=[Store,Filter])
|
||||||
# TODO: safer than a util function and directly using the bits
|
# TODO: safer than a util function and directly using the bits
|
||||||
# test all flag combinations 2^4 = 16 (b0000-b1111)
|
# test all flag combinations 2^4 = 16 (b0000-b1111)
|
||||||
records = toSeq(0b0000_0000'u8..0b0000_1111'u8)
|
records = toSeq(0b0000_0000'u8..0b0000_1111'u8)
|
||||||
.mapIt(initEnr(enrKey,
|
.mapIt(enr.Record.init(enrKey,
|
||||||
some(enrIp),
|
some(enrIp),
|
||||||
some(enrTcpPort),
|
some(enrTcpPort),
|
||||||
some(enrUdpPort),
|
some(enrUdpPort),
|
||||||
|
@ -161,7 +161,7 @@ procSuite "ENR utils":
|
||||||
[true, true, false, true],
|
[true, true, false, true],
|
||||||
[true, true, true, false],
|
[true, true, true, false],
|
||||||
[true, true, true, true]]
|
[true, true, true, true]]
|
||||||
|
|
||||||
for i, record in records:
|
for i, record in records:
|
||||||
for j, capability in @[Lightpush, Filter, Store, Relay]:
|
for j, capability in @[Lightpush, Filter, Store, Relay]:
|
||||||
check expectedCapabilities[i][j] == record.supportsCapability(capability)
|
check expectedCapabilities[i][j] == record.supportsCapability(capability)
|
||||||
|
@ -172,18 +172,18 @@ procSuite "ENR utils":
|
||||||
enrTcpPort, enrUdpPort = Port(60000)
|
enrTcpPort, enrUdpPort = Port(60000)
|
||||||
enrKey = wakuenr.crypto.PrivateKey.random(Secp256k1, rng[])[]
|
enrKey = wakuenr.crypto.PrivateKey.random(Secp256k1, rng[])[]
|
||||||
multiaddrs = @[MultiAddress.init("/ip4/127.0.0.1/tcp/442/ws")[]]
|
multiaddrs = @[MultiAddress.init("/ip4/127.0.0.1/tcp/442/ws")[]]
|
||||||
|
|
||||||
records = @[0b0000_0000'u8,
|
records = @[0b0000_0000'u8,
|
||||||
0b0000_1111'u8,
|
0b0000_1111'u8,
|
||||||
0b0000_1001'u8,
|
0b0000_1001'u8,
|
||||||
0b0000_1110'u8,
|
0b0000_1110'u8,
|
||||||
0b0000_1000'u8,]
|
0b0000_1000'u8,]
|
||||||
.mapIt(initEnr(enrKey,
|
.mapIt(enr.Record.init(enrKey,
|
||||||
some(enrIp),
|
some(enrIp),
|
||||||
some(enrTcpPort),
|
some(enrTcpPort),
|
||||||
some(enrUdpPort),
|
some(enrUdpPort),
|
||||||
some(uint8(it)),
|
some(uint8(it)),
|
||||||
multiaddrs))
|
multiaddrs))
|
||||||
|
|
||||||
# expected capabilities, ordered LSB to MSB
|
# expected capabilities, ordered LSB to MSB
|
||||||
expectedCapabilities: seq[seq[Capabilities]] = @[
|
expectedCapabilities: seq[seq[Capabilities]] = @[
|
||||||
|
@ -197,14 +197,14 @@ procSuite "ENR utils":
|
||||||
check actualExpetedTuple[0].getCapabilities() == actualExpetedTuple[1]
|
check actualExpetedTuple[0].getCapabilities() == actualExpetedTuple[1]
|
||||||
|
|
||||||
asyncTest "Get supported capabilities of a non waku node":
|
asyncTest "Get supported capabilities of a non waku node":
|
||||||
|
|
||||||
# non waku enr, i.e. Ethereum one
|
# non waku enr, i.e. Ethereum one
|
||||||
let nonWakuEnr = "enr:-KG4QOtcP9X1FbIMOe17QNMKqDxCpm14jcX5tiOE4_TyMrFqbmhPZHK_ZPG2G"&
|
let nonWakuEnr = "enr:-KG4QOtcP9X1FbIMOe17QNMKqDxCpm14jcX5tiOE4_TyMrFqbmhPZHK_ZPG2G"&
|
||||||
"xb1GE2xdtodOfx9-cgvNtxnRyHEmC0ghGV0aDKQ9aX9QgAAAAD__________4JpZIJ2NIJpcIQDE8KdiXNl"&
|
"xb1GE2xdtodOfx9-cgvNtxnRyHEmC0ghGV0aDKQ9aX9QgAAAAD__________4JpZIJ2NIJpcIQDE8KdiXNl"&
|
||||||
"Y3AyNTZrMaEDhpehBDbZjM_L9ek699Y7vhUJ-eAdMyQW_Fil522Y0fODdGNwgiMog3VkcIIjKA"
|
"Y3AyNTZrMaEDhpehBDbZjM_L9ek699Y7vhUJ-eAdMyQW_Fil522Y0fODdGNwgiMog3VkcIIjKA"
|
||||||
|
|
||||||
var nonWakuEnrRecord: Record
|
var nonWakuEnrRecord: Record
|
||||||
|
|
||||||
check:
|
check:
|
||||||
nonWakuEnrRecord.fromURI(nonWakuEnr)
|
nonWakuEnrRecord.fromURI(nonWakuEnr)
|
||||||
|
|
||||||
|
@ -214,4 +214,4 @@ procSuite "ENR utils":
|
||||||
nonWakuEnrRecord.supportsCapability(Relay) == false
|
nonWakuEnrRecord.supportsCapability(Relay) == false
|
||||||
nonWakuEnrRecord.supportsCapability(Store) == false
|
nonWakuEnrRecord.supportsCapability(Store) == false
|
||||||
nonWakuEnrRecord.supportsCapability(Filter) == false
|
nonWakuEnrRecord.supportsCapability(Filter) == false
|
||||||
nonWakuEnrRecord.supportsCapability(Lightpush) == false
|
nonWakuEnrRecord.supportsCapability(Lightpush) == false
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
chronos,
|
chronos,
|
||||||
|
chronicles,
|
||||||
testutils/unittests,
|
testutils/unittests,
|
||||||
stew/byteutils,
|
stew/byteutils,
|
||||||
stew/shims/net,
|
stew/shims/net,
|
||||||
|
@ -25,7 +26,7 @@ procSuite "Waku Discovery v5":
|
||||||
nodeTcpPort1 = Port(61500)
|
nodeTcpPort1 = Port(61500)
|
||||||
nodeUdpPort1 = Port(9000)
|
nodeUdpPort1 = Port(9000)
|
||||||
node1 = WakuNode.new(nodeKey1, bindIp, nodeTcpPort1)
|
node1 = WakuNode.new(nodeKey1, bindIp, nodeTcpPort1)
|
||||||
|
|
||||||
nodeKey2 = crypto.PrivateKey.random(Secp256k1, rng[])[]
|
nodeKey2 = crypto.PrivateKey.random(Secp256k1, rng[])[]
|
||||||
nodeTcpPort2 = Port(61502)
|
nodeTcpPort2 = Port(61502)
|
||||||
nodeUdpPort2 = Port(9002)
|
nodeUdpPort2 = Port(9002)
|
||||||
|
@ -46,7 +47,7 @@ procSuite "Waku Discovery v5":
|
||||||
contentTopic = ContentTopic("/waku/2/default-content/proto")
|
contentTopic = ContentTopic("/waku/2/default-content/proto")
|
||||||
payload = "Can you see me?".toBytes()
|
payload = "Can you see me?".toBytes()
|
||||||
message = WakuMessage(payload: payload, contentTopic: contentTopic)
|
message = WakuMessage(payload: payload, contentTopic: contentTopic)
|
||||||
|
|
||||||
# Mount discv5
|
# Mount discv5
|
||||||
node1.wakuDiscv5 = WakuDiscoveryV5.new(
|
node1.wakuDiscv5 = WakuDiscoveryV5.new(
|
||||||
some(extIp), some(nodeTcpPort1), some(nodeUdpPort1),
|
some(extIp), some(nodeTcpPort1), some(nodeUdpPort1),
|
||||||
|
@ -56,10 +57,10 @@ procSuite "Waku Discovery v5":
|
||||||
false,
|
false,
|
||||||
keys.PrivateKey(nodeKey1.skkey),
|
keys.PrivateKey(nodeKey1.skkey),
|
||||||
flags,
|
flags,
|
||||||
[], # Empty enr fields, for now
|
newSeq[MultiAddress](), # Empty multiaddr fields, for now
|
||||||
node1.rng
|
node1.rng
|
||||||
)
|
)
|
||||||
|
|
||||||
node2.wakuDiscv5 = WakuDiscoveryV5.new(
|
node2.wakuDiscv5 = WakuDiscoveryV5.new(
|
||||||
some(extIp), some(nodeTcpPort2), some(nodeUdpPort2),
|
some(extIp), some(nodeTcpPort2), some(nodeUdpPort2),
|
||||||
bindIp,
|
bindIp,
|
||||||
|
@ -68,10 +69,10 @@ procSuite "Waku Discovery v5":
|
||||||
false,
|
false,
|
||||||
keys.PrivateKey(nodeKey2.skkey),
|
keys.PrivateKey(nodeKey2.skkey),
|
||||||
flags,
|
flags,
|
||||||
[], # Empty enr fields, for now
|
newSeq[MultiAddress](), # Empty multiaddr fields, for now
|
||||||
node2.rng
|
node2.rng
|
||||||
)
|
)
|
||||||
|
|
||||||
node3.wakuDiscv5 = WakuDiscoveryV5.new(
|
node3.wakuDiscv5 = WakuDiscoveryV5.new(
|
||||||
some(extIp), some(nodeTcpPort3), some(nodeUdpPort3),
|
some(extIp), some(nodeTcpPort3), some(nodeUdpPort3),
|
||||||
bindIp,
|
bindIp,
|
||||||
|
@ -80,7 +81,7 @@ procSuite "Waku Discovery v5":
|
||||||
false,
|
false,
|
||||||
keys.PrivateKey(nodeKey3.skkey),
|
keys.PrivateKey(nodeKey3.skkey),
|
||||||
flags,
|
flags,
|
||||||
[], # Empty enr fields, for now
|
newSeq[MultiAddress](), # Empty multiaddr fields, for now
|
||||||
node3.rng
|
node3.rng
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -97,7 +98,7 @@ procSuite "Waku Discovery v5":
|
||||||
node1.wakuDiscv5.protocol.nodesDiscovered > 0
|
node1.wakuDiscv5.protocol.nodesDiscovered > 0
|
||||||
node2.wakuDiscv5.protocol.nodesDiscovered > 0
|
node2.wakuDiscv5.protocol.nodesDiscovered > 0
|
||||||
node3.wakuDiscv5.protocol.nodesDiscovered > 0
|
node3.wakuDiscv5.protocol.nodesDiscovered > 0
|
||||||
|
|
||||||
# Let's see if we can deliver a message end-to-end
|
# Let's see if we can deliver a message end-to-end
|
||||||
# var completionFut = newFuture[bool]()
|
# var completionFut = newFuture[bool]()
|
||||||
# proc relayHandler(topic: string, data: seq[byte]) {.async, gcsafe.} =
|
# proc relayHandler(topic: string, data: seq[byte]) {.async, gcsafe.} =
|
||||||
|
@ -119,3 +120,76 @@ procSuite "Waku Discovery v5":
|
||||||
# (await completionFut.withTimeout(6.seconds)) == true
|
# (await completionFut.withTimeout(6.seconds)) == true
|
||||||
|
|
||||||
await allFutures([node1.stop(), node2.stop(), node3.stop()])
|
await allFutures([node1.stop(), node2.stop(), node3.stop()])
|
||||||
|
|
||||||
|
asyncTest "Custom multiaddresses are advertised correctly":
|
||||||
|
let
|
||||||
|
bindIp = ValidIpAddress.init("0.0.0.0")
|
||||||
|
extIp = ValidIpAddress.init("127.0.0.1")
|
||||||
|
expectedMultiAddr = MultiAddress.init("/ip4/200.200.200.200/tcp/9000/wss").tryGet()
|
||||||
|
|
||||||
|
flags = initWakuFlags(lightpush = false,
|
||||||
|
filter = false,
|
||||||
|
store = false,
|
||||||
|
relay = true)
|
||||||
|
|
||||||
|
nodeTcpPort1 = Port(9010)
|
||||||
|
nodeUdpPort1 = Port(9012)
|
||||||
|
node1Key = generateKey()
|
||||||
|
node1NetConfig = NetConfig.init(bindIp = bindIp,
|
||||||
|
extIp = some(extIp),
|
||||||
|
extPort = some(nodeTcpPort1),
|
||||||
|
bindPort = nodeTcpPort1,
|
||||||
|
extmultiAddrs = @[expectedMultiAddr],
|
||||||
|
wakuFlags = some(flags),
|
||||||
|
discv5UdpPort = some(nodeUdpPort1))
|
||||||
|
node1discV5 = WakuDiscoveryV5.new(extIp = node1NetConfig.extIp,
|
||||||
|
extTcpPort = node1NetConfig.extPort,
|
||||||
|
extUdpPort = node1NetConfig.discv5UdpPort,
|
||||||
|
bindIp = node1NetConfig.bindIp,
|
||||||
|
discv5UdpPort = node1NetConfig.discv5UdpPort.get(),
|
||||||
|
privateKey = keys.PrivateKey(node1Key.skkey),
|
||||||
|
multiaddrs = node1NetConfig.enrMultiaddrs,
|
||||||
|
flags = node1NetConfig.wakuFlags.get(),
|
||||||
|
rng = rng)
|
||||||
|
node1 = WakuNode.new(nodekey = node1Key,
|
||||||
|
netConfig = node1NetConfig,
|
||||||
|
wakuDiscv5 = some(node1discV5),
|
||||||
|
rng = rng)
|
||||||
|
|
||||||
|
|
||||||
|
nodeTcpPort2 = Port(9014)
|
||||||
|
nodeUdpPort2 = Port(9016)
|
||||||
|
node2Key = generateKey()
|
||||||
|
node2NetConfig = NetConfig.init(bindIp = bindIp,
|
||||||
|
extIp = some(extIp),
|
||||||
|
extPort = some(nodeTcpPort2),
|
||||||
|
bindPort = nodeTcpPort2,
|
||||||
|
wakuFlags = some(flags),
|
||||||
|
discv5UdpPort = some(nodeUdpPort2))
|
||||||
|
node2discV5 = WakuDiscoveryV5.new(extIp = node2NetConfig.extIp,
|
||||||
|
extTcpPort = node2NetConfig.extPort,
|
||||||
|
extUdpPort = node2NetConfig.discv5UdpPort,
|
||||||
|
bindIp = node2NetConfig.bindIp,
|
||||||
|
discv5UdpPort = node2NetConfig.discv5UdpPort.get(),
|
||||||
|
bootstrapEnrs = @[node1.wakuDiscv5.protocol.localNode.record],
|
||||||
|
privateKey = keys.PrivateKey(node2Key.skkey),
|
||||||
|
flags = node2NetConfig.wakuFlags.get(),
|
||||||
|
rng = rng)
|
||||||
|
node2 = WakuNode.new(nodeKey = node2Key,
|
||||||
|
netConfig = node2NetConfig,
|
||||||
|
wakuDiscv5 = some(node2discV5))
|
||||||
|
|
||||||
|
await allFutures([node1.start(), node2.start()])
|
||||||
|
|
||||||
|
await allFutures([node1.startDiscv5(), node2.startDiscv5()])
|
||||||
|
|
||||||
|
await sleepAsync(3000.millis) # Give the algorithm some time to work its magic
|
||||||
|
|
||||||
|
let node1Enr = node2.wakuDiscv5.protocol.routingTable.buckets[0].nodes[0].record
|
||||||
|
let multiaddrs = node1Enr.get(MULTIADDR_ENR_FIELD, seq[byte])[].toMultiAddresses()
|
||||||
|
|
||||||
|
check:
|
||||||
|
node1.wakuDiscv5.protocol.nodesDiscovered > 0
|
||||||
|
node2.wakuDiscv5.protocol.nodesDiscovered > 0
|
||||||
|
multiaddrs.contains(expectedMultiAddr)
|
||||||
|
|
||||||
|
|
|
@ -103,7 +103,7 @@ procSuite "Waku Peer Exchange":
|
||||||
false,
|
false,
|
||||||
keys.PrivateKey(nodeKey1.skkey),
|
keys.PrivateKey(nodeKey1.skkey),
|
||||||
flags,
|
flags,
|
||||||
[], # Empty enr fields, for now
|
newSeq[MultiAddress](), # Empty multiaddr fields, for now
|
||||||
node1.rng
|
node1.rng
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -115,7 +115,7 @@ procSuite "Waku Peer Exchange":
|
||||||
false,
|
false,
|
||||||
keys.PrivateKey(nodeKey2.skkey),
|
keys.PrivateKey(nodeKey2.skkey),
|
||||||
flags,
|
flags,
|
||||||
[], # Empty enr fields, for now
|
newSeq[MultiAddress](), # Empty multiaddr fields, for now
|
||||||
node2.rng
|
node2.rng
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -112,18 +112,20 @@ proc new*(T: type WakuDiscoveryV5,
|
||||||
extTcpPort, extUdpPort: Option[Port],
|
extTcpPort, extUdpPort: Option[Port],
|
||||||
bindIP: ValidIpAddress,
|
bindIP: ValidIpAddress,
|
||||||
discv5UdpPort: Port,
|
discv5UdpPort: Port,
|
||||||
bootstrapEnrs: seq[enr.Record],
|
bootstrapEnrs = newSeq[enr.Record](),
|
||||||
enrAutoUpdate = false,
|
enrAutoUpdate = false,
|
||||||
privateKey: keys.PrivateKey,
|
privateKey: keys.PrivateKey,
|
||||||
flags: WakuEnrBitfield,
|
flags: WakuEnrBitfield,
|
||||||
enrFields: openArray[(string, seq[byte])],
|
multiaddrs = newSeq[MultiAddress](),
|
||||||
rng: ref HmacDrbgContext,
|
rng: ref HmacDrbgContext,
|
||||||
discv5Config: protocol.DiscoveryConfig = protocol.defaultDiscoveryConfig): T =
|
discv5Config: protocol.DiscoveryConfig = protocol.defaultDiscoveryConfig): T =
|
||||||
## TODO: consider loading from a configurable bootstrap file
|
## TODO: consider loading from a configurable bootstrap file
|
||||||
|
|
||||||
## We always add the waku field as specified
|
## We always add the waku field as specified
|
||||||
var enrInitFields = @[(WAKU_ENR_FIELD, @[flags.byte])]
|
var enrInitFields = @[(WAKU_ENR_FIELD, @[flags.byte])]
|
||||||
enrInitFields.add(enrFields)
|
|
||||||
|
## Add multiaddresses to ENR
|
||||||
|
enrInitFields.add((MULTIADDR_ENR_FIELD, multiaddrs.getRawField()))
|
||||||
|
|
||||||
let protocol = newProtocol(
|
let protocol = newProtocol(
|
||||||
privateKey,
|
privateKey,
|
||||||
|
@ -148,7 +150,7 @@ proc new*(T: type WakuDiscoveryV5,
|
||||||
enrAutoUpdate = false,
|
enrAutoUpdate = false,
|
||||||
privateKey: keys.PrivateKey,
|
privateKey: keys.PrivateKey,
|
||||||
flags: WakuEnrBitfield,
|
flags: WakuEnrBitfield,
|
||||||
enrFields: openArray[(string, seq[byte])],
|
multiaddrs = newSeq[MultiAddress](),
|
||||||
rng: ref HmacDrbgContext,
|
rng: ref HmacDrbgContext,
|
||||||
discv5Config: protocol.DiscoveryConfig = protocol.defaultDiscoveryConfig): T =
|
discv5Config: protocol.DiscoveryConfig = protocol.defaultDiscoveryConfig): T =
|
||||||
|
|
||||||
|
@ -164,7 +166,7 @@ proc new*(T: type WakuDiscoveryV5,
|
||||||
enrAutoUpdate,
|
enrAutoUpdate,
|
||||||
privateKey,
|
privateKey,
|
||||||
flags,
|
flags,
|
||||||
enrFields,
|
multiaddrs,
|
||||||
rng,
|
rng,
|
||||||
discv5Config
|
discv5Config
|
||||||
)
|
)
|
||||||
|
|
|
@ -131,38 +131,47 @@ template wsFlag(wssEnabled: bool): MultiAddress =
|
||||||
if wssEnabled: MultiAddress.init("/wss").tryGet()
|
if wssEnabled: MultiAddress.init("/wss").tryGet()
|
||||||
else: MultiAddress.init("/ws").tryGet()
|
else: MultiAddress.init("/ws").tryGet()
|
||||||
|
|
||||||
proc new*(T: type WakuNode,
|
type NetConfig* = object
|
||||||
nodeKey: crypto.PrivateKey,
|
hostAddress*: MultiAddress
|
||||||
bindIp: ValidIpAddress,
|
wsHostAddress*: Option[MultiAddress]
|
||||||
bindPort: Port,
|
hostExtAddress*: Option[MultiAddress]
|
||||||
extIp = none(ValidIpAddress),
|
wsExtAddress*: Option[MultiAddress]
|
||||||
extPort = none(Port),
|
wssEnabled*: bool
|
||||||
extMultiAddrs = newSeq[MultiAddress](),
|
extIp*: Option[ValidIpAddress]
|
||||||
peerStorage: PeerStorage = nil,
|
extPort*: Option[Port]
|
||||||
maxConnections = builders.MaxConnections,
|
dns4DomainName*: Option[string]
|
||||||
wsBindPort: Port = (Port)8000,
|
announcedAddresses*: seq[MultiAddress]
|
||||||
wsEnabled: bool = false,
|
extMultiAddrs*: seq[MultiAddress]
|
||||||
wssEnabled: bool = false,
|
enrMultiAddrs*: seq[MultiAddress]
|
||||||
secureKey: string = "",
|
enrIp*: Option[ValidIpAddress]
|
||||||
secureCert: string = "",
|
enrPort*: Option[Port]
|
||||||
wakuFlags = none(WakuEnrBitfield),
|
discv5UdpPort*: Option[Port]
|
||||||
nameResolver: NameResolver = nil,
|
wakuFlags*: Option[WakuEnrBitfield]
|
||||||
sendSignedPeerRecord = false,
|
bindIp*: ValidIpAddress
|
||||||
dns4DomainName = none(string),
|
bindPort*: Port
|
||||||
discv5UdpPort = none(Port),
|
|
||||||
agentString = none(string), # defaults to nim-libp2p version
|
|
||||||
peerStoreCapacity = none(int), # defaults to 1.25 maxConnections
|
|
||||||
# TODO: make this argument required after tests are updated
|
|
||||||
rng: ref HmacDrbgContext = crypto.newRng()
|
|
||||||
): T {.raises: [Defect, LPError, IOError, TLSStreamProtocolError].} =
|
|
||||||
## Creates a Waku Node instance.
|
|
||||||
|
|
||||||
|
proc init*(
|
||||||
|
T: type NetConfig,
|
||||||
|
bindIp: ValidIpAddress,
|
||||||
|
bindPort: Port,
|
||||||
|
extIp = none(ValidIpAddress),
|
||||||
|
extPort = none(Port),
|
||||||
|
extMultiAddrs = newSeq[MultiAddress](),
|
||||||
|
wsBindPort: Port = (Port)8000,
|
||||||
|
wsEnabled: bool = false,
|
||||||
|
wssEnabled: bool = false,
|
||||||
|
dns4DomainName = none(string),
|
||||||
|
discv5UdpPort = none(Port),
|
||||||
|
wakuFlags = none(WakuEnrBitfield)
|
||||||
|
): T {.raises: [LPError]} =
|
||||||
## Initialize addresses
|
## Initialize addresses
|
||||||
let
|
let
|
||||||
# Bind addresses
|
# Bind addresses
|
||||||
hostAddress = ip4TcpEndPoint(bindIp, bindPort)
|
hostAddress = ip4TcpEndPoint(bindIp, bindPort)
|
||||||
wsHostAddress = if wsEnabled or wssEnabled: some(ip4TcpEndPoint(bindIp, wsbindPort) & wsFlag(wssEnabled))
|
wsHostAddress = if wsEnabled or wssEnabled: some(ip4TcpEndPoint(bindIp, wsbindPort) & wsFlag(wssEnabled))
|
||||||
else: none(MultiAddress)
|
else: none(MultiAddress)
|
||||||
|
enrIp = if extIp.isSome(): extIp else: some(bindIp)
|
||||||
|
enrPort = if extPort.isSome(): extPort else: some(bindPort)
|
||||||
|
|
||||||
# Setup external addresses, if available
|
# Setup external addresses, if available
|
||||||
var
|
var
|
||||||
|
@ -198,25 +207,48 @@ proc new*(T: type WakuNode,
|
||||||
elif wsHostAddress.isSome():
|
elif wsHostAddress.isSome():
|
||||||
announcedAddresses.add(wsHostAddress.get())
|
announcedAddresses.add(wsHostAddress.get())
|
||||||
|
|
||||||
## Initialize peer
|
|
||||||
let
|
let
|
||||||
enrIp = if extIp.isSome(): extIp
|
|
||||||
else: some(bindIp)
|
|
||||||
enrTcpPort = if extPort.isSome(): extPort
|
|
||||||
else: some(bindPort)
|
|
||||||
# enrMultiaddrs are just addresses which cannot be represented in ENR, as described in
|
# enrMultiaddrs are just addresses which cannot be represented in ENR, as described in
|
||||||
# https://rfc.vac.dev/spec/31/#many-connection-types
|
# https://rfc.vac.dev/spec/31/#many-connection-types
|
||||||
enrMultiaddrs = announcedAddresses.filterIt(it.hasProtocol("dns4") or
|
enrMultiaddrs = announcedAddresses.filterIt(it.hasProtocol("dns4") or
|
||||||
it.hasProtocol("dns6") or
|
it.hasProtocol("dns6") or
|
||||||
it.hasProtocol("ws") or
|
it.hasProtocol("ws") or
|
||||||
it.hasProtocol("wss"))
|
it.hasProtocol("wss"))
|
||||||
enr = initEnr(nodeKey,
|
|
||||||
enrIp,
|
|
||||||
enrTcpPort,
|
|
||||||
discv5UdpPort,
|
|
||||||
wakuFlags,
|
|
||||||
enrMultiaddrs)
|
|
||||||
|
|
||||||
|
return NetConfig(
|
||||||
|
hostAddress: hostAddress,
|
||||||
|
wsHostAddress: wsHostAddress,
|
||||||
|
hostExtAddress: hostExtAddress,
|
||||||
|
wsExtAddress: wsExtAddress,
|
||||||
|
extIp: extIp,
|
||||||
|
extPort: extPort,
|
||||||
|
wssEnabled: wssEnabled,
|
||||||
|
dns4DomainName: dns4DomainName,
|
||||||
|
announcedAddresses: announcedAddresses,
|
||||||
|
extMultiAddrs: extMultiAddrs,
|
||||||
|
enrMultiaddrs: enrMultiaddrs,
|
||||||
|
enrIp: enrIp,
|
||||||
|
enrPort: enrPort,
|
||||||
|
discv5UdpPort: discv5UdpPort,
|
||||||
|
bindIp: bindIp,
|
||||||
|
bindPort: bindPort,
|
||||||
|
wakuFlags: wakuFlags)
|
||||||
|
|
||||||
|
|
||||||
|
proc getEnr*(netConfig: NetConfig,
|
||||||
|
wakuDiscV5 = none(WakuDiscoveryV5),
|
||||||
|
nodeKey: crypto.PrivateKey): enr.Record =
|
||||||
|
if wakuDiscV5.isSome():
|
||||||
|
return wakuDiscV5.get().protocol.getRecord()
|
||||||
|
|
||||||
|
return enr.Record.init(nodekey,
|
||||||
|
netConfig.enrIp,
|
||||||
|
netConfig.enrPort,
|
||||||
|
netConfig.discv5UdpPort,
|
||||||
|
netConfig.wakuFlags,
|
||||||
|
netConfig.enrMultiaddrs)
|
||||||
|
|
||||||
|
proc getAutonatService*(rng = crypto.newRng()): AutonatService =
|
||||||
## AutonatService request other peers to dial us back
|
## AutonatService request other peers to dial us back
|
||||||
## flagging us as Reachable or NotReachable.
|
## flagging us as Reachable or NotReachable.
|
||||||
## minConfidence is used as threshold to determine the state.
|
## minConfidence is used as threshold to determine the state.
|
||||||
|
@ -237,36 +269,107 @@ proc new*(T: type WakuNode,
|
||||||
|
|
||||||
autonatService.statusAndConfidenceHandler(statusAndConfidenceHandler)
|
autonatService.statusAndConfidenceHandler(statusAndConfidenceHandler)
|
||||||
|
|
||||||
info "Initializing networking", addrs=announcedAddresses
|
return autonatService
|
||||||
|
|
||||||
|
## retain old signature, but deprecate it
|
||||||
|
proc new*(T: type WakuNode,
|
||||||
|
nodeKey: crypto.PrivateKey,
|
||||||
|
bindIp: ValidIpAddress,
|
||||||
|
bindPort: Port,
|
||||||
|
extIp = none(ValidIpAddress),
|
||||||
|
extPort = none(Port),
|
||||||
|
extMultiAddrs = newSeq[MultiAddress](),
|
||||||
|
peerStorage: PeerStorage = nil,
|
||||||
|
maxConnections = builders.MaxConnections,
|
||||||
|
wsBindPort: Port = (Port)8000,
|
||||||
|
wsEnabled: bool = false,
|
||||||
|
wssEnabled: bool = false,
|
||||||
|
secureKey: string = "",
|
||||||
|
secureCert: string = "",
|
||||||
|
wakuFlags = none(WakuEnrBitfield),
|
||||||
|
nameResolver: NameResolver = nil,
|
||||||
|
sendSignedPeerRecord = false,
|
||||||
|
dns4DomainName = none(string),
|
||||||
|
discv5UdpPort = none(Port),
|
||||||
|
wakuDiscv5 = none(WakuDiscoveryV5),
|
||||||
|
agentString = none(string), # defaults to nim-libp2p version
|
||||||
|
peerStoreCapacity = none(int), # defaults to 1.25 maxConnections
|
||||||
|
# TODO: make this argument required after tests are updated
|
||||||
|
rng: ref HmacDrbgContext = crypto.newRng()
|
||||||
|
): T {.raises: [Defect, LPError, IOError, TLSStreamProtocolError], deprecated: "Use NetConfig variant".} =
|
||||||
|
let netConfig = NetConfig.init(
|
||||||
|
bindIp = bindIp,
|
||||||
|
bindPort = bindPort,
|
||||||
|
extIp = extIp,
|
||||||
|
extPort = extPort,
|
||||||
|
extMultiAddrs = extMultiAddrs,
|
||||||
|
wsBindPort = wsBindPort,
|
||||||
|
wsEnabled = wsEnabled,
|
||||||
|
wssEnabled = wssEnabled,
|
||||||
|
wakuFlags = wakuFlags,
|
||||||
|
dns4DomainName = dns4DomainName,
|
||||||
|
discv5UdpPort = discv5UdpPort,
|
||||||
|
)
|
||||||
|
|
||||||
|
return WakuNode.new(
|
||||||
|
nodeKey = nodeKey,
|
||||||
|
netConfig = netConfig,
|
||||||
|
peerStorage = peerStorage,
|
||||||
|
maxConnections = maxConnections,
|
||||||
|
secureKey = secureKey,
|
||||||
|
secureCert = secureCert,
|
||||||
|
nameResolver = nameResolver,
|
||||||
|
sendSignedPeerRecord = sendSignedPeerRecord,
|
||||||
|
wakuDiscv5 = wakuDiscv5,
|
||||||
|
agentString = agentString,
|
||||||
|
peerStoreCapacity = peerStoreCapacity,
|
||||||
|
)
|
||||||
|
|
||||||
|
proc new*(T: type WakuNode,
|
||||||
|
nodeKey: crypto.PrivateKey,
|
||||||
|
netConfig: NetConfig,
|
||||||
|
peerStorage: PeerStorage = nil,
|
||||||
|
maxConnections = builders.MaxConnections,
|
||||||
|
secureKey: string = "",
|
||||||
|
secureCert: string = "",
|
||||||
|
nameResolver: NameResolver = nil,
|
||||||
|
sendSignedPeerRecord = false,
|
||||||
|
wakuDiscv5 = none(WakuDiscoveryV5),
|
||||||
|
agentString = none(string), # defaults to nim-libp2p version
|
||||||
|
peerStoreCapacity = none(int), # defaults to 1.25 maxConnections
|
||||||
|
# TODO: make this argument required after tests are updated
|
||||||
|
rng: ref HmacDrbgContext = crypto.newRng()
|
||||||
|
): T {.raises: [Defect, LPError, IOError, TLSStreamProtocolError].} =
|
||||||
|
## Creates a Waku Node instance.
|
||||||
|
|
||||||
|
info "Initializing networking", addrs=netConfig.announcedAddresses
|
||||||
|
|
||||||
let switch = newWakuSwitch(
|
let switch = newWakuSwitch(
|
||||||
some(nodekey),
|
some(nodekey),
|
||||||
hostAddress,
|
address = netConfig.hostAddress,
|
||||||
wsHostAddress,
|
wsAddress = netConfig.wsHostAddress,
|
||||||
transportFlags = {ServerFlags.ReuseAddr},
|
transportFlags = {ServerFlags.ReuseAddr},
|
||||||
rng = rng,
|
rng = rng,
|
||||||
maxConnections = maxConnections,
|
maxConnections = maxConnections,
|
||||||
wssEnabled = wssEnabled,
|
wssEnabled = netConfig.wssEnabled,
|
||||||
secureKeyPath = secureKey,
|
secureKeyPath = secureKey,
|
||||||
secureCertPath = secureCert,
|
secureCertPath = secureCert,
|
||||||
nameResolver = nameResolver,
|
nameResolver = nameResolver,
|
||||||
sendSignedPeerRecord = sendSignedPeerRecord,
|
sendSignedPeerRecord = sendSignedPeerRecord,
|
||||||
agentString = agentString,
|
agentString = agentString,
|
||||||
peerStoreCapacity = peerStoreCapacity,
|
peerStoreCapacity = peerStoreCapacity,
|
||||||
services = @[Service(autonatservice)],
|
services = @[Service(getAutonatService(rng))],
|
||||||
)
|
)
|
||||||
|
|
||||||
let wakuNode = WakuNode(
|
return WakuNode(
|
||||||
peerManager: PeerManager.new(switch, peerStorage),
|
peerManager: PeerManager.new(switch, peerStorage),
|
||||||
switch: switch,
|
switch: switch,
|
||||||
rng: rng,
|
rng: rng,
|
||||||
enr: enr,
|
enr: netConfig.getEnr(wakuDiscv5, nodekey),
|
||||||
announcedAddresses: announcedAddresses
|
announcedAddresses: netConfig.announcedAddresses,
|
||||||
|
wakuDiscv5: if wakuDiscV5.isSome(): wakuDiscV5.get() else: nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
return wakuNode
|
|
||||||
|
|
||||||
|
|
||||||
proc peerInfo*(node: WakuNode): PeerInfo =
|
proc peerInfo*(node: WakuNode): PeerInfo =
|
||||||
node.switch.peerInfo
|
node.switch.peerInfo
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ proc init*(
|
||||||
addrs: addrs,
|
addrs: addrs,
|
||||||
enr: enr,
|
enr: enr,
|
||||||
protocols: protocols)
|
protocols: protocols)
|
||||||
|
|
||||||
return remotePeerInfo
|
return remotePeerInfo
|
||||||
|
|
||||||
proc init*(p: typedesc[RemotePeerInfo],
|
proc init*(p: typedesc[RemotePeerInfo],
|
||||||
|
@ -49,7 +49,7 @@ proc init*(p: typedesc[RemotePeerInfo],
|
||||||
enr: Option[enr.Record] = none(enr.Record),
|
enr: Option[enr.Record] = none(enr.Record),
|
||||||
protocols: seq[string] = @[]): RemotePeerInfo
|
protocols: seq[string] = @[]): RemotePeerInfo
|
||||||
{.raises: [Defect, ResultError[cstring], LPError].} =
|
{.raises: [Defect, ResultError[cstring], LPError].} =
|
||||||
|
|
||||||
let remotePeerInfo = RemotePeerInfo(
|
let remotePeerInfo = RemotePeerInfo(
|
||||||
peerId: PeerID.init(peerId).tryGet(),
|
peerId: PeerID.init(peerId).tryGet(),
|
||||||
addrs: addrs,
|
addrs: addrs,
|
||||||
|
@ -97,7 +97,7 @@ proc parseRemotePeerInfo*(address: string): RemotePeerInfo {.raises: [Defect, Va
|
||||||
|
|
||||||
# nim-libp2p dialing requires remote peers to be initialised with a peerId and a wire address
|
# nim-libp2p dialing requires remote peers to be initialised with a peerId and a wire address
|
||||||
let
|
let
|
||||||
peerIdStr = p2pPart.toString()[].split("/")[^1]
|
peerIdStr = p2pPart.toString()[].split("/")[^1]
|
||||||
|
|
||||||
wireAddr = nwPart & tcpPart & wsPart & wssPart
|
wireAddr = nwPart & tcpPart & wsPart & wssPart
|
||||||
if (not wireAddr.validWireAddr()):
|
if (not wireAddr.validWireAddr()):
|
||||||
|
@ -111,12 +111,12 @@ proc toRemotePeerInfo*(enr: enr.Record): Result[RemotePeerInfo, cstring] =
|
||||||
|
|
||||||
if not typedR.secp256k1.isSome:
|
if not typedR.secp256k1.isSome:
|
||||||
return err("enr: no secp256k1 key in record")
|
return err("enr: no secp256k1 key in record")
|
||||||
|
|
||||||
let
|
let
|
||||||
pubKey = ? keys.PublicKey.fromRaw(typedR.secp256k1.get)
|
pubKey = ? keys.PublicKey.fromRaw(typedR.secp256k1.get)
|
||||||
peerId = ? PeerID.init(crypto.PublicKey(scheme: Secp256k1,
|
peerId = ? PeerID.init(crypto.PublicKey(scheme: Secp256k1,
|
||||||
skkey: secp.SkPublicKey(pubKey)))
|
skkey: secp.SkPublicKey(pubKey)))
|
||||||
|
|
||||||
var addrs = newSeq[MultiAddress]()
|
var addrs = newSeq[MultiAddress]()
|
||||||
|
|
||||||
let transportProto = getTransportProtocol(typedR)
|
let transportProto = getTransportProtocol(typedR)
|
||||||
|
@ -182,3 +182,18 @@ proc hasProtocol*(ma: MultiAddress, proto: string): bool =
|
||||||
if p == MultiCodec.codec(proto):
|
if p == MultiCodec.codec(proto):
|
||||||
return true
|
return true
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
func hasUdpPort*(peer: RemotePeerInfo): bool =
|
||||||
|
if peer.enr.isNone():
|
||||||
|
return false
|
||||||
|
|
||||||
|
let
|
||||||
|
enr = peer.enr.get()
|
||||||
|
typedEnrRes = enr.toTypedRecord()
|
||||||
|
|
||||||
|
if typedEnrRes.isErr():
|
||||||
|
return false
|
||||||
|
|
||||||
|
let typedEnr = typedEnrRes.get()
|
||||||
|
typedEnr.udp.isSome() or typedEnr.udp6.isSome()
|
||||||
|
|
||||||
|
|
|
@ -34,21 +34,25 @@ type
|
||||||
Filter = 2,
|
Filter = 2,
|
||||||
Lightpush = 3,
|
Lightpush = 3,
|
||||||
|
|
||||||
func toFieldPair(multiaddrs: seq[MultiAddress]): FieldPair =
|
func getRawField*(multiaddrs: seq[MultiAddress]): seq[byte] =
|
||||||
## Converts a seq of multiaddrs to a `multiaddrs` ENR
|
|
||||||
## field pair according to https://rfc.vac.dev/spec/31/
|
|
||||||
|
|
||||||
var fieldRaw: seq[byte]
|
var fieldRaw: seq[byte]
|
||||||
|
|
||||||
for multiaddr in multiaddrs:
|
for multiaddr in multiaddrs:
|
||||||
let
|
let
|
||||||
maRaw = multiaddr.data.buffer # binary encoded multiaddr
|
maRaw = multiaddr.data.buffer # binary encoded multiaddr
|
||||||
maSize = maRaw.len.uint16.toBytes(Endianness.bigEndian) # size as Big Endian unsigned 16-bit integer
|
maSize = maRaw.len.uint16.toBytes(Endianness.bigEndian) # size as Big Endian unsigned 16-bit integer
|
||||||
|
|
||||||
assert maSize.len == 2
|
assert maSize.len == 2
|
||||||
|
|
||||||
fieldRaw.add(concat(@maSize, maRaw))
|
fieldRaw.add(concat(@maSize, maRaw))
|
||||||
|
|
||||||
|
return fieldRaw
|
||||||
|
|
||||||
|
func toFieldPair*(multiaddrs: seq[MultiAddress]): FieldPair =
|
||||||
|
## Converts a seq of multiaddrs to a `multiaddrs` ENR
|
||||||
|
## field pair according to https://rfc.vac.dev/spec/31/
|
||||||
|
let fieldRaw = multiaddrs.getRawField()
|
||||||
|
|
||||||
return toFieldPair(MULTIADDR_ENR_FIELD, fieldRaw)
|
return toFieldPair(MULTIADDR_ENR_FIELD, fieldRaw)
|
||||||
|
|
||||||
func stripPeerId(multiaddr: MultiAddress): MultiAddress =
|
func stripPeerId(multiaddr: MultiAddress): MultiAddress =
|
||||||
|
@ -58,10 +62,10 @@ func stripPeerId(multiaddr: MultiAddress): MultiAddress =
|
||||||
if item[].protoName()[] != "p2p":
|
if item[].protoName()[] != "p2p":
|
||||||
# Add all parts except p2p peerId
|
# Add all parts except p2p peerId
|
||||||
discard cleanAddr.append(item[])
|
discard cleanAddr.append(item[])
|
||||||
|
|
||||||
return cleanAddr
|
return cleanAddr
|
||||||
|
|
||||||
func stripPeerIds(multiaddrs: seq[MultiAddress]): seq[MultiAddress] =
|
func stripPeerIds*(multiaddrs: seq[MultiAddress]): seq[MultiAddress] =
|
||||||
var cleanAddrs: seq[MultiAddress]
|
var cleanAddrs: seq[MultiAddress]
|
||||||
|
|
||||||
for multiaddr in multiaddrs:
|
for multiaddr in multiaddrs:
|
||||||
|
@ -69,19 +73,19 @@ func stripPeerIds(multiaddrs: seq[MultiAddress]): seq[MultiAddress] =
|
||||||
cleanAddrs.add(multiaddr.stripPeerId())
|
cleanAddrs.add(multiaddr.stripPeerId())
|
||||||
else:
|
else:
|
||||||
cleanAddrs.add(multiaddr)
|
cleanAddrs.add(multiaddr)
|
||||||
|
|
||||||
return cleanAddrs
|
return cleanAddrs
|
||||||
|
|
||||||
func readBytes(rawBytes: seq[byte], numBytes: int, pos: var int = 0): Result[seq[byte], cstring] =
|
func readBytes(rawBytes: seq[byte], numBytes: int, pos: var int = 0): Result[seq[byte], cstring] =
|
||||||
## Attempts to read `numBytes` from a sequence, from
|
## Attempts to read `numBytes` from a sequence, from
|
||||||
## position `pos`. Returns the requested slice or
|
## position `pos`. Returns the requested slice or
|
||||||
## an error if `rawBytes` boundary is exceeded.
|
## an error if `rawBytes` boundary is exceeded.
|
||||||
##
|
##
|
||||||
## If successful, `pos` is advanced by `numBytes`
|
## If successful, `pos` is advanced by `numBytes`
|
||||||
|
|
||||||
if rawBytes[pos..^1].len() < numBytes:
|
if rawBytes[pos..^1].len() < numBytes:
|
||||||
return err("Exceeds maximum available bytes")
|
return err("Exceeds maximum available bytes")
|
||||||
|
|
||||||
let slicedSeq = rawBytes[pos..<pos+numBytes]
|
let slicedSeq = rawBytes[pos..<pos+numBytes]
|
||||||
pos += numBytes
|
pos += numBytes
|
||||||
|
|
||||||
|
@ -101,8 +105,8 @@ func initWakuFlags*(lightpush, filter, store, relay: bool): WakuEnrBitfield =
|
||||||
|
|
||||||
# TODO: With the changes in this PR, this can be refactored? Using the enum?
|
# TODO: With the changes in this PR, this can be refactored? Using the enum?
|
||||||
# Perhaps refactor to:
|
# Perhaps refactor to:
|
||||||
# WaKuEnr.initEnr(..., capabilities=[Store, Lightpush])
|
# WaKuEnr.enr.Record.init(..., capabilities=[Store, Lightpush])
|
||||||
# WaKuEnr.initEnr(..., capabilities=[Store, Lightpush, Relay, Filter])
|
# WaKuEnr.enr.Record.init(..., capabilities=[Store, Lightpush, Relay, Filter])
|
||||||
|
|
||||||
# Safer also since we dont inject WakuEnrBitfield, and we let this package
|
# Safer also since we dont inject WakuEnrBitfield, and we let this package
|
||||||
# handle the bits according to the capabilities
|
# handle the bits according to the capabilities
|
||||||
|
@ -141,12 +145,13 @@ func toMultiAddresses*(multiaddrsField: seq[byte]): seq[MultiAddress] =
|
||||||
|
|
||||||
return multiaddrs
|
return multiaddrs
|
||||||
|
|
||||||
func initEnr*(privateKey: crypto.PrivateKey,
|
func init*(T: type enr.Record,
|
||||||
enrIp: Option[ValidIpAddress],
|
privateKey: crypto.PrivateKey,
|
||||||
enrTcpPort, enrUdpPort: Option[Port],
|
enrIp: Option[ValidIpAddress],
|
||||||
wakuFlags = none(WakuEnrBitfield),
|
enrTcpPort, enrUdpPort: Option[Port],
|
||||||
multiaddrs: seq[MultiAddress] = @[]): enr.Record =
|
wakuFlags = none(WakuEnrBitfield),
|
||||||
|
multiaddrs: seq[MultiAddress] = @[]): T =
|
||||||
|
|
||||||
assert privateKey.scheme == PKScheme.Secp256k1
|
assert privateKey.scheme == PKScheme.Secp256k1
|
||||||
|
|
||||||
## Waku-specific ENR fields (https://rfc.vac.dev/spec/31/)
|
## Waku-specific ENR fields (https://rfc.vac.dev/spec/31/)
|
||||||
|
@ -166,14 +171,14 @@ func initEnr*(privateKey: crypto.PrivateKey,
|
||||||
enr = enr.Record.init(1, pk,
|
enr = enr.Record.init(1, pk,
|
||||||
enrIp, enrTcpPort, enrUdpPort,
|
enrIp, enrTcpPort, enrUdpPort,
|
||||||
wakuEnrFields).expect("Record within size limits")
|
wakuEnrFields).expect("Record within size limits")
|
||||||
|
|
||||||
return enr
|
return enr
|
||||||
|
|
||||||
proc supportsCapability*(r: Record, capability: Capabilities): bool =
|
proc supportsCapability*(r: Record, capability: Capabilities): bool =
|
||||||
let enrCapabilities = r.get(WAKU_ENR_FIELD, seq[byte])
|
let enrCapabilities = r.get(WAKU_ENR_FIELD, seq[byte])
|
||||||
if enrCapabilities.isOk():
|
if enrCapabilities.isOk():
|
||||||
return testBit(enrCapabilities.get()[0], capability.ord)
|
return testBit(enrCapabilities.get()[0], capability.ord)
|
||||||
return false
|
return false
|
||||||
|
|
||||||
proc getCapabilities*(r: Record): seq[Capabilities] =
|
proc getCapabilities*(r: Record): seq[Capabilities] =
|
||||||
return toSeq(Capabilities.low..Capabilities.high).filterIt(r.supportsCapability(it))
|
return toSeq(Capabilities.low..Capabilities.high).filterIt(r.supportsCapability(it))
|
||||||
|
|
Loading…
Reference in New Issue