diff --git a/codex/codex.nim b/codex/codex.nim index 458a63ff..be85bf59 100644 --- a/codex/codex.nim +++ b/codex/codex.nim @@ -100,14 +100,10 @@ proc new*(T: type CodexServer, config: CodexConf): T = PrivateKey.init(bytes).expect("valid key bytes") - let - addresses = - config.listenPorts.mapIt(MultiAddress.init("/ip4/" & $config.listenIp & "/tcp/" & $(it.int)).tryGet()) & - @[MultiAddress.init("/ip4/" & $config.listenIp & "/udp/" & $(config.discoveryPort.int)).tryGet()] switch = SwitchBuilder .new() .withPrivateKey(privateKey) - .withAddresses(addresses) + .withAddresses(config.listenAddrs) .withRng(Rng.instance()) .withNoise() .withMplex(5.minutes, 5.minutes) @@ -124,15 +120,22 @@ proc new*(T: type CodexServer, config: CodexConf): T = cache = CacheStore.new(cacheSize = config.cacheSize * MiB) let - discoveryBootstrapNodes = config.bootstrapNodes discoveryStore = Datastore(SQLiteDatastore.new( config.dataDir / "dht") .expect("Should not fail!")) + + announceAddrs = + if config.announceAddrs.len <= 0: + config.announceAddrs + else: + config.listenAddrs + blockDiscovery = Discovery.new( - switch.peerInfo, - discoveryPort = config.discoveryPort, - bootstrapNodes = discoveryBootstrapNodes, - store = discoveryStore) + switch.peerInfo.privateKey, + announceAddrs = config.announceAddrs, + discoveryPort = config.discoveryPort, + bootstrapNodes = config.bootstrapNodes, + store = discoveryStore) wallet = WalletRef.new(EthPrivateKey.random()) network = BlockExcNetwork.new(switch) diff --git a/codex/conf.nim b/codex/conf.nim index da25a4d8..57008153 100644 --- a/codex/conf.nim +++ b/codex/conf.nim @@ -85,22 +85,21 @@ type defaultValue: noCommand }: StartUpCommand of noCommand: - listenPorts* {. - desc: "Specifies one or more listening ports for the node to listen on." - defaultValue: @[Port(0)] - defaultValueDesc: "0" - abbr: "l" - name: "listen-port" }: seq[Port] - - # TODO We should have two options: the listen IP and the public IP - # Currently, they are tied together, so we can't be discoverable - # behind a NAT - listenIp* {. - desc: "The public IP" - defaultValue: ValidIpAddress.init("0.0.0.0") - defaultValueDesc: "0.0.0.0" + listenAddrs* {. + desc: "Multi Addresses to listen on" + defaultValue: @[ + MultiAddress.init("/ip4/0.0.0.0/tcp/0") + .expect("Should init multiaddress")] + defaultValueDesc: "/ip4/0.0.0.0/tcp/0" abbr: "i" - name: "listen-ip" }: ValidIpAddress + name: "listen-addrs" }: seq[MultiAddress] + + announceAddrs* {. + desc: "Multi Addresses to announce behind a NAT" + defaultValue: @[] + defaultValueDesc: "" + abbr: "a" + name: "announce-addrs" }: seq[MultiAddress] discoveryPort* {. desc: "Specify the discovery (UDP) port" diff --git a/codex/discovery.nim b/codex/discovery.nim index f2135bae..4f6a424d 100644 --- a/codex/discovery.nim +++ b/codex/discovery.nim @@ -33,25 +33,9 @@ export discv5 type Discovery* = ref object of RootObj protocol: discv5.Protocol - localInfo: PeerInfo - -proc new*( - T: type Discovery, - localInfo: PeerInfo, - discoveryPort = 0.Port, - bootstrapNodes: seq[SignedPeerRecord] = @[], - store: Datastore = SQLiteDatastore.new(Memory) - .expect("Should not fail!")): T = - - T( - protocol: newProtocol( - localInfo.privateKey, - bindPort = discoveryPort, - record = localInfo.signedPeerRecord, - bootstrapRecords = bootstrapNodes, - rng = Rng.instance(), - providers = ProvidersManager.new(store)), - localInfo: localInfo) + key: PrivateKey + announceAddrs: seq[MultiAddress] + record: SignedPeerRecord proc toNodeId*(cid: Cid): NodeId = ## Cid to discovery id @@ -97,8 +81,7 @@ method provide*(d: Discovery, cid: Cid) {.async, base.} = trace "Providing block", cid let nodes = await d.protocol.addProvider( - cid.toNodeId(), - d.localInfo.signedPeerRecord) + cid.toNodeId(), d.record) if nodes.len <= 0: trace "Couldn't provide to any nodes!" @@ -133,25 +116,72 @@ method provide*(d: Discovery, host: ca.Address) {.async, base.} = trace "Providing host", host = $host let nodes = await d.protocol.addProvider( - host.toNodeId(), - d.localInfo.signedPeerRecord) + host.toNodeId(), d.record) if nodes.len > 0: trace "Provided to nodes", nodes = nodes.len -method removeProvider*(d: Discovery, peerId: PeerId): Future[void] = +method removeProvider*(d: Discovery, peerId: PeerId): Future[void] {.base.} = ## Remove provider from providers table ## trace "Removing provider", peerId d.protocol.removeProvidersLocal(peerId) -proc start*(d: Discovery) {.async.} = - d.protocol.updateRecord( - d.localInfo.signedPeerRecord.some) - .expect("updating SPR") +proc updateRecord*(d: Discovery, addrs: openArray[MultiAddress]) = + ## Update providers record + ## + d.announceAddrs = @addrs + d.record = SignedPeerRecord.init( + d.key, + PeerRecord.init( + PeerId.init(d.key).expect("Should construct PeerId"), + d.announceAddrs)).expect("Should construct signed record") + + if not d.protocol.isNil: + d.protocol.updateRecord(d.record.some) + .expect("should update SPR") + +proc start*(d: Discovery) {.async.} = d.protocol.open() await d.protocol.start() proc stop*(d: Discovery) {.async.} = await d.protocol.closeWait() + +proc new*( + T: type Discovery, + key: PrivateKey, + discoveryIp = IPv4_any(), + discoveryPort = 0.Port, + announceAddrs: openArray[MultiAddress] = [], + bootstrapNodes: openArray[SignedPeerRecord] = [], + store: Datastore = SQLiteDatastore.new(Memory) + .expect("Should not fail!")): T = + + let + announceAddrs = + if announceAddrs.len <= 0: + @[ + MultiAddress.init( + ValidIpAddress.init(discoveryIp), + IpTransportProtocol.tcpProtocol, + discoveryPort)] + else: + @announceAddrs + + var + self = T(key: key) + + self.updateRecord(announceAddrs) + + self.protocol = newProtocol( + key, + bindIp = discoveryIp, + bindPort = discoveryPort, + record = self.record, + bootstrapRecords = bootstrapNodes, + rng = Rng.instance(), + providers = ProvidersManager.new(store)) + + self diff --git a/tests/codex/helpers/nodeutils.nim b/tests/codex/helpers/nodeutils.nim index a792aa81..978f20c5 100644 --- a/tests/codex/helpers/nodeutils.nim +++ b/tests/codex/helpers/nodeutils.nim @@ -29,26 +29,26 @@ proc generateNodes*( for i in 0..