From fac507bda213ececfc6a17aeb116d8fa0bfc0936 Mon Sep 17 00:00:00 2001 From: Chrysostomos Nanakos Date: Mon, 15 Jun 2026 14:53:09 +0300 Subject: [PATCH] feat: Bump nim-libp2p to 2.0.0 and switch Mix... ...imports to the new standalone nim-libp2p-mix package. Also replace the binary mixNode_ pool format provided by the Mix implementation with a JSON file. Part of https://github.com/logos-storage/logos-storage-pm/issues/13 Signed-off-by: Chrysostomos Nanakos --- .gitmodules | 3 + storage.nim | 5 +- storage/conf.nim | 7 ++- storage/dht_proxy/client.nim | 2 +- storage/dht_proxy/protocol.nim | 2 +- storage/discovery.nim | 2 +- storage/storage.nim | 11 ++-- storage/utils/mixidentity.nim | 111 ++++++++++++++++++++++++++------- vendor/nim-libp2p-mix | 1 + 9 files changed, 110 insertions(+), 34 deletions(-) create mode 160000 vendor/nim-libp2p-mix diff --git a/.gitmodules b/.gitmodules index 8538670b..40792355 100644 --- a/.gitmodules +++ b/.gitmodules @@ -196,3 +196,6 @@ url = https://github.com/vacp2p/nim-lsquic.git ignore = untracked branch = main +[submodule "vendor/nim-libp2p-mix"] + path = vendor/nim-libp2p-mix + url = https://github.com/logos-co/nim-libp2p-mix diff --git a/storage.nim b/storage.nim index f1f4372a..aaff21ad 100644 --- a/storage.nim +++ b/storage.nim @@ -94,7 +94,10 @@ when isMainModule: else: config.dataDir / config.netPrivKeyFile - privateKey = setupKey(keyPath).expect("Should setup private key!") + privateKey = setupKey(keyPath).valueOr: + fatal "Failed to set up the network private key", + path = keyPath, err = error.msg + quit QuitFailure server = try: diff --git a/storage/conf.nim b/storage/conf.nim index fa6dc7e2..ee6c877a 100644 --- a/storage/conf.nim +++ b/storage/conf.nim @@ -213,10 +213,11 @@ type name: "mix-enabled" .}: bool - mixPoolDir* {. - desc: "Path to the Mix relay pool (expects `pubInfo/mixNode_` files inside)", + mixPool* {. + desc: + "Path to the Mix relay pool JSON file " & "(produced by the `mix_pool` tool).", defaultValue: "", - name: "mix-pool-dir" + name: "mix-pool" .}: string maxPeers* {. diff --git a/storage/dht_proxy/client.nim b/storage/dht_proxy/client.nim index 7455801e..676a42f4 100644 --- a/storage/dht_proxy/client.nim +++ b/storage/dht_proxy/client.nim @@ -16,7 +16,7 @@ import pkg/chronos import pkg/libp2p import pkg/libp2p/cid import pkg/libp2p/routing_record -import pkg/libp2p/protocols/mix +import pkg/libp2p_mix import ../errors import ../logutils diff --git a/storage/dht_proxy/protocol.nim b/storage/dht_proxy/protocol.nim index f4ea2734..c57bd34e 100644 --- a/storage/dht_proxy/protocol.nim +++ b/storage/dht_proxy/protocol.nim @@ -10,7 +10,7 @@ {.push raises: [].} import pkg/libp2p/protobuf/minprotobuf -import pkg/libp2p/protocols/mix +import pkg/libp2p_mix import pkg/libp2p/routing_record import ../logutils diff --git a/storage/discovery.nim b/storage/discovery.nim index 0a806ed0..f134b481 100644 --- a/storage/discovery.nim +++ b/storage/discovery.nim @@ -16,7 +16,7 @@ import std/sequtils import pkg/chronos import pkg/libp2p/[cid, multicodec, routing_record, signed_envelope] -import pkg/libp2p/protocols/mix +import pkg/libp2p_mix import pkg/questionable import pkg/questionable/results import pkg/contractabi/address as ca diff --git a/storage/storage.nim b/storage/storage.nim index ba72de2c..fabd0ded 100644 --- a/storage/storage.nim +++ b/storage/storage.nim @@ -17,7 +17,7 @@ import pkg/chronos import pkg/taskpools import pkg/presto import pkg/libp2p -import pkg/libp2p/protocols/mix +import pkg/libp2p_mix import pkg/confutils import pkg/confutils/defs import pkg/stew/io2 @@ -94,11 +94,14 @@ proc start*(s: StorageServer) {.async.} = mixPub, mixPriv, switch.peerInfo.peerId, mixAddr, switch.peerInfo.privateKey ).valueOr: raise newException(StorageError, "Failed to build Mix node info: " & error.msg) - relayPool = loadRelayPubInfoTable(s.config.mixPoolDir).valueOr: + relayPool = loadRelayPubInfoTable(s.config.mixPool).valueOr: raise newException(StorageError, "Failed to load Mix relay pool: " & error.msg) - mixProto = MixProtocol.new(mixNodeInfo, relayPool, switch) + mixProto = MixProtocol.new(mixNodeInfo, switch) - mixProto.registerDestReadBehavior(DhtProxyCodec, mix.readLp(MaxLookupResponseBytes)) + for info in relayPool.values: + mixProto.nodePool.add(info) + + mixProto.registerDestReadBehavior(DhtProxyCodec, readLp(MaxLookupResponseBytes)) await mixProto.start() switch.mount(mixProto) diff --git a/storage/utils/mixidentity.nim b/storage/utils/mixidentity.nim index 1b739340..49a9a273 100644 --- a/storage/utils/mixidentity.nim +++ b/storage/utils/mixidentity.nim @@ -9,17 +9,20 @@ {.push raises: [].} -import std/[os, tables] +import std/[json, os, tables] import pkg/libp2p import pkg/libp2p/crypto/crypto -import pkg/libp2p/protocols/mix -import pkg/libp2p/protocols/mix/[curve25519, mix_node] +import pkg/libp2p/crypto/secp +import pkg/libp2p_mix +import pkg/libp2p_mix/[curve25519, mix_node] import pkg/questionable/results import pkg/stew/byteutils import ../errors +const PoolFormatVersion = 1 + const MixIdentityFileSize = 2 * FieldElementSize proc pickMixCompatibleMultiAddr*(addrs: openArray[MultiAddress]): Opt[MultiAddress] = @@ -102,30 +105,92 @@ proc buildMixNodeInfo*( libp2pPrivKey = libp2pPriv.skkey, ) -proc loadRelayPubInfoTable*(mixPoolDir: string): ?!Table[PeerId, MixPubInfo] = - if mixPoolDir.len == 0: +proc pubInfoFromJson(node: JsonNode): ?!MixPubInfo = + if node.kind != JObject: + return failure("pool entry is not a JSON object") + + let + peerIdNode = node.getOrDefault("peerId") + multiAddrNode = node.getOrDefault("multiAddr") + mixPubKeyNode = node.getOrDefault("mixPubKey") + libp2pPubKeyNode = node.getOrDefault("libp2pPubKey") + + if peerIdNode.isNil: + return failure("pool entry missing field 'peerId'") + if multiAddrNode.isNil: + return failure("pool entry missing field 'multiAddr'") + if mixPubKeyNode.isNil: + return failure("pool entry missing field 'mixPubKey'") + if libp2pPubKeyNode.isNil: + return failure("pool entry missing field 'libp2pPubKey'") + + let + peerIdStr = peerIdNode.getStr() + multiAddrStr = multiAddrNode.getStr() + mixPubKeyHex = mixPubKeyNode.getStr() + libp2pPubKeyHex = libp2pPubKeyNode.getStr() + + let peerId = PeerId.init(peerIdStr).valueOr: + return failure("Invalid peerId in pool entry: " & peerIdStr & " (" & $error & ")") + + let multiAddr = MultiAddress.init(multiAddrStr).valueOr: + return + failure("Invalid multiAddr in pool entry: " & multiAddrStr & " (" & $error & ")") + + let mixPubKeyBytes = + try: + hexToSeqByte(mixPubKeyHex) + except ValueError as exc: + return failure("Invalid mixPubKey hex in pool entry: " & exc.msg) + let mixPubKey = bytesToFieldElement(mixPubKeyBytes).valueOr: + return failure("Invalid mixPubKey in pool entry: " & error) + + let libp2pPubKeyBytes = + try: + hexToSeqByte(libp2pPubKeyHex) + except ValueError as exc: + return failure("Invalid libp2pPubKey hex in pool entry: " & exc.msg) + let libp2pPubKey = SkPublicKey.init(libp2pPubKeyBytes).valueOr: + return failure("Invalid libp2pPubKey in pool entry: " & $error) + + success MixPubInfo.init(peerId, multiAddr, mixPubKey, libp2pPubKey) + +proc loadRelayPubInfoTable*(poolPath: string): ?!Table[PeerId, MixPubInfo] = + ## Expected format: + ## { "version": 1, "relays": [ { peerId, multiAddr, mixPubKey, libp2pPubKey }, ... ] } + if poolPath.len == 0: return success initTable[PeerId, MixPubInfo]() - let pubInfoDir = mixPoolDir / "pubInfo" - if not dirExists(pubInfoDir): - return failure("Relay pubInfo directory does not exist: " & pubInfoDir) + if not fileExists(poolPath): + return failure("Mix pool file does not exist: " & poolPath) - var - t = initTable[PeerId, MixPubInfo]() - i = 0 - while true: - let entry = - try: - MixPubInfo.readFromFile(i, pubInfoDir) - except IOError as exc: - return failure("I/O error reading pubInfo at index " & $i & ": " & exc.msg) - except OSError as exc: - return failure("OS error reading pubInfo at index " & $i & ": " & exc.msg) - if entry.isErr: - break - let info = entry.get() + let raw = + try: + readFile(poolPath) + except IOError as exc: + return failure("Failed to read pool " & poolPath & ": " & exc.msg) + + let parsed = + try: + parseJson(raw) + except CatchableError as exc: + return failure("Failed to parse pool JSON: " & exc.msg) + + let versionNode = parsed.getOrDefault("version") + if versionNode.isNil or versionNode.getInt() != PoolFormatVersion: + return failure( + "Unsupported pool version (expected " & $PoolFormatVersion & " in " & poolPath & + ")" + ) + + let relaysNode = parsed.getOrDefault("relays") + if relaysNode.isNil or relaysNode.kind != JArray: + return failure("Pool file missing 'relays' array: " & poolPath) + + var t = initTable[PeerId, MixPubInfo]() + for entry in relaysNode: + let info = ?pubInfoFromJson(entry) t[info.peerId] = info - inc i success t diff --git a/vendor/nim-libp2p-mix b/vendor/nim-libp2p-mix new file mode 160000 index 00000000..fc220354 --- /dev/null +++ b/vendor/nim-libp2p-mix @@ -0,0 +1 @@ +Subproject commit fc22035416ac3df258e043ad8a53cf929f225e9d