nim-libp2p-experimental/tests/testmultiaddress.nim

461 lines
16 KiB
Nim

{.used.}
# Nim-Libp2p
# Copyright (c) 2023 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
# at your option.
# This file may not be copied, modified, or distributed except according to
# those terms.
{.push raises: [].}
import std/sequtils
import unittest2
import stew/byteutils
import ../libp2p/[multicodec, multiaddress]
type
PatternVector = object
pattern: MaPattern
good: seq[string]
bad: seq[string]
const
SuccessVectors = [
"/ip4/1.2.3.4",
"/ip4/0.0.0.0",
"/ip6/::1",
"/ip6/2601:9:4f81:9700:803e:ca65:66e8:c21",
"/ip6/2601:9:4f81:9700:803e:ca65:66e8:c21/udp/1234/quic",
"/ip6zone/x/ip6/fe80::1",
"/ip6zone/x%y/ip6/fe80::1",
"/ip6zone/x%y/ip6/::",
"/ip6zone/x/ip6/fe80::1/udp/1234/quic",
"/onion/timaq4ygg2iegci7:1234",
"/onion/timaq4ygg2iegci7:80/http",
"/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:1234",
"/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:80/http",
"/udp/0",
"/tcp/0",
"/sctp/0",
"/udp/1234",
"/tcp/1234",
"/sctp/1234",
"/udp/65535",
"/tcp/65535",
"/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
"/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
"/udp/1234/sctp/1234",
"/udp/1234/udt",
"/udp/1234/utp",
"/tcp/1234/http",
"/tcp/1234/https",
"/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234",
"/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234",
"/ip4/127.0.0.1/udp/1234",
"/ip4/127.0.0.1/udp/0",
"/ip4/127.0.0.1/tcp/1234",
"/ip4/127.0.0.1/tcp/1234/",
"/ip4/127.0.0.1/udp/1234/quic",
"/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
"/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234",
"/ip4/127.0.0.1/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
"/ip4/127.0.0.1/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234",
"/unix/a/b/c/d/e",
"/unix/stdio",
"/ip4/1.2.3.4/tcp/80/unix/a/b/c/d/e/f",
"/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234/unix/stdio",
"/ip4/127.0.0.1/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234/unix/stdio",
"/dns/example.io/udp/65535",
"/dns4/example.io/udp/65535",
"/dns6/example.io/udp/65535",
"/dnsaddr/example.io/udp/65535",
]
FailureVectors = [
"",
"/",
"/ip4",
"/ip4/::1",
"/ip4/fdpsofodsajfdoisa",
"/ip6",
"/ip6zone",
"/ip6zone/",
"/ip6zone//ip6/fe80::1",
"/udp",
"/tcp",
"/sctp",
"/udp/65536",
"/tcp/65536",
"/quic/65536",
"/onion/9imaq4ygg2iegci7:80",
"/onion/aaimaq4ygg2iegci7:80",
"/onion/timaq4ygg2iegci7:0",
"/onion/timaq4ygg2iegci7:-1",
"/onion/timaq4ygg2iegci7",
"/onion/timaq4ygg2iegci@:666",
"/onion3/9ww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:80",
"/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd7:80",
"/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:0",
"/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:-1",
"/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd",
"/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyy@:666",
"/udp/1234/sctp",
"/udp/1234/udt/1234",
"/udp/1234/utp/1234",
"/ip4/127.0.0.1/udp/jfodsajfidosajfoidsa",
"/ip4/127.0.0.1/udp",
"/ip4/127.0.0.1/tcp/jfodsajfidosajfoidsa",
"/ip4/127.0.0.1/tcp",
"/ip4/127.0.0.1/quic/1234",
"/ip4/127.0.0.1/ipfs",
"/ip4/127.0.0.1/ipfs/tcp",
"/ip4/127.0.0.1/p2p",
"/ip4/127.0.0.1/p2p/tcp",
"/unix"
]
RustSuccessVectors = [
"/ip4/1.2.3.4",
"/ip4/0.0.0.0",
"/ip6/::1",
"/ip6/2601:9:4f81:9700:803e:ca65:66e8:c21",
"/udp/0",
"/tcp/0",
"/sctp/0",
"/udp/1234",
"/tcp/1234",
"/sctp/1234",
"/udp/65535",
"/tcp/65535",
"/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
"/udp/1234/sctp/1234",
"/udp/1234/udt",
"/udp/1234/utp",
"/tcp/1234/http",
"/tcp/1234/https",
"/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234",
"/ip4/127.0.0.1/udp/1234",
"/ip4/127.0.0.1/udp/0",
"/ip4/127.0.0.1/tcp/1234",
"/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
"/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234",
"/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/tcp/8000/ws/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
"/p2p-webrtc-star/ip4/127.0.0.1/tcp/9090/ws/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
"/ip4/127.0.0.1/tcp/9090/p2p-circuit/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC"
]
RustSuccessExpects = [
"0401020304",
"0400000000",
"2900000000000000000000000000000001",
"29260100094F819700803ECA6566E80C21",
"91020000",
"060000",
"84010000",
"910204D2",
"0604D2",
"840104D2",
"9102FFFF",
"06FFFF",
"A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B",
"910204D2840104D2",
"910204D2AD02",
"910204D2AE02",
"0604D2E003",
"0604D2BB03",
"A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B0604D2",
"047F000001910204D2",
"047F00000191020000",
"047F0000010604D2",
"047F000001A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B",
"047F000001A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B0604D2",
"29200108A07AC542013AC986FFFE317095061F40DD03A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B",
"9302047F000001062382DD03A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B",
"047F000001062382A202A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B"
]
RustFailureVectors = [
"/ip4",
"/ip4/::1",
"/ip4/fdpsofodsajfdoisa",
"/ip6",
"/udp",
"/tcp",
"/sctp",
"/udp/65536",
"/tcp/65536",
"/onion/9imaq4ygg2iegci7:80",
"/onion/aaimaq4ygg2iegci7:80",
"/onion/timaq4ygg2iegci7:0",
"/onion/timaq4ygg2iegci7:-1",
"/onion/timaq4ygg2iegci7",
"/onion/timaq4ygg2iegci@:666",
"/onion3/9ww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:80",
"/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd7:80",
"/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:0",
"/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:-1",
"/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd",
"/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyy@:666",
"/udp/1234/sctp",
"/udp/1234/udt/1234",
"/udp/1234/utp/1234",
"/ip4/127.0.0.1/udp/jfodsajfidosajfoidsa",
"/ip4/127.0.0.1/udp",
"/ip4/127.0.0.1/tcp/jfodsajfidosajfoidsa",
"/ip4/127.0.0.1/tcp",
"/ip4/127.0.0.1/ipfs",
"/ip4/127.0.0.1/ipfs/tcp",
"/p2p-circuit/50"
]
PathVectors = [
"/unix/tmp/p2pd.sock",
"/unix/a/b/c/d/e/f/g/h/i.sock"
]
PathExpects = [
"90030E2F746D702F703270642E736F636B",
"9003172F612F622F632F642F652F662F672F682F692E736F636B"
]
PatternVectors = [
PatternVector(pattern: IP,
good: @["/ip4/0.0.0.0", "/ip6/fc00::"],
bad: @["/ip4/0.0.0.0/tcp/555", "/udp/789/ip6/fc00::"]
),
PatternVector(pattern: TCP,
good: @["/ip4/0.0.7.6/tcp/1234", "/ip6/::/tcp/0"],
bad: @["/tcp/12345", "/ip6/fc00::/udp/5523/tcp/9543"]
),
PatternVector(pattern: UDP,
good: @["/ip4/0.0.7.6/udp/1234", "/ip6/::/udp/0"],
bad: @["/udp/12345", "/ip6/fc00::/tcp/5523/udp/9543"],
),
PatternVector(pattern: UTP,
good: @["/ip4/1.2.3.4/udp/3456/utp", "/ip6/::/udp/0/utp"],
bad: @[
"/ip4/0.0.0.0/tcp/12345/utp",
"/ip6/fc00::/ip4/0.0.0.0/udp/1234/utp",
"/utp"
]
),
PatternVector(pattern: QUIC,
good: @["/ip4/1.2.3.4/udp/1234/quic", "/ip6/::/udp/1234/quic"],
bad: @[
"/ip4/0.0.0.0/tcp/12345/quic",
"/ip6/fc00::/ip4/0.0.0.0/udp/1234/quic",
"/quic"
]
),
PatternVector(pattern: IPFS,
good: @[
"/ip4/1.2.3.4/tcp/1234/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
"/ip6/::/tcp/1234/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
"/ip6/::/udp/1234/utp/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
"/ip4/0.0.0.0/udp/1234/utp/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
],
bad: @[
"/ip4/1.2.3.4/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
"/ip6/::/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
"/tcp/123/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
"/ip6/::/udp/1234/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
"/ip6/::/utp/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
"/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
]
),
PatternVector(pattern: DNS,
good: @["/dns/example.io", "/dnsaddr/example.io", "/dns4/example.io", "/dns6/example.io"],
bad: @["/ip4/127.0.0.1"],
),
PatternVector(pattern: WebRTCDirect,
good: @[
"/ip4/1.2.3.4/tcp/3456/http/p2p-webrtc-direct",
"/ip6/::/tcp/0/http/p2p-webrtc-direct"
],
bad: @[
"/ip4/0.0.0.0", "/ip6/fc00::", "/udp/12345",
"/ip6/fc00::/tcp/5523/udp/9543"
]
),
PatternVector(pattern: HTTP,
good: @[
"/ip4/1.2.3.4/http", "/dns4/example.io/http",
"/dns6/::/tcp/7011/http", "/dnsaddr/example.io/http",
"/ip6/fc00::/http"
],
bad: @[
"/ip4/1.2.3.4/https", "/ip4/0.0.0.0/tcp/12345/quic",
"/ip6/fc00::/tcp/5523"
]
),
PatternVector(pattern: HTTPS,
good: @[
"/ip4/1.2.3.4/https", "/dns4/example.io/https",
"/dns6/::/tcp/7011/https", "/ip6/fc00::/https"
],
bad: @[
"/ip4/1.2.3.4/http", "/ip4/0.0.0.0/tcp/12345/quic",
"/ip6/fc00::/tcp/5523"
]
)
]
suite "MultiAddress test suite":
test "go-multiaddr success test vectors":
for item in SuccessVectors:
var a = MultiAddress.init(item).get()
check a.isEmpty() == false
check a.validate() == true
test "go-multiaddr failure test vectors":
for item in FailureVectors:
check MultiAddress.init(item).isErr()
check MultiAddress.init(item.toBytes()).isErr()
test "rust-multiaddr success test vectors":
## Rust test vectors are with changed UDP encoding and without WSS
for i in 0..<len(RustSuccessVectors):
var a = MultiAddress.init(RustSuccessVectors[i]).get()
check:
hex(a) == RustSuccessExpects[i]
test "rust-multiaddr failure test vectors":
for item in RustFailureVectors:
check MultiAddress.init(item).isErr()
test "Concatenation test":
var ma1 = MultiAddress.init()
var ma2 = MultiAddress.init()
var ma3 = MultiAddress.init("/ip4/127.0.0.1").get()
var ma4 = MultiAddress.init("/udp/30000").get()
var ma5 = MultiAddress.init("/p2p-circuit").get()
var cma = ma1 & ma3 & ma4 & ma5
ma2 &= ma3
ma2 &= ma4
ma2 &= ma5
check:
$cma == "/ip4/127.0.0.1/udp/30000/p2p-circuit"
$ma2 == "/ip4/127.0.0.1/udp/30000/p2p-circuit"
test "Path addresses serialization/deserialization":
for i in 0..<len(PathVectors):
var a = MultiAddress.init(PathVectors[i]).get()
check:
hex(a) == PathExpects[i]
$a == PathVectors[i]
test "MultiAddress pattern matching test vectors":
for item in PatternVectors:
for gitem in item.good:
var a = MultiAddress.init(gitem).get()
check item.pattern.match(a) == true
for bitem in item.bad:
var a = MultiAddress.init(bitem).get()
check item.pattern.match(a) == false
test "MultiAddress init(\"tcp/udp/dccp/sctp\", int) test":
check:
$MultiAddress.init(multiCodec("tcp"), 0).get() == "/tcp/0"
$MultiAddress.init(multiCodec("tcp"), 65535).get() == "/tcp/65535"
$MultiAddress.init(multiCodec("tcp"), 34000).get() == "/tcp/34000"
$MultiAddress.init(multiCodec("udp"), 0).get() == "/udp/0"
$MultiAddress.init(multiCodec("udp"), 65535).get() == "/udp/65535"
$MultiAddress.init(multiCodec("udp"), 34000).get() == "/udp/34000"
$MultiAddress.init(multiCodec("dccp"), 0).get() == "/dccp/0"
$MultiAddress.init(multiCodec("dccp"), 65535).get() == "/dccp/65535"
$MultiAddress.init(multiCodec("dccp"), 34000).get() == "/dccp/34000"
$MultiAddress.init(multiCodec("sctp"), 0).get() == "/sctp/0"
$MultiAddress.init(multiCodec("sctp"), 65535).get() == "/sctp/65535"
$MultiAddress.init(multiCodec("sctp"), 34000).get() == "/sctp/34000"
check:
MultiAddress.init(multiCodec("ip4"), 0).isErr()
MultiAddress.init(multiCodec("ip6"), 0).isErr()
MultiAddress.init(multiCodec("p2p"), 0).isErr()
MultiAddress.init(multiCodec("tcp"), 65536).isErr()
MultiAddress.init(multiCodec("udp"), 65536).isErr()
MultiAddress.init(multiCodec("dccp"), 65536).isErr()
MultiAddress.init(multiCodec("sctp"), 65536).isErr()
MultiAddress.init(multiCodec("tcp"), -1).isErr()
MultiAddress.init(multiCodec("udp"), -1).isErr()
MultiAddress.init(multiCodec("dccp"), -1).isErr()
MultiAddress.init(multiCodec("sctp"), -1).isErr()
test "MultiAddress protoAddress(fixed) test":
var
address_v4: array[4, byte]
address_v6: array[16, byte]
check:
MultiAddress.init("/ip4/0.0.0.0").get().protoAddress().get() == address_v4
MultiAddress.init("/ip6/::0").get().protoAddress().get() == address_v6
test "MultiAddress getParts":
let ma = MultiAddress.init("/ip4/0.0.0.0/tcp/0/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/p2p-circuit/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSuNEXT/unix/stdio/").get()
check:
$ma[0..0].get() == "/ip4/0.0.0.0"
$ma[^1].get() == "/unix/stdio"
ma[-100].isErr()
ma[100].isErr()
ma[^100].isErr()
ma[^0].isErr()
$ma[0..1].get() == "/ip4/0.0.0.0/tcp/0"
$ma[1..2].get() == "/tcp/0/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC"
$ma[^3..^1].get() == "/p2p-circuit/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSuNEXT/unix/stdio"
ma[5..7].isErr()
test "[](MultiCodec) test":
let onionMAStr = "/onion3/torchdeedp3i2jigzjdmfpn5ttjhthh5wbmda2rr3jvqjg5p77c54dqd:80"
let ma = MultiAddress.init(onionMAStr).get()
check $(ma[multiCodec("onion3")].tryGet()) == onionMAStr
let onionMAWithTcpStr = "/onion3/torchdeedp3i2jigzjdmfpn5ttjhthh5wbmda2rr3jvqjg5p77c54dqd:80/tcp/80"
let maWithTcp = MultiAddress.init(onionMAWithTcpStr).get()
check $(maWithTcp[multiCodec("onion3")].tryGet()) == onionMAStr
test "matchPartial":
const
tcp = mapEq("tcp")
let ma = MultiAddress.init("/ip4/0.0.0.0/tcp/0").get()
check not tcp.matchPartial(ma)
check IP4.matchPartial(ma)
test "getRepeatedField does not fail when all addresses are valid":
var pb = initProtoBuffer()
let mas = SuccessVectors.mapIt(MultiAddress.init(it).get())
for ma in mas:
pb.write(1, ma)
pb.finish()
var decoded = newSeq[MultiAddress]()
check pb.getRepeatedField(1, decoded).isOk()
check decoded == mas
test "getRepeatedField does not fail when some addresses are invalid":
var pb = initProtoBuffer()
var mas = @[MultiAddress.init("/ip4/1.2.3.4" ).get(), MultiAddress()]
for ma in mas:
pb.write(1, ma)
pb.finish()
var decoded = newSeq[MultiAddress]()
check pb.getRepeatedField(1, decoded).isOk()
check decoded == @[MultiAddress.init("/ip4/1.2.3.4" ).get()]
test "getRepeatedField fails when all addresses are invalid":
var pb = initProtoBuffer()
var mas = @[MultiAddress(), MultiAddress()]
for ma in mas:
pb.write(1, ma)
pb.finish()
var decoded = newSeq[MultiAddress]()
let error = pb.getRepeatedField(1, decoded).error()
check error == ProtoError.IncorrectBlob
check decoded.len == 0