diff --git a/libp2pdht/private/eth/p2p/discoveryv5/protocol.nim b/libp2pdht/private/eth/p2p/discoveryv5/protocol.nim index fbd0ef3..2684053 100644 --- a/libp2pdht/private/eth/p2p/discoveryv5/protocol.nim +++ b/libp2pdht/private/eth/p2p/discoveryv5/protocol.nim @@ -222,12 +222,12 @@ func getRecord*(d: Protocol): SignedPeerRecord = ## Get the SPR of the local node. d.localNode.record -proc updateRecord*(d: Protocol): DiscResult[void] = +proc updateRecord*(d: Protocol, newSpr: SignedPeerRecord): DiscResult[void] = ## Update the ENR of the local node with provided `enrFields` k:v pairs. - # TODO: Do we need this proc? This simply serves so that seqNo will be - # incremented to satisfy the tests... - d.localNode.record.incSeqNo(d.privateKey) + info "Updated discovery SPR", uri=toURI(newSpr) + d.localNode.record = newSpr + ok() # TODO: Would it make sense to actively ping ("broadcast") to all the peers # we stored a handshake with in order to get that ENR updated? @@ -889,6 +889,7 @@ proc refreshLoop(d: Protocol) {.async.} = trace "refreshLoop canceled" proc ipMajorityLoop(d: Protocol) {.async.} = + #TODO this should be handled by libp2p, not the DHT ## When `enrAutoUpdate` is enabled, the IP:port combination returned ## by the majority will be used to update the local SPR. ## This should be safe as long as the routing table is not overwhelmed by @@ -1008,6 +1009,33 @@ proc newProtocol*( result.transport = newTransport(result, privKey, node, bindPort, bindIp, rng) +proc newProtocol*( + privKey: PrivateKey, + bindPort: Port, + record: SignedPeerRecord, + bootstrapRecords: openArray[SignedPeerRecord] = [], + bindIp = IPv4_any(), + config = defaultDiscoveryConfig, + rng = newRng()): + Protocol = + info "Discovery SPR initialized", seqNum = record.seqNum, uri = toURI(record) + let node = newNode(record).expect("Properly initialized record") + + # TODO Consider whether this should be a Defect + doAssert rng != nil, "RNG initialization failed" + + result = Protocol( + privateKey: privKey, + localNode: node, + bootstrapRecords: @bootstrapRecords, + ipVote: IpVote.init(), + enrAutoUpdate: false, #TODO this should be removed from nim-libp2p-dht + routingTable: RoutingTable.init( + node, config.bitsPerHop, config.tableIpLimits, rng), + rng: rng) + + result.transport = newTransport(result, privKey, node, bindPort, bindIp, rng) + proc open*(d: Protocol) {.raises: [Defect, CatchableError].} = info "Starting discovery node", node = d.localNode diff --git a/libp2pdht/private/eth/p2p/discoveryv5/spr.nim b/libp2pdht/private/eth/p2p/discoveryv5/spr.nim index f95c324..b55bc19 100644 --- a/libp2pdht/private/eth/p2p/discoveryv5/spr.nim +++ b/libp2pdht/private/eth/p2p/discoveryv5/spr.nim @@ -166,14 +166,14 @@ proc update*(r: var SignedPeerRecord, pk: crypto.PrivateKey, proc toTypedRecord*(r: SignedPeerRecord) : RecordResult[SignedPeerRecord] = ok(r) proc ip*(r: SignedPeerRecord): Option[array[4, byte]] = - let ma = r.data.addresses[0].address - - let code = ma[0].get.protoCode() - if code.isOk and code.get == multiCodec("ip4"): - var ipbuf: array[4, byte] - let res = ma[0].get.protoArgument(ipbuf) - if res.isOk: - return some(ipbuf) + for address in r.data.addresses: + let ma = address.address + let code = ma[0].get.protoCode() + if code.isOk and code.get == multiCodec("ip4"): + var ipbuf: array[4, byte] + let res = ma[0].get.protoArgument(ipbuf) + if res.isOk: + return some(ipbuf) # err("Incorrect IPv4 address") # else: @@ -188,15 +188,16 @@ proc ip*(r: SignedPeerRecord): Option[array[4, byte]] = # err("MultiAddress must be wire address (tcp, udp or unix)") proc udp*(r: SignedPeerRecord): Option[int] = - let ma = r.data.addresses[0].address + for address in r.data.addresses: + let ma = address.address - let code = ma[1].get.protoCode() - if code.isOk and code.get == multiCodec("udp"): - var pbuf: array[2, byte] - let res = ma[1].get.protoArgument(pbuf) - if res.isOk: - let p = fromBytesBE(uint16, pbuf) - return some(p.int) + let code = ma[1].get.protoCode() + if code.isOk and code.get == multiCodec("udp"): + var pbuf: array[2, byte] + let res = ma[1].get.protoArgument(pbuf) + if res.isOk: + let p = fromBytesBE(uint16, pbuf) + return some(p.int) proc fromBase64*(r: var SignedPeerRecord, s: string): bool = ## Loads SPR from base64-encoded protobuf-encoded bytes, and validates the