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_<i> 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 <chris@include.gr>
This commit is contained in:
Chrysostomos Nanakos 2026-06-15 14:53:09 +03:00
parent cefd06371e
commit fac507bda2
No known key found for this signature in database
9 changed files with 110 additions and 34 deletions

3
.gitmodules vendored
View File

@ -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

View File

@ -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:

View File

@ -213,10 +213,11 @@ type
name: "mix-enabled"
.}: bool
mixPoolDir* {.
desc: "Path to the Mix relay pool (expects `pubInfo/mixNode_<i>` 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* {.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

1
vendor/nim-libp2p-mix vendored Submodule

@ -0,0 +1 @@
Subproject commit fc22035416ac3df258e043ad8a53cf929f225e9d