Less exceptions more results (#188)

* Less exceptions more results

* Fix daemonapi and interop tests

* Add multibase

* wip multiaddress

* fix the build, consuming new result types

* fix standard setup

* Simplify match, rename into MaError, add more exaustive err text

* Fix the CI issues

* Fix directchat build

* daemon api fixes

* better err messages formatting

Co-authored-by: Zahary Karadjov <zahary@gmail.com>
This commit is contained in:
Giovanni Petrantoni 2020-05-31 23:22:49 +09:00 committed by GitHub
parent 7c9e5c2f7a
commit 6affcda937
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 605 additions and 539 deletions

View File

@ -41,11 +41,11 @@ type ChatProto = ref object of LPProtocol
proc initAddress(T: type MultiAddress, str: string): T = proc initAddress(T: type MultiAddress, str: string): T =
let address = MultiAddress.init(str) let address = MultiAddress.init(str).tryGet()
if IPFS.match(address) and matchPartial(multiaddress.TCP, address): if IPFS.match(address) and matchPartial(multiaddress.TCP, address):
result = address result = address
else: else:
raise newException(MultiAddressError, raise newException(ValueError,
"Invalid bootstrap node multi-address") "Invalid bootstrap node multi-address")
proc dialPeer(p: ChatProto, address: string) {.async.} = proc dialPeer(p: ChatProto, address: string) {.async.} =
@ -160,10 +160,10 @@ proc processInput(rfd: AsyncFD) {.async.} =
let a = await transp.readLine() let a = await transp.readLine()
try: try:
if a.len > 0: if a.len > 0:
peerInfo.addrs.add(Multiaddress.init(a)) peerInfo.addrs.add(Multiaddress.init(a).tryGet())
break break
peerInfo.addrs.add(Multiaddress.init(localAddress)) peerInfo.addrs.add(Multiaddress.init(localAddress).tryGet())
break break
except: except:
echo "invalid address" echo "invalid address"

View File

@ -130,7 +130,7 @@ proc decode(data: openarray[char], cid: var Cid): CidStatus =
proc validate*(ctype: typedesc[Cid], data: openarray[byte]): bool = proc validate*(ctype: typedesc[Cid], data: openarray[byte]): bool =
## Returns ``true`` is data has valid binary CID representation. ## Returns ``true`` is data has valid binary CID representation.
var version, codec: uint64 var version, codec: uint64
var res: VarintStatus var res: VarintResult[void]
if len(data) < 2: if len(data) < 2:
return false return false
let last = data.high let last = data.high
@ -140,7 +140,7 @@ proc validate*(ctype: typedesc[Cid], data: openarray[byte]): bool =
var offset = 0 var offset = 0
var length = 0 var length = 0
res = LP.getUVarint(data.toOpenArray(offset, last), length, version) res = LP.getUVarint(data.toOpenArray(offset, last), length, version)
if res != VarintStatus.Success: if res.isErr():
return false return false
if version != 1'u64: if version != 1'u64:
return false return false
@ -148,7 +148,7 @@ proc validate*(ctype: typedesc[Cid], data: openarray[byte]): bool =
if offset >= len(data): if offset >= len(data):
return false return false
res = LP.getUVarint(data.toOpenArray(offset, last), length, codec) res = LP.getUVarint(data.toOpenArray(offset, last), length, codec)
if res != VarintStatus.Success: if res.isErr():
return false return false
var mcodec = CodeContentIds.getOrDefault(cast[int](codec), InvalidMultiCodec) var mcodec = CodeContentIds.getOrDefault(cast[int](codec), InvalidMultiCodec)
if mcodec == InvalidMultiCodec: if mcodec == InvalidMultiCodec:
@ -253,11 +253,11 @@ proc encode*(mbtype: typedesc[MultiBase], encoding: string,
cid: Cid): string {.inline.} = cid: Cid): string {.inline.} =
## Get MultiBase encoded representation of ``cid`` using encoding ## Get MultiBase encoded representation of ``cid`` using encoding
## ``encoding``. ## ``encoding``.
result = MultiBase.encode(encoding, cid.data.buffer) result = MultiBase.encode(encoding, cid.data.buffer).tryGet()
proc `$`*(cid: Cid): string = proc `$`*(cid: Cid): string =
## Return official string representation of content identifier ``cid``. ## Return official string representation of content identifier ``cid``.
if cid.cidver == CIDv0: if cid.cidver == CIDv0:
result = BTCBase58.encode(cid.data.buffer) result = BTCBase58.encode(cid.data.buffer)
elif cid.cidver == CIDv1: elif cid.cidver == CIDv1:
result = Multibase.encode("base58btc", cid.data.buffer) result = Multibase.encode("base58btc", cid.data.buffer).tryGet()

View File

@ -82,7 +82,7 @@ proc init*(sig: var SkSignature, data: string): SkResult[void] =
try: try:
buffer = hexToSeqByte(data) buffer = hexToSeqByte(data)
except ValueError: except ValueError:
return err("Hex to bytes failed") return err("secp: Hex to bytes failed")
init(sig, buffer) init(sig, buffer)
proc init*(t: typedesc[SkPrivateKey], data: openarray[byte]): SkResult[SkPrivateKey] = proc init*(t: typedesc[SkPrivateKey], data: openarray[byte]): SkResult[SkPrivateKey] =
@ -145,7 +145,7 @@ proc toBytes*(key: SkPrivateKey, data: var openarray[byte]): SkResult[int] =
data[0..<SkRawPrivateKeySize] = SkSecretKey(key).toRaw() data[0..<SkRawPrivateKeySize] = SkSecretKey(key).toRaw()
ok(SkRawPrivateKeySize) ok(SkRawPrivateKeySize)
else: else:
err("Not enough bytes") err("secp: Not enough bytes")
proc toBytes*(key: SkPublicKey, data: var openarray[byte]): SkResult[int] = proc toBytes*(key: SkPublicKey, data: var openarray[byte]): SkResult[int] =
## Serialize Secp256k1 `public key` ``key`` to raw binary form and store it ## Serialize Secp256k1 `public key` ``key`` to raw binary form and store it
@ -157,7 +157,7 @@ proc toBytes*(key: SkPublicKey, data: var openarray[byte]): SkResult[int] =
data[0..<SkRawPublicKeySize] = secp256k1.SkPublicKey(key).toRawCompressed() data[0..<SkRawPublicKeySize] = secp256k1.SkPublicKey(key).toRawCompressed()
ok(SkRawPublicKeySize) ok(SkRawPublicKeySize)
else: else:
err("Not enough bytes") err("secp: Not enough bytes")
proc toBytes*(sig: SkSignature, data: var openarray[byte]): int = proc toBytes*(sig: SkSignature, data: var openarray[byte]): int =
## Serialize Secp256k1 `signature` ``sig`` to raw binary form and store it ## Serialize Secp256k1 `signature` ``sig`` to raw binary form and store it

View File

@ -474,15 +474,15 @@ proc recvMessage(conn: StreamTransport): Future[seq[byte]] {.async.} =
var var
size: uint size: uint
length: int length: int
res: VarintStatus res: VarintResult[void]
var buffer = newSeq[byte](10) var buffer = newSeq[byte](10)
try: try:
for i in 0..<len(buffer): for i in 0..<len(buffer):
await conn.readExactly(addr buffer[i], 1) await conn.readExactly(addr buffer[i], 1)
res = PB.getUVarint(buffer.toOpenArray(0, i), length, size) res = PB.getUVarint(buffer.toOpenArray(0, i), length, size)
if res == VarintStatus.Success: if res.isOk():
break break
if res != VarintStatus.Success or size > MaxMessageSize: if res.isErr() or size > MaxMessageSize:
buffer.setLen(0) buffer.setLen(0)
result = buffer result = buffer
return return
@ -521,27 +521,27 @@ proc getSocket(pattern: string,
var sockname = "" var sockname = ""
var pid = $getProcessId() var pid = $getProcessId()
sockname = pattern % [pid, $(count[])] sockname = pattern % [pid, $(count[])]
let tmpma = MultiAddress.init(sockname) let tmpma = MultiAddress.init(sockname).tryGet()
if UNIX.match(tmpma): if UNIX.match(tmpma):
while true: while true:
count[] = count[] + 1 count[] = count[] + 1
sockname = pattern % [pid, $(count[])] sockname = pattern % [pid, $(count[])]
var ma = MultiAddress.init(sockname) var ma = MultiAddress.init(sockname).tryGet()
let res = await socketExists(ma) let res = await socketExists(ma)
if not res: if not res:
result = ma result = ma
break break
elif TCP.match(tmpma): elif TCP.match(tmpma):
sockname = pattern % [pid, "0"] sockname = pattern % [pid, "0"]
var ma = MultiAddress.init(sockname) var ma = MultiAddress.init(sockname).tryGet()
var sock = createAsyncSocket(ma) var sock = createAsyncSocket(ma)
if sock.bindAsyncSocket(ma): if sock.bindAsyncSocket(ma):
# Socket was successfully bound, then its free to use # Socket was successfully bound, then its free to use
count[] = count[] + 1 count[] = count[] + 1
var ta = sock.getLocalAddress() var ta = sock.getLocalAddress()
sockname = pattern % [pid, $ta.port] sockname = pattern % [pid, $ta.port]
result = MultiAddress.init(sockname) result = MultiAddress.init(sockname).tryGet()
closeSocket(sock) closeSocket(sock)
# This is forward declaration needed for newDaemonApi() # This is forward declaration needed for newDaemonApi()
@ -649,7 +649,7 @@ proc newDaemonApi*(flags: set[P2PDaemonFlags] = {},
api.flags.excl(NoProcessCtrl) api.flags.excl(NoProcessCtrl)
api.address = await getSocket(patternForSocket, addr daemonsCount) api.address = await getSocket(patternForSocket, addr daemonsCount)
else: else:
api.address = MultiAddress.init(sockpath) api.address = MultiAddress.init(sockpath).tryGet()
api.flags.incl(NoProcessCtrl) api.flags.incl(NoProcessCtrl)
let res = await socketExists(api.address) let res = await socketExists(api.address)
if not res: if not res:
@ -830,7 +830,7 @@ proc getPeerInfo(pb: var ProtoBuffer): PeerInfo =
while pb.getBytes(2, address) != -1: while pb.getBytes(2, address) != -1:
if len(address) != 0: if len(address) != 0:
var copyaddr = address var copyaddr = address
result.addresses.add(MultiAddress.init(copyaddr)) result.addresses.add(MultiAddress.init(copyaddr).tryGet())
address.setLen(0) address.setLen(0)
proc identity*(api: DaemonAPI): Future[PeerInfo] {.async.} = proc identity*(api: DaemonAPI): Future[PeerInfo] {.async.} =
@ -888,7 +888,7 @@ proc openStream*(api: DaemonAPI, peer: PeerID,
raise newException(DaemonLocalError, "Missing `peer` field!") raise newException(DaemonLocalError, "Missing `peer` field!")
if pb.getLengthValue(2, raddress) == -1: if pb.getLengthValue(2, raddress) == -1:
raise newException(DaemonLocalError, "Missing `address` field!") raise newException(DaemonLocalError, "Missing `address` field!")
stream.raddress = MultiAddress.init(raddress) stream.raddress = MultiAddress.init(raddress).tryGet()
if pb.getLengthValue(3, stream.protocol) == -1: if pb.getLengthValue(3, stream.protocol) == -1:
raise newException(DaemonLocalError, "Missing `proto` field!") raise newException(DaemonLocalError, "Missing `proto` field!")
stream.flags.incl(Outbound) stream.flags.incl(Outbound)
@ -909,7 +909,7 @@ proc streamHandler(server: StreamServer, transp: StreamTransport) {.async.} =
raise newException(DaemonLocalError, "Missing `peer` field!") raise newException(DaemonLocalError, "Missing `peer` field!")
if pb.getLengthValue(2, raddress) == -1: if pb.getLengthValue(2, raddress) == -1:
raise newException(DaemonLocalError, "Missing `address` field!") raise newException(DaemonLocalError, "Missing `address` field!")
stream.raddress = MultiAddress.init(raddress) stream.raddress = MultiAddress.init(raddress).tryGet()
if pb.getLengthValue(3, stream.protocol) == -1: if pb.getLengthValue(3, stream.protocol) == -1:
raise newException(DaemonLocalError, "Missing `proto` field!") raise newException(DaemonLocalError, "Missing `proto` field!")
stream.flags.incl(Inbound) stream.flags.incl(Inbound)

View File

@ -8,14 +8,16 @@
## those terms. ## those terms.
## This module implements MultiAddress. ## This module implements MultiAddress.
{.push raises: [Defect].}
import nativesockets import nativesockets
import tables, strutils, net import tables, strutils, net
import chronos import chronos
import multicodec, multihash, multibase, transcoder, vbuffer import multicodec, multihash, multibase, transcoder, vbuffer
import stew/[base58, base32, endians2] import stew/[base58, base32, endians2, results]
from peer import PeerID from peer import PeerID
export results
{.deadCodeElim:on.}
type type
MAKind* = enum MAKind* = enum
@ -42,7 +44,13 @@ type
flag*: bool flag*: bool
rem*: seq[MultiCodec] rem*: seq[MultiCodec]
MultiAddressError* = object of CatchableError MaResult*[T] = Result[T, string]
const
# These are needed in order to avoid an ambiguity error stemming from
# some cint constants with the same name defined in the posix modules
IPPROTO_TCP = Protocol.IPPROTO_TCP
IPPROTO_UDP = Protocol.IPPROTO_UDP
proc ip4StB(s: string, vb: var VBuffer): bool = proc ip4StB(s: string, vb: var VBuffer): bool =
## IPv4 stringToBuffer() implementation. ## IPv4 stringToBuffer() implementation.
@ -438,33 +446,35 @@ proc shcopy*(m1: var MultiAddress, m2: MultiAddress) =
m1.data.offset = m2.data.offset m1.data.offset = m2.data.offset
m1.data.length = m2.data.length m1.data.length = m2.data.length
proc protoCode*(ma: MultiAddress): MultiCodec = proc protoCode*(ma: MultiAddress): MaResult[MultiCodec] =
## Returns MultiAddress ``ma`` protocol code. ## Returns MultiAddress ``ma`` protocol code.
var header: uint64 var header: uint64
var vb: MultiAddress var vb: MultiAddress
shcopy(vb, ma) shcopy(vb, ma)
if vb.data.readVarint(header) == -1: if vb.data.readVarint(header) == -1:
raise newException(MultiAddressError, "Malformed binary address!") err("multiaddress: Malformed binary address!")
else:
let proto = CodeAddresses.getOrDefault(MultiCodec(header)) let proto = CodeAddresses.getOrDefault(MultiCodec(header))
if proto.kind == None: if proto.kind == None:
raise newException(MultiAddressError, err("multiaddress: Unsupported protocol '" & $header & "'")
"Unsupported protocol '" & $header & "'") else:
result = proto.mcodec ok(proto.mcodec)
proc protoName*(ma: MultiAddress): string = proc protoName*(ma: MultiAddress): MaResult[string] =
## Returns MultiAddress ``ma`` protocol name. ## Returns MultiAddress ``ma`` protocol name.
var header: uint64 var header: uint64
var vb: MultiAddress var vb: MultiAddress
shcopy(vb, ma) shcopy(vb, ma)
if vb.data.readVarint(header) == -1: if vb.data.readVarint(header) == -1:
raise newException(MultiAddressError, "Malformed binary address!") err("multiaddress: Malformed binary address!")
else:
let proto = CodeAddresses.getOrDefault(MultiCodec(header)) let proto = CodeAddresses.getOrDefault(MultiCodec(header))
if proto.kind == None: if proto.kind == None:
raise newException(MultiAddressError, err("multiaddress: Unsupported protocol '" & $header & "'")
"Unsupported protocol '" & $header & "'") else:
result = $(proto.mcodec) ok($(proto.mcodec))
proc protoArgument*(ma: MultiAddress, value: var openarray[byte]): int = proc protoArgument*(ma: MultiAddress, value: var openarray[byte]): MaResult[int] =
## Returns MultiAddress ``ma`` protocol argument value. ## Returns MultiAddress ``ma`` protocol argument value.
## ##
## If current MultiAddress do not have argument value, then result will be ## If current MultiAddress do not have argument value, then result will be
@ -474,71 +484,85 @@ proc protoArgument*(ma: MultiAddress, value: var openarray[byte]): int =
var buffer: seq[byte] var buffer: seq[byte]
shcopy(vb, ma) shcopy(vb, ma)
if vb.data.readVarint(header) == -1: if vb.data.readVarint(header) == -1:
raise newException(MultiAddressError, "Malformed binary address!") err("multiaddress: Malformed binary address!")
else:
let proto = CodeAddresses.getOrDefault(MultiCodec(header)) let proto = CodeAddresses.getOrDefault(MultiCodec(header))
if proto.kind == None: if proto.kind == None:
raise newException(MultiAddressError, err("multiaddress: Unsupported protocol '" & $header & "'")
"Unsupported protocol '" & $header & "'") else:
var res: int
if proto.kind == Fixed: if proto.kind == Fixed:
result = proto.size res = proto.size
if len(value) >= result: if len(value) >= res and
if vb.data.readArray(value.toOpenArray(0, proto.size - 1)) != proto.size: vb.data.readArray(value.toOpenArray(0, proto.size - 1)) != proto.size:
raise newException(MultiAddressError, "Decoding protocol error") err("multiaddress: Decoding protocol error")
else:
ok(res)
elif proto.kind in {Length, Path}: elif proto.kind in {Length, Path}:
if vb.data.readSeq(buffer) == -1: if vb.data.readSeq(buffer) == -1:
raise newException(MultiAddressError, "Decoding protocol error") err("multiaddress: Decoding protocol error")
result = len(buffer) else:
if len(value) >= result: res = len(buffer)
copyMem(addr value[0], addr buffer[0], result) if len(value) >= res:
copyMem(addr value[0], addr buffer[0], res)
ok(res)
else:
ok(res)
proc protoAddress*(ma: MultiAddress): seq[byte] = proc protoAddress*(ma: MultiAddress): MaResult[seq[byte]] =
## Returns MultiAddress ``ma`` protocol address binary blob. ## Returns MultiAddress ``ma`` protocol address binary blob.
## ##
## If current MultiAddress do not have argument value, then result array will ## If current MultiAddress do not have argument value, then result array will
## be empty. ## be empty.
result = newSeq[byte](len(ma.data.buffer)) var buffer = newSeq[byte](len(ma.data.buffer))
let res = protoArgument(ma, result) let res = ? protoArgument(ma, buffer)
result.setLen(res) buffer.setLen(res)
ok(buffer)
proc getPart(ma: MultiAddress, index: int): MultiAddress = proc getPart(ma: MultiAddress, index: int): MaResult[MultiAddress] =
var header: uint64 var header: uint64
var data = newSeq[byte]() var data = newSeq[byte]()
var offset = 0 var offset = 0
var vb = ma var vb = ma
result.data = initVBuffer() var res: MultiAddress
res.data = initVBuffer()
while offset <= index: while offset <= index:
if vb.data.readVarint(header) == -1: if vb.data.readVarint(header) == -1:
raise newException(MultiAddressError, "Malformed binary address!") return err("multiaddress: Malformed binary address!")
let proto = CodeAddresses.getOrDefault(MultiCodec(header)) let proto = CodeAddresses.getOrDefault(MultiCodec(header))
if proto.kind == None: if proto.kind == None:
raise newException(MultiAddressError, return err("multiaddress: Unsupported protocol '" & $header & "'")
"Unsupported protocol '" & $header & "'")
elif proto.kind == Fixed: elif proto.kind == Fixed:
data.setLen(proto.size) data.setLen(proto.size)
if vb.data.readArray(data) != proto.size: if vb.data.readArray(data) != proto.size:
raise newException(MultiAddressError, "Decoding protocol error") return err("multiaddress: Decoding protocol error")
if offset == index: if offset == index:
result.data.writeVarint(header) res.data.writeVarint(header)
result.data.writeArray(data) res.data.writeArray(data)
result.data.finish() res.data.finish()
elif proto.kind in {Length, Path}: elif proto.kind in {Length, Path}:
if vb.data.readSeq(data) == -1: if vb.data.readSeq(data) == -1:
raise newException(MultiAddressError, "Decoding protocol error") return err("multiaddress: Decoding protocol error")
if offset == index: if offset == index:
result.data.writeVarint(header) res.data.writeVarint(header)
result.data.writeSeq(data) res.data.writeSeq(data)
result.data.finish() res.data.finish()
elif proto.kind == Marker: elif proto.kind == Marker:
if offset == index: if offset == index:
result.data.writeVarint(header) res.data.writeVarint(header)
result.data.finish() res.data.finish()
inc(offset) inc(offset)
ok(res)
proc `[]`*(ma: MultiAddress, i: int): MultiAddress {.inline.} = proc `[]`*(ma: MultiAddress, i: int): MaResult[MultiAddress] {.inline.} =
## Returns part with index ``i`` of MultiAddress ``ma``. ## Returns part with index ``i`` of MultiAddress ``ma``.
result = ma.getPart(i) ma.getPart(i)
iterator items*(ma: MultiAddress): MultiAddress = iterator items*(ma: MultiAddress): MaResult[MultiAddress] =
## Iterates over all addresses inside of MultiAddress ``ma``. ## Iterates over all addresses inside of MultiAddress ``ma``.
var header: uint64 var header: uint64
var data = newSeq[byte]() var data = newSeq[byte]()
@ -546,75 +570,70 @@ iterator items*(ma: MultiAddress): MultiAddress =
while true: while true:
if vb.data.isEmpty(): if vb.data.isEmpty():
break break
var res = MultiAddress(data: initVBuffer()) var res = MultiAddress(data: initVBuffer())
if vb.data.readVarint(header) == -1: if vb.data.readVarint(header) == -1:
raise newException(MultiAddressError, "Malformed binary address!") yield err(MaResult[MultiAddress], "Malformed binary address!")
let proto = CodeAddresses.getOrDefault(MultiCodec(header)) let proto = CodeAddresses.getOrDefault(MultiCodec(header))
if proto.kind == None: if proto.kind == None:
raise newException(MultiAddressError, yield err(MaResult[MultiAddress], "Unsupported protocol '" & $header & "'")
"Unsupported protocol '" & $header & "'")
elif proto.kind == Fixed: elif proto.kind == Fixed:
data.setLen(proto.size) data.setLen(proto.size)
if vb.data.readArray(data) != proto.size: if vb.data.readArray(data) != proto.size:
raise newException(MultiAddressError, "Decoding protocol error") yield err(MaResult[MultiAddress], "Decoding protocol error")
res.data.writeVarint(header) res.data.writeVarint(header)
res.data.writeArray(data) res.data.writeArray(data)
elif proto.kind in {Length, Path}: elif proto.kind in {Length, Path}:
if vb.data.readSeq(data) == -1: if vb.data.readSeq(data) == -1:
raise newException(MultiAddressError, "Decoding protocol error") yield err(MaResult[MultiAddress], "Decoding protocol error")
res.data.writeVarint(header) res.data.writeVarint(header)
res.data.writeSeq(data) res.data.writeSeq(data)
elif proto.kind == Marker: elif proto.kind == Marker:
res.data.writeVarint(header) res.data.writeVarint(header)
res.data.finish() res.data.finish()
yield res yield ok(MaResult[MultiAddress], res)
proc contains*(ma: MultiAddress, codec: MultiCodec): bool {.inline.} = proc contains*(ma: MultiAddress, codec: MultiCodec): MaResult[bool] {.inline.} =
## Returns ``true``, if address with MultiCodec ``codec`` present in ## Returns ``true``, if address with MultiCodec ``codec`` present in
## MultiAddress ``ma``. ## MultiAddress ``ma``.
var res = false
for item in ma.items: for item in ma.items:
if item.protoCode() == codec: let code = ?(?item).protoCode()
res = true if code == codec:
break return ok(true)
result = res ok(false)
proc `[]`*(ma: MultiAddress, codec: MultiCodec): MultiAddress {.inline.} = proc `[]`*(ma: MultiAddress, codec: MultiCodec): MaResult[MultiAddress] {.inline.} =
## Returns partial MultiAddress with MultiCodec ``codec`` and present in ## Returns partial MultiAddress with MultiCodec ``codec`` and present in
## MultiAddress ``ma``. ## MultiAddress ``ma``.
##
## Procedure will raise ``MultiAddressError`` if ``codec`` could not be
## found inside of ``ma``.
var res = MultiAddress(data: initVBuffer())
for item in ma.items: for item in ma.items:
if item.protoCode == codec: if ?(?item).protoCode == codec:
res = item return item
break err("multiaddress: Codec is not present in address")
if res.data.isEmpty():
raise newException(MultiAddressError, "Codec is not present in address")
result = res
proc `$`*(value: MultiAddress): string = proc toString*(value: MultiAddress): MaResult[string] =
## Return string representation of MultiAddress ``value``. ## Return string representation of MultiAddress ``value``.
var header: uint64 var header: uint64
var vb = value var vb = value
var parts = newSeq[string]() var parts = newSeq[string]()
var part: string var part: string
var res: string
while true: while true:
if vb.data.isEmpty(): if vb.data.isEmpty():
break break
if vb.data.readVarint(header) == -1: if vb.data.readVarint(header) == -1:
raise newException(MultiAddressError, "Malformed binary address!") return err("multiaddress: Malformed binary address!")
let proto = CodeAddresses.getOrDefault(MultiCodec(header)) let proto = CodeAddresses.getOrDefault(MultiCodec(header))
if proto.kind == None: if proto.kind == None:
raise newException(MultiAddressError, return err("multiaddress: Unsupported protocol '" & $header & "'")
"Unsupported protocol '" & $header & "'")
if proto.kind in {Fixed, Length, Path}: if proto.kind in {Fixed, Length, Path}:
if isNil(proto.coder.bufferToString): if isNil(proto.coder.bufferToString):
raise newException(MultiAddressError, return err("multiaddress: Missing protocol '" & $(proto.mcodec) & "' coder")
"Missing protocol '" & $(proto.mcodec) & "' coder")
if not proto.coder.bufferToString(vb.data, part): if not proto.coder.bufferToString(vb.data, part):
raise newException(MultiAddressError, "Decoding protocol error") return err("multiaddress: Decoding protocol error")
parts.add($(proto.mcodec)) parts.add($(proto.mcodec))
if proto.kind == Path and part[0] == '/': if proto.kind == Path and part[0] == '/':
parts.add(part[1..^1]) parts.add(part[1..^1])
@ -623,17 +642,23 @@ proc `$`*(value: MultiAddress): string =
elif proto.kind == Marker: elif proto.kind == Marker:
parts.add($(proto.mcodec)) parts.add($(proto.mcodec))
if len(parts) > 0: if len(parts) > 0:
result = "/" & parts.join("/") res = "/" & parts.join("/")
ok(res)
proc protocols*(value: MultiAddress): seq[MultiCodec] = proc `$`*(value: MultiAddress): string {.raises: [Defect, ResultError[string]].} =
## Return string representation of MultiAddress ``value``.
value.toString().tryGet()
proc protocols*(value: MultiAddress): MaResult[seq[MultiCodec]] =
## Returns list of protocol codecs inside of MultiAddress ``value``. ## Returns list of protocol codecs inside of MultiAddress ``value``.
result = newSeq[MultiCodec]() var res = newSeq[MultiCodec]()
for item in value.items(): for item in value.items():
result.add(item.protoCode()) res.add(?(?item).protoCode())
ok(res)
proc hex*(value: MultiAddress): string = proc hex*(value: MultiAddress): string =
## Return hexadecimal string representation of MultiAddress ``value``. ## Return hexadecimal string representation of MultiAddress ``value``.
result = $(value.data) $(value.data)
proc write*(vb: var VBuffer, ma: MultiAddress) {.inline.} = proc write*(vb: var VBuffer, ma: MultiAddress) {.inline.} =
## Write MultiAddress value ``ma`` to buffer ``vb``. ## Write MultiAddress value ``ma`` to buffer ``vb``.
@ -667,200 +692,239 @@ proc validate*(ma: MultiAddress): bool =
discard discard
result = true result = true
proc init*(mtype: typedesc[MultiAddress], protocol: MultiCodec, proc init*(mtype: typedesc[MultiAddress], protocol: MultiCodec, value: openarray[byte]): MaResult[MultiAddress] =
value: openarray[byte]): MultiAddress =
## Initialize MultiAddress object from protocol id ``protocol`` and array ## Initialize MultiAddress object from protocol id ``protocol`` and array
## of bytes ``value``. ## of bytes ``value``.
let proto = CodeAddresses.getOrDefault(protocol) let proto = CodeAddresses.getOrDefault(protocol)
if proto.kind == None: if proto.kind == None:
raise newException(MultiAddressError, "Protocol not found") err("multiaddress: Protocol not found")
result.data = initVBuffer() else:
result.data.writeVarint(cast[uint64](proto.mcodec)) var res: MultiAddress
res.data = initVBuffer()
res.data.writeVarint(cast[uint64](proto.mcodec))
if proto.kind in {Fixed, Length, Path}: if proto.kind in {Fixed, Length, Path}:
if len(value) == 0: if len(value) == 0:
raise newException(MultiAddressError, "Value must not be empty array") err("multiaddress: Value must not be empty array")
else:
if proto.kind == Fixed: if proto.kind == Fixed:
result.data.writeArray(value) res.data.writeArray(value)
else: else:
var data = newSeq[byte](len(value)) var data = newSeq[byte](len(value))
copyMem(addr data[0], unsafeAddr value[0], len(value)) copyMem(addr data[0], unsafeAddr value[0], len(value))
result.data.writeSeq(data) res.data.writeSeq(data)
result.data.finish() res.data.finish()
ok(res)
proc init*(mtype: typedesc[MultiAddress], protocol: MultiCodec, proc init*(mtype: typedesc[MultiAddress], protocol: MultiCodec, value: PeerID): MaResult[MultiAddress] {.inline.} =
value: PeerID): MultiAddress {.inline.} =
## Initialize MultiAddress object from protocol id ``protocol`` and peer id ## Initialize MultiAddress object from protocol id ``protocol`` and peer id
## ``value``. ## ``value``.
init(mtype, protocol, value.data) init(mtype, protocol, value.data)
proc init*(mtype: typedesc[MultiAddress], protocol: MultiCodec): MultiAddress = proc init*(mtype: typedesc[MultiAddress], protocol: MultiCodec): MaResult[MultiAddress] =
## Initialize MultiAddress object from protocol id ``protocol``. ## Initialize MultiAddress object from protocol id ``protocol``.
let proto = CodeAddresses.getOrDefault(protocol) let proto = CodeAddresses.getOrDefault(protocol)
if proto.kind == None: if proto.kind == None:
raise newException(MultiAddressError, "Protocol not found") err("multiaddress: Protocol not found")
result.data = initVBuffer() else:
var res: MultiAddress
res.data = initVBuffer()
if proto.kind != Marker: if proto.kind != Marker:
raise newException(MultiAddressError, "Protocol missing value") raise newException(MultiAddressError, "Protocol missing value")
result.data.writeVarint(cast[uint64](proto.mcodec)) res.data.writeVarint(cast[uint64](proto.mcodec))
result.data.finish() res.data.finish()
ok(res)
proc init*(mtype: typedesc[MultiAddress], protocol: MultiCodec, proc init*(mtype: typedesc[MultiAddress], protocol: MultiCodec, value: int): MaResult[MultiAddress] =
value: int): MultiAddress =
## Initialize MultiAddress object from protocol id ``protocol`` and integer ## Initialize MultiAddress object from protocol id ``protocol`` and integer
## ``value``. This procedure can be used to instantiate ``tcp``, ``udp``, ## ``value``. This procedure can be used to instantiate ``tcp``, ``udp``,
## ``dccp`` and ``sctp`` MultiAddresses. ## ``dccp`` and ``sctp`` MultiAddresses.
var allowed = [multiCodec("tcp"), multiCodec("udp"), multiCodec("dccp"), var allowed = [multiCodec("tcp"), multiCodec("udp"), multiCodec("dccp"),
multiCodec("sctp")] multiCodec("sctp")]
if protocol notin allowed: if protocol notin allowed:
raise newException(MultiAddressError, err("multiaddress: Incorrect protocol for integer value")
"Incorrect protocol for integer value") else:
let proto = CodeAddresses.getOrDefault(protocol) let proto = CodeAddresses.getOrDefault(protocol)
result.data = initVBuffer() var res: MultiAddress
result.data.writeVarint(cast[uint64](proto.mcodec)) res.data = initVBuffer()
res.data.writeVarint(cast[uint64](proto.mcodec))
if value < 0 or value > 65535: if value < 0 or value > 65535:
raise newException(MultiAddressError, "Incorrect integer value") err("multiaddress: Incorrect integer value")
result.data.writeArray(toBytesBE(cast[uint16](value))) else:
result.data.finish() res.data.writeArray(toBytesBE(cast[uint16](value)))
res.data.finish()
ok(res)
proc getProtocol(name: string): MAProtocol {.inline.} = proc getProtocol(name: string): MAProtocol {.inline.} =
let mc = MultiCodec.codec(name) let mc = MultiCodec.codec(name)
if mc != InvalidMultiCodec: if mc != InvalidMultiCodec:
result = CodeAddresses.getOrDefault(mc) result = CodeAddresses.getOrDefault(mc)
proc init*(mtype: typedesc[MultiAddress], value: string): MultiAddress = proc init*(mtype: typedesc[MultiAddress], value: string): MaResult[MultiAddress] =
## Initialize MultiAddress object from string representation ``value``. ## Initialize MultiAddress object from string representation ``value``.
var parts = value.trimRight('/').split('/') var parts = value.trimRight('/').split('/')
if len(parts[0]) != 0: if len(parts[0]) != 0:
raise newException(MultiAddressError, err("multiaddress: Invalid MultiAddress, must start with `/`")
"Invalid MultiAddress, must start with `/`") else:
var offset = 1 var offset = 1
result.data = initVBuffer() var res: MultiAddress
res.data = initVBuffer()
while offset < len(parts): while offset < len(parts):
let part = parts[offset] let part = parts[offset]
let proto = getProtocol(part) let proto = getProtocol(part)
if proto.kind == None: if proto.kind == None:
raise newException(MultiAddressError, return err("multiaddress: Unsupported protocol '" & part & "'")
"Unsupported protocol '" & part & "'") else:
if proto.kind in {Fixed, Length, Path}: if proto.kind in {Fixed, Length, Path}:
if isNil(proto.coder.stringToBuffer): if isNil(proto.coder.stringToBuffer):
raise newException(MultiAddressError, return err("multiaddress: Missing protocol '" & part & "' transcoder")
"Missing protocol '" & part & "' transcoder")
if offset + 1 >= len(parts): if offset + 1 >= len(parts):
raise newException(MultiAddressError, return err("multiaddress: Missing protocol '" & part & "' argument")
"Missing protocol '" & part & "' argument")
if proto.kind in {Fixed, Length}: if proto.kind in {Fixed, Length}:
result.data.write(proto.mcodec) res.data.write(proto.mcodec)
let res = proto.coder.stringToBuffer(parts[offset + 1], result.data) let res = proto.coder.stringToBuffer(parts[offset + 1], res.data)
if not res: if not res:
raise newException(MultiAddressError, return err("multiaddress: Error encoding `" & part & "/" & parts[offset + 1] & "`")
"Error encoding `$1/$2`" % [part, parts[offset + 1]])
offset += 2 offset += 2
elif proto.kind == Path: elif proto.kind == Path:
var path = "/" & (parts[(offset + 1)..^1].join("/")) var path = "/" & (parts[(offset + 1)..^1].join("/"))
result.data.write(proto.mcodec) res.data.write(proto.mcodec)
if not proto.coder.stringToBuffer(path, result.data): if not proto.coder.stringToBuffer(path, res.data):
raise newException(MultiAddressError, return err("multiaddress: Error encoding `" & part & "/" & path & "`")
"Error encoding `$1/$2`" % [part, path])
break break
elif proto.kind == Marker: elif proto.kind == Marker:
result.data.write(proto.mcodec) res.data.write(proto.mcodec)
offset += 1 offset += 1
result.data.finish() res.data.finish()
ok(res)
proc init*(mtype: typedesc[MultiAddress], data: openarray[byte]): MultiAddress =
proc init*(mtype: typedesc[MultiAddress], data: openarray[byte]): MaResult[MultiAddress] =
## Initialize MultiAddress with array of bytes ``data``. ## Initialize MultiAddress with array of bytes ``data``.
if len(data) == 0: if len(data) == 0:
raise newException(MultiAddressError, "Address could not be empty!") err("multiaddress: Address could not be empty!")
result.data = initVBuffer() else:
result.data.buffer.setLen(len(data)) var res: MultiAddress
copyMem(addr result.data.buffer[0], unsafeAddr data[0], len(data)) res.data = initVBuffer()
if not result.validate(): res.data.buffer.setLen(len(data))
raise newException(MultiAddressError, "Incorrect MultiAddress!") copyMem(addr res.data.buffer[0], unsafeAddr data[0], len(data))
if not res.validate():
err("multiaddress: Incorrect MultiAddress!")
else:
ok(res)
proc init*(mtype: typedesc[MultiAddress]): MultiAddress = proc init*(mtype: typedesc[MultiAddress]): MultiAddress =
## Initialize empty MultiAddress. ## Initialize empty MultiAddress.
result.data = initVBuffer() result.data = initVBuffer()
proc init*(mtype: typedesc[MultiAddress], proc init*(mtype: typedesc[MultiAddress],
address: IpAddress, protocol: Protocol, port: Port): MultiAddress = address: IpAddress, protocol: Protocol, port: Port): MaResult[MultiAddress] =
## Initialize MultiAddress using stdlib's net.IpAddress (IPv4/IPv6) and ## Initialize MultiAddress using stdlib's net.IpAddress (IPv4/IPv6) and
## net.Protocol (UDP/TCP) information. ## net.Protocol (UDP/TCP) information.
result.data = initVBuffer() var res: MultiAddress
res.data = initVBuffer()
let familyProto = case address.family let familyProto = case address.family
of IpAddressFamily.IPv4: getProtocol("ip4") of IpAddressFamily.IPv4: getProtocol("ip4")
of IpAddressFamily.IPv6: getProtocol("ip6") of IpAddressFamily.IPv6: getProtocol("ip6")
let protoProto = case protocol let protoProto = case protocol
of IPPROTO_TCP: getProtocol("tcp") of IPPROTO_TCP: getProtocol("tcp")
of IPPROTO_UDP: getProtocol("udp") of IPPROTO_UDP: getProtocol("udp")
else: raise newException(AssertionError, else: return err("multiaddress: protocol should be either TCP or UDP")
"protocol should be either TCP or UDP")
result.data.write(familyProto.mcodec) res.data.write(familyProto.mcodec)
if not familyProto.coder.stringToBuffer($address, result.data): if not familyProto.coder.stringToBuffer($address, res.data):
raise newException(MultiAddressError, "Error encoding IPv4/IPv6 address") err("multiaddress: Error encoding IPv4/IPv6 address")
result.data.write(protoProto.mcodec) else:
if not protoProto.coder.stringToBuffer($port, result.data): res.data.write(protoProto.mcodec)
raise newException(MultiAddressError, "Error encoding port number") if not protoProto.coder.stringToBuffer($port, res.data):
result.data.finish() err("multiaddress: Error encoding port number")
else:
res.data.finish()
ok(res)
proc init*(mtype: typedesc[MultiAddress], address: TransportAddress, proc init*(mtype: typedesc[MultiAddress], address: TransportAddress,
protocol: Protocol = IPPROTO_TCP): MultiAddress = protocol = IPPROTO_TCP): MaResult[MultiAddress] =
## Initialize MultiAddress using chronos.TransportAddress (IPv4/IPv6/Unix) ## Initialize MultiAddress using chronos.TransportAddress (IPv4/IPv6/Unix)
## and protocol information (UDP/TCP). ## and protocol information (UDP/TCP).
result.data = initVBuffer() var res: MultiAddress
res.data = initVBuffer()
let protoProto = case protocol let protoProto = case protocol
of IPPROTO_TCP: getProtocol("tcp") of IPPROTO_TCP: getProtocol("tcp")
of IPPROTO_UDP: getProtocol("udp") of IPPROTO_UDP: getProtocol("udp")
else: raise newException(AssertionError, else: return err("multiaddress: protocol should be either TCP or UDP")
"protocol should be either TCP or UDP")
if address.family == AddressFamily.IPv4: if address.family == AddressFamily.IPv4:
result.data.write(getProtocol("ip4").mcodec) res.data.write(getProtocol("ip4").mcodec)
result.data.writeArray(address.address_v4) res.data.writeArray(address.address_v4)
result.data.write(protoProto.mcodec) res.data.write(protoProto.mcodec)
discard protoProto.coder.stringToBuffer($address.port, result.data) discard protoProto.coder.stringToBuffer($address.port, res.data)
elif address.family == AddressFamily.IPv6: elif address.family == AddressFamily.IPv6:
result.data.write(getProtocol("ip6").mcodec) res.data.write(getProtocol("ip6").mcodec)
result.data.writeArray(address.address_v6) res.data.writeArray(address.address_v6)
result.data.write(protoProto.mcodec) res.data.write(protoProto.mcodec)
discard protoProto.coder.stringToBuffer($address.port, result.data) discard protoProto.coder.stringToBuffer($address.port, res.data)
elif address.family == AddressFamily.Unix: elif address.family == AddressFamily.Unix:
result.data.write(getProtocol("unix").mcodec) res.data.write(getProtocol("unix").mcodec)
result.data.writeSeq(address.address_un) res.data.writeSeq(address.address_un)
result.data.finish() res.data.finish()
ok(res)
proc isEmpty*(ma: MultiAddress): bool = proc isEmpty*(ma: MultiAddress): bool =
## Returns ``true``, if MultiAddress ``ma`` is empty or non initialized. ## Returns ``true``, if MultiAddress ``ma`` is empty or non initialized.
result = len(ma.data) == 0 result = len(ma.data) == 0
proc `&`*(m1, m2: MultiAddress): MultiAddress = proc concat*(m1, m2: MultiAddress): MaResult[MultiAddress] =
var res: MultiAddress
res.data = initVBuffer()
res.data.buffer = m1.data.buffer & m2.data.buffer
if not res.validate():
err("multiaddress: Incorrect MultiAddress!")
else:
ok(res)
proc append*(m1: var MultiAddress, m2: MultiAddress): MaResult[void] =
m1.data.buffer &= m2.data.buffer
if not m1.validate():
err("multiaddress: Incorrect MultiAddress!")
else:
ok()
proc `&`*(m1, m2: MultiAddress): MultiAddress {.raises: [Defect, ResultError[string]].} =
## Concatenates two addresses ``m1`` and ``m2``, and returns result. ## Concatenates two addresses ``m1`` and ``m2``, and returns result.
## ##
## This procedure performs validation of concatenated result and can raise ## This procedure performs validation of concatenated result and can raise
## exception on error. ## exception on error.
result.data = initVBuffer() concat(m1, m2).tryGet()
result.data.buffer = m1.data.buffer & m2.data.buffer
if not result.validate():
raise newException(MultiAddressError, "Incorrect MultiAddress!")
proc `&=`*(m1: var MultiAddress, m2: MultiAddress) = proc `&=`*(m1: var MultiAddress, m2: MultiAddress) {.raises: [Defect, ResultError[string]].} =
## Concatenates two addresses ``m1`` and ``m2``. ## Concatenates two addresses ``m1`` and ``m2``.
## ##
## This procedure performs validation of concatenated result and can raise ## This procedure performs validation of concatenated result and can raise
## exception on error. ## exception on error.
m1.data.buffer &= m2.data.buffer ##
if not m1.validate(): m1.append(m2).tryGet()
raise newException(MultiAddressError, "Incorrect MultiAddress!")
proc isWire*(ma: MultiAddress): bool = proc isWire*(ma: MultiAddress): bool =
## Returns ``true`` if MultiAddress ``ma`` is one of: ## Returns ``true`` if MultiAddress ``ma`` is one of:
## - {IP4}/{TCP, UDP} ## - {IP4}/{TCP, UDP}
## - {IP6}/{TCP, UDP} ## - {IP6}/{TCP, UDP}
## - {UNIX}/{PATH} ## - {UNIX}/{PATH}
var state = 0 var
state = 0
try: try:
for part in ma.items(): for rpart in ma.items():
if rpart.isErr():
return false
let part = rpart.get()
if state == 0: if state == 0:
let code = part.protoCode() let rcode = part.protoCode()
if rcode.isErr():
return false
let code = rcode.get()
if code == multiCodec("ip4") or code == multiCodec("ip6"): if code == multiCodec("ip4") or code == multiCodec("ip6"):
inc(state) inc(state)
continue continue
@ -871,8 +935,12 @@ proc isWire*(ma: MultiAddress): bool =
result = false result = false
break break
elif state == 1: elif state == 1:
if part.protoCode == multiCodec("tcp") or let rcode = part.protoCode()
part.protoCode == multiCodec("udp"): if rcode.isErr():
return false
let code = rcode.get()
if code == multiCodec("tcp") or code == multiCodec("udp"):
inc(state) inc(state)
result = true result = true
else: else:
@ -912,16 +980,20 @@ proc matchPart(pat: MaPattern, protos: seq[MultiCodec]): MaPatResult =
proc match*(pat: MaPattern, address: MultiAddress): bool = proc match*(pat: MaPattern, address: MultiAddress): bool =
## Match full ``address`` using pattern ``pat`` and return ``true`` if ## Match full ``address`` using pattern ``pat`` and return ``true`` if
## ``address`` satisfies pattern. ## ``address`` satisfies pattern.
var protos = address.protocols() let protos = address.protocols()
let res = matchPart(pat, protos) if protos.isErr():
result = res.flag and (len(res.rem) == 0) return false
let res = matchPart(pat, protos.get())
res.flag and (len(res.rem) == 0)
proc matchPartial*(pat: MaPattern, address: MultiAddress): bool = proc matchPartial*(pat: MaPattern, address: MultiAddress): bool =
## Match prefix part of ``address`` using pattern ``pat`` and return ## Match prefix part of ``address`` using pattern ``pat`` and return
## ``true`` if ``address`` starts with pattern. ## ``true`` if ``address`` starts with pattern.
var protos = address.protocols() let protos = address.protocols()
let res = matchPart(pat, protos) if protos.isErr():
result = res.flag return false
let res = matchPart(pat, protos.get())
res.flag
proc `$`*(pat: MaPattern): string = proc `$`*(pat: MaPattern): string =
## Return pattern ``pat`` as string. ## Return pattern ``pat`` as string.

View File

@ -11,8 +11,12 @@
## ##
## TODO: ## TODO:
## 1. base32z ## 1. base32z
##
{.push raises: [Defect].}
import tables import tables
import stew/[base32, base58, base64] import stew/[base32, base58, base64, results]
type type
MultibaseStatus* {.pure.} = enum MultibaseStatus* {.pure.} = enum
@ -20,22 +24,20 @@ type
MultiBase* = object MultiBase* = object
MBCodeSize = proc(length: int): int {.nimcall.} MBCodeSize = proc(length: int): int {.nimcall, raises: [Defect].}
MBCodec = object MBCodec = object
code: char code: char
name: string name: string
encr: proc(inbytes: openarray[byte], encr: proc(inbytes: openarray[byte],
outbytes: var openarray[char], outbytes: var openarray[char],
outlen: var int): MultibaseStatus {.nimcall.} outlen: var int): MultibaseStatus {.nimcall, raises: [Defect].}
decr: proc(inbytes: openarray[char], decr: proc(inbytes: openarray[char],
outbytes: var openarray[byte], outbytes: var openarray[byte],
outlen: var int): MultibaseStatus {.nimcall.} outlen: var int): MultibaseStatus {.nimcall, raises: [Defect].}
encl: MBCodeSize encl: MBCodeSize
decl: MBCodeSize decl: MBCodeSize
MultiBaseError* = object of CatchableError
proc idd(inbytes: openarray[char], outbytes: var openarray[byte], proc idd(inbytes: openarray[char], outbytes: var openarray[byte],
outlen: var int): MultibaseStatus = outlen: var int): MultibaseStatus =
let length = len(inbytes) let length = len(inbytes)
@ -439,48 +441,50 @@ proc decode*(mbtype: typedesc[MultiBase], inbytes: openarray[char],
result = mb.decr(inbytes.toOpenArray(1, length - 1), outbytes, outlen) result = mb.decr(inbytes.toOpenArray(1, length - 1), outbytes, outlen)
proc encode*(mbtype: typedesc[MultiBase], encoding: string, proc encode*(mbtype: typedesc[MultiBase], encoding: string,
inbytes: openarray[byte]): string = inbytes: openarray[byte]): Result[string, string] =
## Encode array ``inbytes`` using MultiBase encoding scheme ``encoding`` and ## Encode array ``inbytes`` using MultiBase encoding scheme ``encoding`` and
## return encoded string. ## return encoded string.
let length = len(inbytes) let length = len(inbytes)
let mb = NameMultibases.getOrDefault(encoding) let mb = NameMultibases.getOrDefault(encoding)
if len(mb.name) == 0: if len(mb.name) == 0:
raise newException(MultiBaseError, "Encoding scheme is incorrect!") return err("multibase: Encoding scheme is incorrect!")
if isNil(mb.encr) or isNil(mb.encl): if isNil(mb.encr) or isNil(mb.encl):
raise newException(MultiBaseError, "Encoding scheme is not supported!") return err("multibase: Encoding scheme is not supported!")
var buffer: string var buffer: string
if length > 0: if length > 0:
buffer = newString(mb.encl(length) + 1) buffer = newString(mb.encl(length) + 1)
var outlen = 0 var outlen = 0
let res = mb.encr(inbytes, buffer.toOpenArray(1, buffer.high), outlen) let res = mb.encr(inbytes, buffer.toOpenArray(1, buffer.high), outlen)
if res != MultiBaseStatus.Success: if res != MultiBaseStatus.Success:
raise newException(MultiBaseError, "Encoding error [" & $res & "]") return err("multibase: Encoding error [" & $res & "]")
buffer.setLen(outlen + 1) buffer.setLen(outlen + 1)
buffer[0] = mb.code buffer[0] = mb.code
else: else:
buffer = newString(1) buffer = newString(1)
buffer[0] = mb.code buffer[0] = mb.code
result = buffer ok(buffer)
proc decode*(mbtype: typedesc[MultiBase], inbytes: openarray[char]): seq[byte] = proc decode*(mbtype: typedesc[MultiBase], inbytes: openarray[char]): Result[seq[byte], string] =
## Decode MultiBase encoded array ``inbytes`` and return decoded sequence of ## Decode MultiBase encoded array ``inbytes`` and return decoded sequence of
## bytes. ## bytes.
let length = len(inbytes) let length = len(inbytes)
if length == 0: if length == 0:
raise newException(MultiBaseError, "Could not decode zero-length string") return err("multibase: Could not decode zero-length string")
let mb = CodeMultibases.getOrDefault(inbytes[0]) let mb = CodeMultibases.getOrDefault(inbytes[0])
if len(mb.name) == 0: if len(mb.name) == 0:
raise newException(MultiBaseError, "MultiBase scheme is incorrect!") return err("multibase: MultiBase scheme is incorrect!")
if isNil(mb.decr) or isNil(mb.decl): if isNil(mb.decr) or isNil(mb.decl):
raise newException(MultiBaseError, "MultiBase scheme is not supported!") return err("multibase: MultiBase scheme is not supported!")
if length == 1: if length == 1:
result = newSeq[byte]() let empty: seq[byte] = @[]
ok(empty) # empty
else: else:
var buffer = newSeq[byte](mb.decl(length - 1)) var buffer = newSeq[byte](mb.decl(length - 1))
var outlen = 0 var outlen = 0
let res = mb.decr(inbytes.toOpenArray(1, length - 1), let res = mb.decr(inbytes.toOpenArray(1, length - 1),
buffer, outlen) buffer, outlen)
if res != MultiBaseStatus.Success: if res != MultiBaseStatus.Success:
raise newException(MultiBaseError, "Decoding error [" & $res & "]") err("multibase: Decoding error [" & $res & "]")
result = buffer else:
result.setLen(outlen) buffer.setLen(outlen)
ok(buffer)

View File

@ -482,20 +482,20 @@ proc decode*(mhtype: typedesc[MultiHash], data: openarray[byte],
proc validate*(mhtype: typedesc[MultiHash], data: openarray[byte]): bool = proc validate*(mhtype: typedesc[MultiHash], data: openarray[byte]): bool =
## Returns ``true`` if array of bytes ``data`` has correct MultiHash inside. ## Returns ``true`` if array of bytes ``data`` has correct MultiHash inside.
var code, size: uint64 var code, size: uint64
var res: VarintStatus var res: VarintResult[void]
if len(data) < 2: if len(data) < 2:
return false return false
let last = data.high let last = data.high
var offset = 0 var offset = 0
var length = 0 var length = 0
res = LP.getUVarint(data.toOpenArray(offset, last), length, code) res = LP.getUVarint(data.toOpenArray(offset, last), length, code)
if res != VarintStatus.Success: if res.isErr():
return false return false
offset += length offset += length
if offset >= len(data): if offset >= len(data):
return false return false
res = LP.getUVarint(data.toOpenArray(offset, last), length, size) res = LP.getUVarint(data.toOpenArray(offset, last), length, size)
if res != VarintStatus.Success: if res.isErr():
return false return false
offset += length offset += length
if size > 0x7FFF_FFFF'u64: if size > 0x7FFF_FFFF'u64:

View File

@ -8,6 +8,9 @@
## those terms. ## those terms.
## This module implements minimal Google's ProtoBuf primitives. ## This module implements minimal Google's ProtoBuf primitives.
{.push raises: [Defect].}
import ../varint import ../varint
const const
@ -142,15 +145,15 @@ proc initProtoBuffer*(options: set[ProtoFlags] = {}): ProtoBuffer =
proc write*(pb: var ProtoBuffer, field: ProtoField) = proc write*(pb: var ProtoBuffer, field: ProtoField) =
## Encode protobuf's field ``field`` and store it to protobuf's buffer ``pb``. ## Encode protobuf's field ``field`` and store it to protobuf's buffer ``pb``.
var length = 0 var length = 0
var res: VarintStatus var res: VarintResult[void]
pb.buffer.setLen(len(pb.buffer) + vsizeof(field)) pb.buffer.setLen(len(pb.buffer) + vsizeof(field))
res = PB.putUVarint(pb.toOpenArray(), length, protoHeader(field)) res = PB.putUVarint(pb.toOpenArray(), length, protoHeader(field))
doAssert(res == VarintStatus.Success) doAssert(res.isOk())
pb.offset += length pb.offset += length
case field.kind case field.kind
of ProtoFieldKind.Varint: of ProtoFieldKind.Varint:
res = PB.putUVarint(pb.toOpenArray(), length, field.vint) res = PB.putUVarint(pb.toOpenArray(), length, field.vint)
doAssert(res == VarintStatus.Success) doAssert(res.isOk())
pb.offset += length pb.offset += length
of ProtoFieldKind.Fixed64: of ProtoFieldKind.Fixed64:
doAssert(pb.isEnough(8)) doAssert(pb.isEnough(8))
@ -174,7 +177,7 @@ proc write*(pb: var ProtoBuffer, field: ProtoField) =
pb.offset += 4 pb.offset += 4
of ProtoFieldKind.Length: of ProtoFieldKind.Length:
res = PB.putUVarint(pb.toOpenArray(), length, uint(len(field.vbuffer))) res = PB.putUVarint(pb.toOpenArray(), length, uint(len(field.vbuffer)))
doAssert(res == VarintStatus.Success) doAssert(res.isOk())
pb.offset += length pb.offset += length
doAssert(pb.isEnough(len(field.vbuffer))) doAssert(pb.isEnough(len(field.vbuffer)))
if len(field.vbuffer) > 0: if len(field.vbuffer) > 0:
@ -192,7 +195,7 @@ proc finish*(pb: var ProtoBuffer) =
let pos = 10 - vsizeof(size) let pos = 10 - vsizeof(size)
var usedBytes = 0 var usedBytes = 0
let res = PB.putUVarint(pb.buffer.toOpenArray(pos, 9), usedBytes, size) let res = PB.putUVarint(pb.buffer.toOpenArray(pos, 9), usedBytes, size)
doAssert(res == VarintStatus.Success) doAssert(res.isOk())
pb.offset = pos pb.offset = pos
elif WithUint32BeLength in pb.options: elif WithUint32BeLength in pb.options:
let size = uint(len(pb.buffer) - 4) let size = uint(len(pb.buffer) - 4)
@ -218,8 +221,7 @@ proc getVarintValue*(data: var ProtoBuffer, field: int,
var header = 0'u64 var header = 0'u64
var soffset = data.offset var soffset = data.offset
if not data.isEmpty() and if not data.isEmpty() and PB.getUVarint(data.toOpenArray(), length, header).isOk():
PB.getUVarint(data.toOpenArray(), length, header) == VarintStatus.Success:
data.offset += length data.offset += length
if header == protoHeader(field, Varint): if header == protoHeader(field, Varint):
if not data.isEmpty(): if not data.isEmpty():
@ -227,7 +229,7 @@ proc getVarintValue*(data: var ProtoBuffer, field: int,
let res = getSVarint(data.toOpenArray(), length, value) let res = getSVarint(data.toOpenArray(), length, value)
else: else:
let res = PB.getUVarint(data.toOpenArray(), length, value) let res = PB.getUVarint(data.toOpenArray(), length, value)
if res == VarintStatus.Success: if res.isOk():
data.offset += length data.offset += length
result = length result = length
return return
@ -243,12 +245,10 @@ proc getLengthValue*[T: string|seq[byte]](data: var ProtoBuffer, field: int,
var soffset = data.offset var soffset = data.offset
result = -1 result = -1
buffer.setLen(0) buffer.setLen(0)
if not data.isEmpty() and if not data.isEmpty() and PB.getUVarint(data.toOpenArray(), length, header).isOk():
PB.getUVarint(data.toOpenArray(), length, header) == VarintStatus.Success:
data.offset += length data.offset += length
if header == protoHeader(field, Length): if header == protoHeader(field, Length):
if not data.isEmpty() and if not data.isEmpty() and PB.getUVarint(data.toOpenArray(), length, ssize).isOk():
PB.getUVarint(data.toOpenArray(), length, ssize) == VarintStatus.Success:
data.offset += length data.offset += length
if ssize <= MaxMessageSize and data.isEnough(int(ssize)): if ssize <= MaxMessageSize and data.isEnough(int(ssize)):
buffer.setLen(ssize) buffer.setLen(ssize)
@ -280,12 +280,10 @@ proc enterSubmessage*(pb: var ProtoBuffer): int =
var msize = 0'u64 var msize = 0'u64
var soffset = pb.offset var soffset = pb.offset
if not pb.isEmpty() and if not pb.isEmpty() and PB.getUVarint(pb.toOpenArray(), length, header).isOk():
PB.getUVarint(pb.toOpenArray(), length, header) == VarintStatus.Success:
pb.offset += length pb.offset += length
if (header and 0x07'u64) == cast[uint64](ProtoFieldKind.Length): if (header and 0x07'u64) == cast[uint64](ProtoFieldKind.Length):
if not pb.isEmpty() and if not pb.isEmpty() and PB.getUVarint(pb.toOpenArray(), length, msize).isOk():
PB.getUVarint(pb.toOpenArray(), length, msize) == VarintStatus.Success:
pb.offset += length pb.offset += length
if msize <= MaxMessageSize and pb.isEnough(int(msize)): if msize <= MaxMessageSize and pb.isEnough(int(msize)):
pb.length = int(msize) pb.length = int(msize)

View File

@ -78,7 +78,7 @@ proc decodeMsg*(buf: seq[byte]): IdentifyInfo =
while pb.getBytes(2, address) > 0: while pb.getBytes(2, address) > 0:
if len(address) != 0: if len(address) != 0:
var copyaddr = address var copyaddr = address
var ma = MultiAddress.init(copyaddr) var ma = MultiAddress.init(copyaddr).tryGet()
result.addrs.add(ma) result.addrs.add(ma)
trace "read address bytes from message", address = ma trace "read address bytes from message", address = ma
address.setLen(0) address.setLen(0)
@ -91,7 +91,7 @@ proc decodeMsg*(buf: seq[byte]): IdentifyInfo =
var observableAddr = newSeq[byte]() var observableAddr = newSeq[byte]()
if pb.getBytes(4, observableAddr) > 0: # attempt to read the observed addr if pb.getBytes(4, observableAddr) > 0: # attempt to read the observed addr
var ma = MultiAddress.init(observableAddr) var ma = MultiAddress.init(observableAddr).tryGet()
trace "read observedAddr from message", address = ma trace "read observedAddr from message", address = ma
result.observedAddr = some(ma) result.observedAddr = some(ma)

View File

@ -21,7 +21,7 @@ export
switch, peer, peerinfo, connection, multiaddress, crypto switch, peer, peerinfo, connection, multiaddress, crypto
proc newStandardSwitch*(privKey = none(PrivateKey), proc newStandardSwitch*(privKey = none(PrivateKey),
address = MultiAddress.init("/ip4/127.0.0.1/tcp/0"), address = MultiAddress.init("/ip4/127.0.0.1/tcp/0").tryGet(),
triggerSelf = false, triggerSelf = false,
gossip = false, gossip = false,
verifySignature = libp2p_pubsub_verify, verifySignature = libp2p_pubsub_verify,

View File

@ -120,9 +120,9 @@ proc readVarint*(conn: LPStream): Future[uint64] {.async, gcsafe.} =
for i in 0..<len(buffer): for i in 0..<len(buffer):
await conn.readExactly(addr buffer[i], 1) await conn.readExactly(addr buffer[i], 1)
let res = PB.getUVarint(buffer.toOpenArray(0, i), length, varint) let res = PB.getUVarint(buffer.toOpenArray(0, i), length, varint)
if res == VarintStatus.Success: if res.isOk():
return varint return varint
if res != VarintStatus.Incomplete: if res.error() != VarintError.Incomplete:
break break
if true: # can't end with a raise apparently if true: # can't end with a raise apparently
raise (ref InvalidVarintError)(msg: "Cannot parse varint") raise (ref InvalidVarintError)(msg: "Cannot parse varint")

View File

@ -13,7 +13,7 @@ import vbuffer
type type
Transcoder* = object Transcoder* = object
stringToBuffer*: proc(s: string, stringToBuffer*: proc(s: string,
vb: var VBuffer): bool {.nimcall, gcsafe.} vb: var VBuffer): bool {.nimcall, gcsafe, raises: [Defect].}
bufferToString*: proc(vb: var VBuffer, bufferToString*: proc(vb: var VBuffer,
s: var string): bool {.nimcall, gcsafe.} s: var string): bool {.nimcall, gcsafe, raises: [Defect].}
validateBuffer*: proc(vb: var VBuffer): bool {.nimcall, gcsafe.} validateBuffer*: proc(vb: var VBuffer): bool {.nimcall, gcsafe, raises: [Defect].}

View File

@ -63,7 +63,7 @@ proc connHandler*(t: TcpTransport,
initiator: bool): Connection = initiator: bool): Connection =
trace "handling connection", address = $client.remoteAddress trace "handling connection", address = $client.remoteAddress
let conn: Connection = newConnection(newChronosStream(client)) let conn: Connection = newConnection(newChronosStream(client))
conn.observedAddrs = MultiAddress.init(client.remoteAddress) conn.observedAddrs = MultiAddress.init(client.remoteAddress).tryGet()
if not initiator: if not initiator:
if not isNil(t.handler): if not isNil(t.handler):
t.handlers &= t.handler(conn) t.handlers &= t.handler(conn)
@ -142,7 +142,7 @@ method listen*(t: TcpTransport,
t.server.start() t.server.start()
# always get the resolved address in case we're bound to 0.0.0.0:0 # always get the resolved address in case we're bound to 0.0.0.0:0
t.ma = MultiAddress.init(t.server.sock.getLocalAddress()) t.ma = MultiAddress.init(t.server.sock.getLocalAddress()).tryGet()
result = t.server.join() result = t.server.join()
trace "started node on", address = t.ma trace "started node on", address = t.ma
@ -156,4 +156,4 @@ method dial*(t: TcpTransport,
method handles*(t: TcpTransport, address: MultiAddress): bool {.gcsafe.} = method handles*(t: TcpTransport, address: MultiAddress): bool {.gcsafe.} =
if procCall Transport(t).handles(address): if procCall Transport(t).handles(address):
result = address.protocols.filterIt( it == multiCodec("tcp") ).len > 0 result = address.protocols.tryGet().filterIt( it == multiCodec("tcp") ).len > 0

View File

@ -56,7 +56,7 @@ method handles*(t: Transport, address: MultiAddress): bool {.base, gcsafe.} =
# by default we skip circuit addresses to avoid # by default we skip circuit addresses to avoid
# having to repeat the check in every transport # having to repeat the check in every transport
address.protocols.filterIt( it == multiCodec("p2p-circuit") ).len == 0 address.protocols.tryGet().filterIt( it == multiCodec("p2p-circuit") ).len == 0
method localAddress*(t: Transport): MultiAddress {.base, gcsafe.} = method localAddress*(t: Transport): MultiAddress {.base, gcsafe.} =
## get the local address of the transport in case started with 0.0.0.0:0 ## get the local address of the transport in case started with 0.0.0.0:0

View File

@ -15,17 +15,23 @@
## - LibP2P varint, which is able to encode only 63bits of uint64 number and ## - LibP2P varint, which is able to encode only 63bits of uint64 number and
## maximum size of encoded value is 9 octets (bytes). ## maximum size of encoded value is 9 octets (bytes).
## https://github.com/multiformats/unsigned-varint ## https://github.com/multiformats/unsigned-varint
{.push raises: [Defect].}
import bitops, typetraits import bitops, typetraits
import stew/results
export results
type type
VarintStatus* {.pure.} = enum VarintError* {.pure.} = enum
Error, Error,
Success,
Overflow, Overflow,
Incomplete, Incomplete,
Overlong, Overlong,
Overrun Overrun
VarintResult*[T] = Result[T, VarintError]
PB* = object PB* = object
## Use this type to specify Google ProtoBuf's varint encoding ## Use this type to specify Google ProtoBuf's varint encoding
LP* = object LP* = object
@ -49,7 +55,6 @@ type
LPSomeVarint* = LPSomeUVarint LPSomeVarint* = LPSomeUVarint
SomeVarint* = PBSomeVarint | LPSomeVarint SomeVarint* = PBSomeVarint | LPSomeVarint
SomeUVarint* = PBSomeUVarint | LPSomeUVarint SomeUVarint* = PBSomeUVarint | LPSomeUVarint
VarintError* = object of CatchableError
proc vsizeof*(x: SomeUVarint): int {.inline.} = proc vsizeof*(x: SomeUVarint): int {.inline.} =
## Returns number of bytes required to encode integer ``x`` as varint. ## Returns number of bytes required to encode integer ``x`` as varint.
@ -99,7 +104,7 @@ proc vsizeof*(x: PBZigVarint): int {.inline.} =
proc getUVarint*[T: PB|LP](vtype: typedesc[T], proc getUVarint*[T: PB|LP](vtype: typedesc[T],
pbytes: openarray[byte], pbytes: openarray[byte],
outlen: var int, outlen: var int,
outval: var SomeUVarint): VarintStatus = outval: var SomeUVarint): VarintResult[void] =
## Decode `unsigned varint` from buffer ``pbytes`` and store it to ``outval``. ## Decode `unsigned varint` from buffer ``pbytes`` and store it to ``outval``.
## On success ``outlen`` will be set to number of bytes processed while ## On success ``outlen`` will be set to number of bytes processed while
## decoding `unsigned varint`. ## decoding `unsigned varint`.
@ -130,38 +135,35 @@ proc getUVarint*[T: PB|LP](vtype: typedesc[T],
const MaxBits = byte(sizeof(outval) * 8) const MaxBits = byte(sizeof(outval) * 8)
var shift = 0'u8 var shift = 0'u8
result = VarintStatus.Incomplete
outlen = 0 outlen = 0
outval = type(outval)(0) outval = type(outval)(0)
for i in 0..<len(pbytes): for i in 0..<len(pbytes):
let b = pbytes[i] let b = pbytes[i]
if shift >= MaxBits: if shift >= MaxBits:
result = VarintStatus.Overflow
outlen = 0 outlen = 0
outval = type(outval)(0) outval = type(outval)(0)
break return err(VarintError.Overflow)
else: else:
outval = outval or (type(outval)(b and 0x7F'u8) shl shift) outval = outval or (type(outval)(b and 0x7F'u8) shl shift)
shift += 7 shift += 7
inc(outlen) inc(outlen)
if (b and 0x80'u8) == 0'u8: if (b and 0x80'u8) == 0'u8:
result = VarintStatus.Success # done, success
break
if result == VarintStatus.Incomplete:
outlen = 0
outval = type(outval)(0)
when vtype is LP:
if result == VarintStatus.Success:
if outlen != vsizeof(outval): if outlen != vsizeof(outval):
outval = type(outval)(0) outval = type(outval)(0)
outlen = 0 outlen = 0
result = VarintStatus.Overlong return err(VarintError.Overlong)
else:
return ok()
outlen = 0
outval = type(outval)(0)
err(VarintError.Incomplete)
proc putUVarint*[T: PB|LP](vtype: typedesc[T], proc putUVarint*[T: PB|LP](vtype: typedesc[T],
pbytes: var openarray[byte], pbytes: var openarray[byte],
outlen: var int, outlen: var int,
outval: SomeUVarint): VarintStatus = outval: SomeUVarint): VarintResult[void] =
## Encode `unsigned varint` ``outval`` and store it to array ``pbytes``. ## Encode `unsigned varint` ``outval`` and store it to array ``pbytes``.
## ##
## On success ``outlen`` will hold number of bytes (octets) used to encode ## On success ``outlen`` will hold number of bytes (octets) used to encode
@ -185,8 +187,7 @@ proc putUVarint*[T: PB|LP](vtype: typedesc[T],
when vtype is LP: when vtype is LP:
if sizeof(outval) == 8: if sizeof(outval) == 8:
if (uint64(outval) and 0x8000_0000_0000_0000'u64) != 0'u64: if (uint64(outval) and 0x8000_0000_0000_0000'u64) != 0'u64:
result = Overflow return err(VarintError.Overflow)
return
if value <= type(outval)(0x7F): if value <= type(outval)(0x7F):
buffer[0] = byte(outval and 0xFF) buffer[0] = byte(outval and 0xFF)
@ -201,12 +202,12 @@ proc putUVarint*[T: PB|LP](vtype: typedesc[T],
outlen = k outlen = k
if len(pbytes) >= k: if len(pbytes) >= k:
copyMem(addr pbytes[0], addr buffer[0], k) copyMem(addr pbytes[0], addr buffer[0], k)
result = VarintStatus.Success ok()
else: else:
result = VarintStatus.Overrun err(VarintError.Overrun)
proc getSVarint*(pbytes: openarray[byte], outsize: var int, proc getSVarint*(pbytes: openarray[byte], outsize: var int,
outval: var PBSomeSVarint): VarintStatus {.inline.} = outval: var PBSomeSVarint): VarintResult[void] {.inline.} =
## Decode signed integer (``int32`` or ``int64``) from buffer ``pbytes`` ## Decode signed integer (``int32`` or ``int64``) from buffer ``pbytes``
## and store it to ``outval``. ## and store it to ``outval``.
## ##
@ -230,12 +231,13 @@ proc getSVarint*(pbytes: openarray[byte], outsize: var int,
else: else:
var value: uint32 var value: uint32
result = PB.getUVarint(pbytes, outsize, value) let res = PB.getUVarint(pbytes, outsize, value)
if result == VarintStatus.Success: if res.isOk():
outval = cast[type(outval)](value) outval = cast[type(outval)](value)
res
proc getSVarint*(pbytes: openarray[byte], outsize: var int, proc getSVarint*(pbytes: openarray[byte], outsize: var int,
outval: var PBZigVarint): VarintStatus {.inline.} = outval: var PBZigVarint): VarintResult[void] {.inline.} =
## Decode Google ProtoBuf's zigzag encoded signed integer (``sint32`` or ## Decode Google ProtoBuf's zigzag encoded signed integer (``sint32`` or
## ``sint64`` ) from buffer ``pbytes`` and store it to ``outval``. ## ``sint64`` ) from buffer ``pbytes`` and store it to ``outval``.
## ##
@ -259,15 +261,16 @@ proc getSVarint*(pbytes: openarray[byte], outsize: var int,
else: else:
var value: uint32 var value: uint32
result = PB.getUVarint(pbytes, outsize, value) let res = PB.getUVarint(pbytes, outsize, value)
if result == VarintStatus.Success: if res.isOk():
if (value and type(value)(1)) != type(value)(0): if (value and type(value)(1)) != type(value)(0):
outval = cast[type(outval)](not(value shr 1)) outval = cast[type(outval)](not(value shr 1))
else: else:
outval = cast[type(outval)](value shr 1) outval = cast[type(outval)](value shr 1)
res
proc putSVarint*(pbytes: var openarray[byte], outsize: var int, proc putSVarint*(pbytes: var openarray[byte], outsize: var int,
outval: PBZigVarint): VarintStatus {.inline.} = outval: PBZigVarint): VarintResult[void] {.inline.} =
## Encode signed integer ``outval`` using ProtoBuffer's zigzag encoding ## Encode signed integer ``outval`` using ProtoBuffer's zigzag encoding
## (``sint32`` or ``sint64``) and store it to array ``pbytes``. ## (``sint32`` or ``sint64``) and store it to array ``pbytes``.
## ##
@ -292,10 +295,10 @@ proc putSVarint*(pbytes: var openarray[byte], outsize: var int,
not(uint32(outval) shl 1) not(uint32(outval) shl 1)
else: else:
uint32(outval) shl 1 uint32(outval) shl 1
result = PB.putUVarint(pbytes, outsize, value) PB.putUVarint(pbytes, outsize, value)
proc putSVarint*(pbytes: var openarray[byte], outsize: var int, proc putSVarint*(pbytes: var openarray[byte], outsize: var int,
outval: PBSomeSVarint): VarintStatus {.inline.} = outval: PBSomeSVarint): VarintResult[void] {.inline.} =
## Encode signed integer ``outval`` (``int32`` or ``int64``) and store it to ## Encode signed integer ``outval`` (``int32`` or ``int64``) and store it to
## array ``pbytes``. ## array ``pbytes``.
## ##
@ -309,84 +312,87 @@ proc putSVarint*(pbytes: var openarray[byte], outsize: var int,
## Maximum encoded length of 64bit integer is 10 octets. ## Maximum encoded length of 64bit integer is 10 octets.
## Maximum encoded length of 32bit integer is 5 octets. ## Maximum encoded length of 32bit integer is 5 octets.
when sizeof(outval) == 8: when sizeof(outval) == 8:
result = PB.putUVarint(pbytes, outsize, uint64(outval)) PB.putUVarint(pbytes, outsize, uint64(outval))
else: else:
result = PB.putUVarint(pbytes, outsize, uint32(outval)) PB.putUVarint(pbytes, outsize, uint32(outval))
template varintFatal(msg) = template varintFatal(msg) =
const m = msg const m = msg
{.fatal: m.} {.fatal: m.}
proc putVarint*[T: PB|LP](vtype: typedesc[T], pbytes: var openarray[byte], proc putVarint*[T: PB|LP](vtype: typedesc[T], pbytes: var openarray[byte],
nbytes: var int, value: SomeVarint): VarintStatus {.inline.} = nbytes: var int, value: SomeVarint): VarintResult[void] {.inline.} =
when vtype is PB: when vtype is PB:
when (type(value) is PBSomeSVarint) or (type(value) is PBZigVarint): when (type(value) is PBSomeSVarint) or (type(value) is PBZigVarint):
result = putSVarint(pbytes, nbytes, value) putSVarint(pbytes, nbytes, value)
elif (type(value) is PBSomeUVarint): elif (type(value) is PBSomeUVarint):
result = PB.putUVarint(pbytes, nbytes, value) PB.putUVarint(pbytes, nbytes, value)
else: else:
varintFatal("Protobuf's varint do not support type [" & varintFatal("Protobuf's varint do not support type [" &
typetraits.name(type(value)) & "]") typetraits.name(type(value)) & "]")
elif vtype is LP: elif vtype is LP:
when (type(value) is LPSomeVarint): when (type(value) is LPSomeVarint):
result = LP.putUVarint(pbytes, nbytes, value) LP.putUVarint(pbytes, nbytes, value)
else: else:
varintFatal("LibP2P's varint do not support type [" & varintFatal("LibP2P's varint do not support type [" &
typetraits.name(type(value)) & "]") typetraits.name(type(value)) & "]")
proc getVarint*[T: PB|LP](vtype: typedesc[T], pbytes: openarray[byte], proc getVarint*[T: PB|LP](vtype: typedesc[T], pbytes: openarray[byte],
nbytes: var int, nbytes: var int,
value: var SomeVarint): VarintStatus {.inline.} = value: var SomeVarint): VarintResult[void] {.inline.} =
when vtype is PB: when vtype is PB:
when (type(value) is PBSomeSVarint) or (type(value) is PBZigVarint): when (type(value) is PBSomeSVarint) or (type(value) is PBZigVarint):
result = getSVarint(pbytes, nbytes, value) getSVarint(pbytes, nbytes, value)
elif (type(value) is PBSomeUVarint): elif (type(value) is PBSomeUVarint):
result = PB.getUVarint(pbytes, nbytes, value) PB.getUVarint(pbytes, nbytes, value)
else: else:
varintFatal("Protobuf's varint do not support type [" & varintFatal("Protobuf's varint do not support type [" &
typetraits.name(type(value)) & "]") typetraits.name(type(value)) & "]")
elif vtype is LP: elif vtype is LP:
when (type(value) is LPSomeVarint): when (type(value) is LPSomeVarint):
result = LP.getUVarint(pbytes, nbytes, value) LP.getUVarint(pbytes, nbytes, value)
else: else:
varintFatal("LibP2P's varint do not support type [" & varintFatal("LibP2P's varint do not support type [" &
typetraits.name(type(value)) & "]") typetraits.name(type(value)) & "]")
proc encodeVarint*(vtype: typedesc[PB], proc encodeVarint*(vtype: typedesc[PB],
value: PBSomeVarint): seq[byte] {.inline.} = value: PBSomeVarint): VarintResult[seq[byte]] {.inline.} =
## Encode integer to Google ProtoBuf's `signed/unsigned varint` and returns ## Encode integer to Google ProtoBuf's `signed/unsigned varint` and returns
## sequence of bytes as result. ## sequence of bytes as buffer.
var outsize = 0 var outsize = 0
result = newSeqOfCap[byte](10) var buffer = newSeqOfCap[byte](10)
when sizeof(value) == 4: when sizeof(value) == 4:
result.setLen(5) buffer.setLen(5)
else: else:
result.setLen(10) buffer.setLen(10)
when (type(value) is PBSomeSVarint) or (type(value) is PBZigVarint): when (type(value) is PBSomeSVarint) or (type(value) is PBZigVarint):
let res = putSVarint(result, outsize, value) let res = putSVarint(buffer, outsize, value)
else: else:
let res = PB.putUVarint(result, outsize, value) let res = PB.putUVarint(buffer, outsize, value)
if res == VarintStatus.Success: if res.isOk():
result.setLen(outsize) buffer.setLen(outsize)
ok(buffer)
else: else:
raise newException(VarintError, "Error '" & $res & "'") err(res.error())
proc encodeVarint*(vtype: typedesc[LP], proc encodeVarint*(vtype: typedesc[LP],
value: LPSomeVarint): seq[byte] {.inline.} = value: LPSomeVarint): VarintResult[seq[byte]] {.inline.} =
## Encode integer to LibP2P `unsigned varint` and returns sequence of bytes ## Encode integer to LibP2P `unsigned varint` and returns sequence of bytes
## as result. ## as buffer.
var outsize = 0 var outsize = 0
result = newSeqOfCap[byte](9) var buffer = newSeqOfCap[byte](9)
when sizeof(value) == 1: when sizeof(value) == 1:
result.setLen(2) buffer.setLen(2)
elif sizeof(value) == 2: elif sizeof(value) == 2:
result.setLen(3) buffer.setLen(3)
elif sizeof(value) == 4: elif sizeof(value) == 4:
result.setLen(5) buffer.setLen(5)
else: else:
result.setLen(9) buffer.setLen(9)
let res = LP.putUVarint(result, outsize, value) let res = LP.putUVarint(buffer, outsize, value)
if res == VarintStatus.Success: if res.isOk():
result.setLen(outsize) buffer.setLen(outsize)
ok(buffer)
else: else:
raise newException(VarintError, "Error '" & $res & "'") err(res.error)

View File

@ -8,6 +8,9 @@
## those terms. ## those terms.
## This module implements variable buffer. ## This module implements variable buffer.
{.push raises: [Defect].}
import varint, strutils import varint, strutils
type type
@ -66,7 +69,7 @@ proc writePBVarint*(vb: var VBuffer, value: PBSomeUVarint) =
vb.buffer.setLen(len(vb.buffer) + vsizeof(v)) vb.buffer.setLen(len(vb.buffer) + vsizeof(v))
let res = PB.putUVarint(toOpenArray(vb.buffer, vb.offset, vb.buffer.high), let res = PB.putUVarint(toOpenArray(vb.buffer, vb.offset, vb.buffer.high),
length, v) length, v)
doAssert(res == VarintStatus.Success) doAssert(res.isOk())
vb.offset += length vb.offset += length
proc writeLPVarint*(vb: var VBuffer, value: LPSomeUVarint) = proc writeLPVarint*(vb: var VBuffer, value: LPSomeUVarint) =
@ -77,7 +80,7 @@ proc writeLPVarint*(vb: var VBuffer, value: LPSomeUVarint) =
vb.buffer.setLen(len(vb.buffer) + vsizeof(v)) vb.buffer.setLen(len(vb.buffer) + vsizeof(v))
let res = LP.putUVarint(toOpenArray(vb.buffer, vb.offset, vb.buffer.high), let res = LP.putUVarint(toOpenArray(vb.buffer, vb.offset, vb.buffer.high),
length, v) length, v)
doAssert(res == VarintStatus.Success) doAssert(res.isOk())
vb.offset += length vb.offset += length
proc writeVarint*(vb: var VBuffer, value: LPSomeUVarint) = proc writeVarint*(vb: var VBuffer, value: LPSomeUVarint) =
@ -90,7 +93,7 @@ proc writeSeq*[T: byte|char](vb: var VBuffer, value: openarray[T]) =
vb.buffer.setLen(len(vb.buffer) + vsizeof(uint(len(value))) + len(value)) vb.buffer.setLen(len(vb.buffer) + vsizeof(uint(len(value))) + len(value))
let res = LP.putUVarint(toOpenArray(vb.buffer, vb.offset, vb.buffer.high), let res = LP.putUVarint(toOpenArray(vb.buffer, vb.offset, vb.buffer.high),
length, uint(len(value))) length, uint(len(value)))
doAssert(res == VarintStatus.Success) doAssert(res.isOk())
vb.offset += length vb.offset += length
if len(value) > 0: if len(value) > 0:
copyMem(addr vb.buffer[vb.offset], unsafeAddr value[0], len(value)) copyMem(addr vb.buffer[vb.offset], unsafeAddr value[0], len(value))
@ -120,7 +123,7 @@ proc peekVarint*(vb: var VBuffer, value: var LPSomeUVarint): int =
if not vb.isEmpty(): if not vb.isEmpty():
let res = LP.getUVarint( let res = LP.getUVarint(
toOpenArray(vb.buffer, vb.offset, vb.buffer.high), length, value) toOpenArray(vb.buffer, vb.offset, vb.buffer.high), length, value)
if res == VarintStatus.Success: if res.isOk():
result = length result = length
proc peekSeq*[T: string|seq[byte]](vb: var VBuffer, value: var T): int = proc peekSeq*[T: string|seq[byte]](vb: var VBuffer, value: var T): int =
@ -135,8 +138,7 @@ proc peekSeq*[T: string|seq[byte]](vb: var VBuffer, value: var T): int =
var length = 0 var length = 0
var size = 0'u64 var size = 0'u64
if not vb.isEmpty() and if not vb.isEmpty() and
LP.getUVarint(toOpenArray(vb.buffer, vb.offset, vb.buffer.high), LP.getUVarint(toOpenArray(vb.buffer, vb.offset, vb.buffer.high), length, size).isOk():
length, size) == VarintStatus.Success:
vb.offset += length vb.offset += length
result = length result = length
if vb.isEnough(int(size)): if vb.isEnough(int(size)):

View File

@ -22,38 +22,40 @@ proc initTAddress*(ma: MultiAddress): TransportAddress =
## MultiAddress must be wire address, e.g. ``{IP4, IP6, UNIX}/{TCP, UDP}``. ## MultiAddress must be wire address, e.g. ``{IP4, IP6, UNIX}/{TCP, UDP}``.
var state = 0 var state = 0
var pbuf: array[2, byte] var pbuf: array[2, byte]
for part in ma.items(): for rpart in ma.items():
let code = part.protoCode() let
part = rpart.tryGet()
rcode = part.protoCode()
code = rcode.tryGet()
if state == 0: if state == 0:
if code == multiCodec("ip4"): if code == multiCodec("ip4"):
result = TransportAddress(family: AddressFamily.IPv4) result = TransportAddress(family: AddressFamily.IPv4)
if part.protoArgument(result.address_v4) == 0: if part.protoArgument(result.address_v4).tryGet() == 0:
raise newException(TransportAddressError, "Incorrect IPv4 address") raise newException(TransportAddressError, "Incorrect IPv4 address")
inc(state) inc(state)
elif code == multiCodec("ip6"): elif code == multiCodec("ip6"):
result = TransportAddress(family: AddressFamily.IPv6) result = TransportAddress(family: AddressFamily.IPv6)
if part.protoArgument(result.address_v6) == 0: if part.protoArgument(result.address_v6).tryGet() == 0:
raise newException(TransportAddressError, "Incorrect IPv6 address") raise newException(TransportAddressError, "Incorrect IPv6 address")
inc(state) inc(state)
elif code == multiCodec("unix"): elif code == multiCodec("unix"):
result = TransportAddress(family: AddressFamily.Unix) result = TransportAddress(family: AddressFamily.Unix)
if part.protoArgument(result.address_un) == 0: if part.protoArgument(result.address_un).tryGet() == 0:
raise newException(TransportAddressError, "Incorrect Unix address") raise newException(TransportAddressError, "Incorrect Unix address")
result.port = Port(1) result.port = Port(1)
break break
else: else:
raise newException(TransportAddressError, raise newException(TransportAddressError, "Could not initialize address!")
"Could not initialize address!")
elif state == 1: elif state == 1:
if code == multiCodec("tcp") or code == multiCodec("udp"): if code == multiCodec("tcp") or code == multiCodec("udp"):
if part.protoArgument(pbuf) == 0: if part.protoArgument(pbuf).tryGet() == 0:
raise newException(TransportAddressError, "Incorrect port") raise newException(TransportAddressError, "Incorrect port")
result.port = Port((cast[uint16](pbuf[0]) shl 8) or result.port = Port((cast[uint16](pbuf[0]) shl 8) or
cast[uint16](pbuf[1])) cast[uint16](pbuf[1]))
break break
else: else:
raise newException(TransportAddressError, raise newException(TransportAddressError, "Could not initialize address!")
"Could not initialize address!")
proc connect*(ma: MultiAddress, bufferSize = DefaultStreamBufferSize, proc connect*(ma: MultiAddress, bufferSize = DefaultStreamBufferSize,
child: StreamTransport = nil): Future[StreamTransport] {.async.} = child: StreamTransport = nil): Future[StreamTransport] {.async.} =
@ -63,7 +65,7 @@ proc connect*(ma: MultiAddress, bufferSize = DefaultStreamBufferSize,
let address = initTAddress(ma) let address = initTAddress(ma)
if address.family in {AddressFamily.IPv4, AddressFamily.IPv6}: if address.family in {AddressFamily.IPv4, AddressFamily.IPv6}:
if ma[1].protoCode() != multiCodec("tcp"): if ma[1].tryGet().protoCode().tryGet() != multiCodec("tcp"):
raise newException(TransportAddressError, "Incorrect address type!") raise newException(TransportAddressError, "Incorrect address type!")
result = await connect(address, bufferSize, child) result = await connect(address, bufferSize, child)
@ -79,7 +81,7 @@ proc createStreamServer*[T](ma: MultiAddress,
## Create new TCP stream server which bounds to ``ma`` address. ## Create new TCP stream server which bounds to ``ma`` address.
var address = initTAddress(ma) var address = initTAddress(ma)
if address.family in {AddressFamily.IPv4, AddressFamily.IPv6}: if address.family in {AddressFamily.IPv4, AddressFamily.IPv6}:
if ma[1].protoCode() != multiCodec("tcp"): if ma[1].tryGet().protoCode().tryGet() != multiCodec("tcp"):
raise newException(TransportAddressError, "Incorrect address type!") raise newException(TransportAddressError, "Incorrect address type!")
result = createStreamServer(address, cbproc, flags, udata, sock, backlog, result = createStreamServer(address, cbproc, flags, udata, sock, backlog,
bufferSize, child, init) bufferSize, child, init)
@ -100,10 +102,10 @@ proc createAsyncSocket*(ma: MultiAddress): AsyncFD =
return asyncInvalidSocket return asyncInvalidSocket
if address.family in {AddressFamily.IPv4, AddressFamily.IPv6}: if address.family in {AddressFamily.IPv4, AddressFamily.IPv6}:
if ma[1].protoCode() == multiCodec("udp"): if ma[1].tryGet().protoCode().tryGet() == multiCodec("udp"):
socktype = SockType.SOCK_DGRAM socktype = SockType.SOCK_DGRAM
protocol = Protocol.IPPROTO_UDP protocol = Protocol.IPPROTO_UDP
elif ma[1].protoCode() == multiCodec("tcp"): elif ma[1].tryGet().protoCode().tryGet() == multiCodec("tcp"):
socktype = SockType.SOCK_STREAM socktype = SockType.SOCK_STREAM
protocol = Protocol.IPPROTO_TCP protocol = Protocol.IPPROTO_TCP
elif address.family in {AddressFamily.Unix}: elif address.family in {AddressFamily.Unix}:

View File

@ -20,7 +20,7 @@ suite "Identify":
test "handle identify message": test "handle identify message":
proc testHandle(): Future[bool] {.async.} = proc testHandle(): Future[bool] {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0") let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
let remoteSecKey = PrivateKey.random(ECDSA).get() let remoteSecKey = PrivateKey.random(ECDSA).get()
let remotePeerInfo = PeerInfo.init(remoteSecKey, let remotePeerInfo = PeerInfo.init(remoteSecKey,
[ma], [ma],
@ -65,7 +65,7 @@ suite "Identify":
test "handle failed identify": test "handle failed identify":
proc testHandleError() {.async.} = proc testHandleError() {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0") let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
var remotePeerInfo = PeerInfo.init(PrivateKey.random(ECDSA).get(), [ma]) var remotePeerInfo = PeerInfo.init(PrivateKey.random(ECDSA).get(), [ma])
let identifyProto1 = newIdentify(remotePeerInfo) let identifyProto1 = newIdentify(remotePeerInfo)
let msListen = newMultistream() let msListen = newMultistream()

View File

@ -46,16 +46,15 @@ proc readLp*(s: StreamTransport): Future[seq[byte]] {.async, gcsafe.} =
var var
size: uint size: uint
length: int length: int
res: VarintStatus res: VarintResult[void]
result = newSeq[byte](10) result = newSeq[byte](10)
for i in 0..<len(result): for i in 0..<len(result):
await s.readExactly(addr result[i], 1) await s.readExactly(addr result[i], 1)
res = LP.getUVarint(result.toOpenArray(0, i), length, size) res = LP.getUVarint(result.toOpenArray(0, i), length, size)
if res == VarintStatus.Success: if res.isOk():
break break
if res != VarintStatus.Success: res.expect("Valid varint")
raise (ref InvalidVarintError)()
result.setLen(size) result.setLen(size)
if size > 0.uint: if size > 0.uint:
await s.readExactly(addr result[0], int(size)) await s.readExactly(addr result[0], int(size))
@ -68,7 +67,7 @@ proc createNode*(privKey: Option[PrivateKey] = none(PrivateKey),
if privKey.isNone: if privKey.isNone:
seckey = some(PrivateKey.random(RSA).get()) seckey = some(PrivateKey.random(RSA).get())
var peerInfo = NativePeerInfo.init(seckey.get(), [Multiaddress.init(address)]) var peerInfo = NativePeerInfo.init(seckey.get(), [Multiaddress.init(address).tryGet()])
proc createMplex(conn: Connection): Muxer = newMplex(conn) proc createMplex(conn: Connection): Muxer = newMplex(conn)
let mplexProvider = newMuxerProvider(createMplex, MplexCodec) let mplexProvider = newMuxerProvider(createMplex, MplexCodec)
let transports = @[Transport(TcpTransport.init())] let transports = @[Transport(TcpTransport.init())]

View File

@ -214,7 +214,7 @@ suite "Mplex":
test "e2e - read/write receiver": test "e2e - read/write receiver":
proc testNewStream() {.async.} = proc testNewStream() {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0") let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
var done = newFuture[void]() var done = newFuture[void]()
proc connHandler(conn: Connection) {.async, gcsafe.} = proc connHandler(conn: Connection) {.async, gcsafe.} =
@ -252,7 +252,7 @@ suite "Mplex":
test "e2e - read/write receiver lazy": test "e2e - read/write receiver lazy":
proc testNewStream() {.async.} = proc testNewStream() {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0") let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
var done = newFuture[void]() var done = newFuture[void]()
proc connHandler(conn: Connection) {.async, gcsafe.} = proc connHandler(conn: Connection) {.async, gcsafe.} =
@ -292,7 +292,7 @@ suite "Mplex":
test "e2e - write fragmented": test "e2e - write fragmented":
proc testNewStream() {.async.} = proc testNewStream() {.async.} =
let let
ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0") ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
listenJob = newFuture[void]() listenJob = newFuture[void]()
var bigseq = newSeqOfCap[uint8](MaxMsgSize * 2) var bigseq = newSeqOfCap[uint8](MaxMsgSize * 2)
@ -338,7 +338,7 @@ suite "Mplex":
test "e2e - read/write initiator": test "e2e - read/write initiator":
proc testNewStream() {.async.} = proc testNewStream() {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0") let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
let done = newFuture[void]() let done = newFuture[void]()
proc connHandler(conn: Connection) {.async, gcsafe.} = proc connHandler(conn: Connection) {.async, gcsafe.} =
@ -375,7 +375,7 @@ suite "Mplex":
test "e2e - multiple streams": test "e2e - multiple streams":
proc testNewStream() {.async.} = proc testNewStream() {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0") let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
let done = newFuture[void]() let done = newFuture[void]()
proc connHandler(conn: Connection) {.async, gcsafe.} = proc connHandler(conn: Connection) {.async, gcsafe.} =
@ -417,7 +417,7 @@ suite "Mplex":
test "e2e - multiple read/write streams": test "e2e - multiple read/write streams":
proc testNewStream() {.async.} = proc testNewStream() {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0") let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
let done = newFuture[void]() let done = newFuture[void]()
proc connHandler(conn: Connection) {.async, gcsafe.} = proc connHandler(conn: Connection) {.async, gcsafe.} =
@ -461,7 +461,7 @@ suite "Mplex":
test "jitter - channel should be able to handle erratic read/writes": test "jitter - channel should be able to handle erratic read/writes":
proc test() {.async.} = proc test() {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0") let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
var complete = newFuture[void]() var complete = newFuture[void]()
const MsgSize = 1024 const MsgSize = 1024
@ -529,7 +529,7 @@ suite "Mplex":
test "jitter - channel should handle 1 byte read/write": test "jitter - channel should handle 1 byte read/write":
proc test() {.async.} = proc test() {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0") let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
var complete = newFuture[void]() var complete = newFuture[void]()
const MsgSize = 512 const MsgSize = 512

View File

@ -297,23 +297,18 @@ suite "MultiAddress test suite":
test "go-multiaddr success test vectors": test "go-multiaddr success test vectors":
for item in SuccessVectors: for item in SuccessVectors:
var a = MultiAddress.init(item) var a = MultiAddress.init(item).get()
check a.isEmpty() == false check a.isEmpty() == false
check a.validate() == true check a.validate() == true
test "go-multiaddr failure test vectors": test "go-multiaddr failure test vectors":
for item in FailureVectors: for item in FailureVectors:
var r = false check MultiAddress.init(item).isErr()
try:
discard MultiAddress.init(item)
except:
r = true
check r == true
test "rust-multiaddr success test vectors": test "rust-multiaddr success test vectors":
## Rust test vectors are with changed UDP encoding and without WSS ## Rust test vectors are with changed UDP encoding and without WSS
for i in 0..<len(RustSuccessVectors): for i in 0..<len(RustSuccessVectors):
var a = MultiAddress.init(RustSuccessVectors[i]) var a = MultiAddress.init(RustSuccessVectors[i]).get()
check: check:
hex(a) == RustSuccessExpects[i] hex(a) == RustSuccessExpects[i]
@ -321,7 +316,7 @@ suite "MultiAddress test suite":
for item in RustFailureVectors: for item in RustFailureVectors:
var r = false var r = false
try: try:
discard MultiAddress.init(item) discard MultiAddress.init(item).get()
except: except:
r = true r = true
check r == true check r == true
@ -329,9 +324,9 @@ suite "MultiAddress test suite":
test "Concatenation test": test "Concatenation test":
var ma1 = MultiAddress.init() var ma1 = MultiAddress.init()
var ma2 = MultiAddress.init() var ma2 = MultiAddress.init()
var ma3 = MultiAddress.init("/ip4/127.0.0.1") var ma3 = MultiAddress.init("/ip4/127.0.0.1").get()
var ma4 = MultiAddress.init("/udp/30000") var ma4 = MultiAddress.init("/udp/30000").get()
var ma5 = MultiAddress.init("/p2p-circuit") var ma5 = MultiAddress.init("/p2p-circuit").get()
var cma = ma1 & ma3 & ma4 & ma5 var cma = ma1 & ma3 & ma4 & ma5
ma2 &= ma3 ma2 &= ma3
ma2 &= ma4 ma2 &= ma4
@ -342,15 +337,15 @@ suite "MultiAddress test suite":
test "isWire() test": test "isWire() test":
for item in UtilitySuccessVectors: for item in UtilitySuccessVectors:
var a = MultiAddress.init(item) var a = MultiAddress.init(item).get()
check a.isWire() == true check a.isWire() == true
for item in UtilityFailVectors: for item in UtilityFailVectors:
var a = MultiAddress.init(item) var a = MultiAddress.init(item).get()
check a.isWire() == false check a.isWire() == false
test "Path addresses serialization/deserialization": test "Path addresses serialization/deserialization":
for i in 0..<len(PathVectors): for i in 0..<len(PathVectors):
var a = MultiAddress.init(PathVectors[i]) var a = MultiAddress.init(PathVectors[i]).get()
check: check:
hex(a) == PathExpects[i] hex(a) == PathExpects[i]
$a == PathVectors[i] $a == PathVectors[i]
@ -358,44 +353,44 @@ suite "MultiAddress test suite":
test "MultiAddress pattern matching test vectors": test "MultiAddress pattern matching test vectors":
for item in PatternVectors: for item in PatternVectors:
for gitem in item.good: for gitem in item.good:
var a = MultiAddress.init(gitem) var a = MultiAddress.init(gitem).get()
check item.pattern.match(a) == true check item.pattern.match(a) == true
for bitem in item.bad: for bitem in item.bad:
var a = MultiAddress.init(bitem) var a = MultiAddress.init(bitem).get()
check item.pattern.match(a) == false check item.pattern.match(a) == false
test "MultiAddress init(\"tcp/udp/dccp/sctp\", int) test": test "MultiAddress init(\"tcp/udp/dccp/sctp\", int) test":
check: check:
$MultiAddress.init(multiCodec("tcp"), 0) == "/tcp/0" $MultiAddress.init(multiCodec("tcp"), 0).get() == "/tcp/0"
$MultiAddress.init(multiCodec("tcp"), 65535) == "/tcp/65535" $MultiAddress.init(multiCodec("tcp"), 65535).get() == "/tcp/65535"
$MultiAddress.init(multiCodec("tcp"), 34000) == "/tcp/34000" $MultiAddress.init(multiCodec("tcp"), 34000).get() == "/tcp/34000"
$MultiAddress.init(multiCodec("udp"), 0) == "/udp/0" $MultiAddress.init(multiCodec("udp"), 0).get() == "/udp/0"
$MultiAddress.init(multiCodec("udp"), 65535) == "/udp/65535" $MultiAddress.init(multiCodec("udp"), 65535).get() == "/udp/65535"
$MultiAddress.init(multiCodec("udp"), 34000) == "/udp/34000" $MultiAddress.init(multiCodec("udp"), 34000).get() == "/udp/34000"
$MultiAddress.init(multiCodec("dccp"), 0) == "/dccp/0" $MultiAddress.init(multiCodec("dccp"), 0).get() == "/dccp/0"
$MultiAddress.init(multiCodec("dccp"), 65535) == "/dccp/65535" $MultiAddress.init(multiCodec("dccp"), 65535).get() == "/dccp/65535"
$MultiAddress.init(multiCodec("dccp"), 34000) == "/dccp/34000" $MultiAddress.init(multiCodec("dccp"), 34000).get() == "/dccp/34000"
$MultiAddress.init(multiCodec("sctp"), 0) == "/sctp/0" $MultiAddress.init(multiCodec("sctp"), 0).get() == "/sctp/0"
$MultiAddress.init(multiCodec("sctp"), 65535) == "/sctp/65535" $MultiAddress.init(multiCodec("sctp"), 65535).get() == "/sctp/65535"
$MultiAddress.init(multiCodec("sctp"), 34000) == "/sctp/34000" $MultiAddress.init(multiCodec("sctp"), 34000).get() == "/sctp/34000"
expect(MultiAddressError): check:
discard MultiAddress.init(multiCodec("ip4"), 0) MultiAddress.init(multiCodec("ip4"), 0).isErr()
discard MultiAddress.init(multiCodec("ip6"), 0) MultiAddress.init(multiCodec("ip6"), 0).isErr()
discard MultiAddress.init(multiCodec("p2p"), 0) MultiAddress.init(multiCodec("p2p"), 0).isErr()
discard MultiAddress.init(multiCodec("tcp"), 65536) MultiAddress.init(multiCodec("tcp"), 65536).isErr()
discard MultiAddress.init(multiCodec("udp"), 65536) MultiAddress.init(multiCodec("udp"), 65536).isErr()
discard MultiAddress.init(multiCodec("dccp"), 65536) MultiAddress.init(multiCodec("dccp"), 65536).isErr()
discard MultiAddress.init(multiCodec("sctp"), 65536) MultiAddress.init(multiCodec("sctp"), 65536).isErr()
discard MultiAddress.init(multiCodec("tcp"), -1) MultiAddress.init(multiCodec("tcp"), -1).isErr()
discard MultiAddress.init(multiCodec("udp"), -1) MultiAddress.init(multiCodec("udp"), -1).isErr()
discard MultiAddress.init(multiCodec("dccp"), -1) MultiAddress.init(multiCodec("dccp"), -1).isErr()
discard MultiAddress.init(multiCodec("sctp"), -1) MultiAddress.init(multiCodec("sctp"), -1).isErr()
test "MultiAddress protoAddress(fixed) test": test "MultiAddress protoAddress(fixed) test":
var var
address_v4: array[4, byte] address_v4: array[4, byte]
address_v6: array[16, byte] address_v6: array[16, byte]
check: check:
MultiAddress.init("/ip4/0.0.0.0").protoAddress() == address_v4 MultiAddress.init("/ip4/0.0.0.0").get().protoAddress().get() == address_v4
MultiAddress.init("/ip6/::0").protoAddress() == address_v6 MultiAddress.init("/ip6/::0").get().protoAddress().get() == address_v6

View File

@ -1,5 +1,6 @@
import unittest import unittest
import ../libp2p/multibase import ../libp2p/multibase
import stew/results
when defined(nimHasUsed): {.used.} when defined(nimHasUsed): {.used.}
@ -97,49 +98,49 @@ suite "MultiBase test suite":
MultiBase.decodedLength('\x00', 0) == -1 MultiBase.decodedLength('\x00', 0) == -1
MultiBase.decodedLength('\x00', 1) == 0 MultiBase.decodedLength('\x00', 1) == 0
check: check:
MultiBase.encode("identity", plain) == "\x00" MultiBase.encode("identity", plain).get() == "\x00"
# MultiBase.encode("base1", plain) == "1" # MultiBase.encode("base1", plain) == "1"
# MultiBase.encode("base2", plain) == "0" # MultiBase.encode("base2", plain) == "0"
# MultiBase.encode("base8", plain) == "7" # MultiBase.encode("base8", plain) == "7"
# MultiBase.encode("base10", plain) == "9" # MultiBase.encode("base10", plain) == "9"
# MultiBase.encode("base16", plain) == "f" # MultiBase.encode("base16", plain) == "f"
# MultiBase.encode("base16upper", plain) == "F" # MultiBase.encode("base16upper", plain) == "F"
MultiBase.encode("base32hex", plain) == "v" MultiBase.encode("base32hex", plain).get() == "v"
MultiBase.encode("base32hexupper", plain) == "V" MultiBase.encode("base32hexupper", plain).get() == "V"
MultiBase.encode("base32hexpad", plain) == "t" MultiBase.encode("base32hexpad", plain).get() == "t"
MultiBase.encode("base32hexpadupper", plain) == "T" MultiBase.encode("base32hexpadupper", plain).get() == "T"
MultiBase.encode("base32", plain) == "b" MultiBase.encode("base32", plain).get() == "b"
MultiBase.encode("base32upper", plain) == "B" MultiBase.encode("base32upper", plain).get() == "B"
MultiBase.encode("base32pad", plain) == "c" MultiBase.encode("base32pad", plain).get() == "c"
MultiBase.encode("base32padupper", plain) == "C" MultiBase.encode("base32padupper", plain).get() == "C"
MultiBase.encode("base58btc", plain) == "z" MultiBase.encode("base58btc", plain).get() == "z"
MultiBase.encode("base58flickr", plain) == "Z" MultiBase.encode("base58flickr", plain).get() == "Z"
MultiBase.encode("base64", plain) == "m" MultiBase.encode("base64", plain).get() == "m"
MultiBase.encode("base64pad", plain) == "M" MultiBase.encode("base64pad", plain).get() == "M"
MultiBase.encode("base64url", plain) == "u" MultiBase.encode("base64url", plain).get() == "u"
MultiBase.encode("base64urlpad", plain) == "U" MultiBase.encode("base64urlpad", plain).get() == "U"
check: check:
len(MultiBase.decode("\x00")) == 0 len(MultiBase.decode("\x00").get()) == 0
# len(MultiBase.decode("1")) == 0 # len(MultiBase.decode("1")) == 0
# len(MultiBase.decode("0")) == 0 # len(MultiBase.decode("0")) == 0
# len(MultiBase.decode("7")) == 0 # len(MultiBase.decode("7")) == 0
# len(MultiBase.decode("9")) == 0 # len(MultiBase.decode("9")) == 0
# len(MultiBase.decode("f")) == 0 # len(MultiBase.decode("f")) == 0
# len(MultiBase.decode("F")) == 0 # len(MultiBase.decode("F")) == 0
len(MultiBase.decode("v")) == 0 len(MultiBase.decode("v").get()) == 0
len(MultiBase.decode("V")) == 0 len(MultiBase.decode("V").get()) == 0
len(MultiBase.decode("t")) == 0 len(MultiBase.decode("t").get()) == 0
len(MultiBase.decode("T")) == 0 len(MultiBase.decode("T").get()) == 0
len(MultiBase.decode("b")) == 0 len(MultiBase.decode("b").get()) == 0
len(MultiBase.decode("B")) == 0 len(MultiBase.decode("B").get()) == 0
len(MultiBase.decode("c")) == 0 len(MultiBase.decode("c").get()) == 0
len(MultiBase.decode("C")) == 0 len(MultiBase.decode("C").get()) == 0
len(MultiBase.decode("z")) == 0 len(MultiBase.decode("z").get()) == 0
len(MultiBase.decode("Z")) == 0 len(MultiBase.decode("Z").get()) == 0
len(MultiBase.decode("m")) == 0 len(MultiBase.decode("m").get()) == 0
len(MultiBase.decode("M")) == 0 len(MultiBase.decode("M").get()) == 0
len(MultiBase.decode("u")) == 0 len(MultiBase.decode("u").get()) == 0
len(MultiBase.decode("U")) == 0 len(MultiBase.decode("U").get()) == 0
check: check:
MultiBase.encode("identity", plain, enc, MultiBase.encode("identity", plain, enc,
olens[0]) == MultiBaseStatus.Success olens[0]) == MultiBaseStatus.Success
@ -261,8 +262,8 @@ suite "MultiBase test suite":
var bexpect = cast[seq[byte]](expect) var bexpect = cast[seq[byte]](expect)
var outlen = 0 var outlen = 0
check: check:
MultiBase.encode(encoding, bexpect) == encoded MultiBase.encode(encoding, bexpect).get() == encoded
MultiBase.decode(encoded) == bexpect MultiBase.decode(encoded).get() == bexpect
let elength = MultiBase.encodedLength(encoding, len(expect)) let elength = MultiBase.encodedLength(encoding, len(expect))
var ebuffer = newString(elength) var ebuffer = newString(elength)
@ -291,18 +292,5 @@ suite "MultiBase test suite":
MultiBase.encode("unknown", data, ebuffer, MultiBase.encode("unknown", data, ebuffer,
outlen) == MultiBaseStatus.BadCodec outlen) == MultiBaseStatus.BadCodec
MultiBase.decode("\x01\x00", dbuffer, outlen) == MultiBaseStatus.BadCodec MultiBase.decode("\x01\x00", dbuffer, outlen) == MultiBaseStatus.BadCodec
var r1 = false MultiBase.encode("unknwon", data).isErr()
var r2 = false MultiBase.decode("\x01\x00").isErr()
try:
discard MultiBase.encode("unknwon", data)
except MultiBaseError:
r1 = true
try:
discard MultiBase.decode("\x01\x00")
except MultiBaseError:
r2 = true
check:
r1 == true
r2 == true

View File

@ -236,7 +236,7 @@ suite "Multistream select":
test "e2e - handle": test "e2e - handle":
proc endToEnd(): Future[bool] {.async.} = proc endToEnd(): Future[bool] {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0") let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
let let
handlerWait1 = newFuture[void]() handlerWait1 = newFuture[void]()
@ -283,7 +283,7 @@ suite "Multistream select":
test "e2e - ls": test "e2e - ls":
proc endToEnd(): Future[bool] {.async.} = proc endToEnd(): Future[bool] {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0") let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
let let
handlerWait = newFuture[void]() handlerWait = newFuture[void]()
@ -331,7 +331,7 @@ suite "Multistream select":
test "e2e - select one from a list with unsupported protos": test "e2e - select one from a list with unsupported protos":
proc endToEnd(): Future[bool] {.async.} = proc endToEnd(): Future[bool] {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0") let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
var protocol: LPProtocol = new LPProtocol var protocol: LPProtocol = new LPProtocol
proc testHandler(conn: Connection, proc testHandler(conn: Connection,
@ -371,7 +371,7 @@ suite "Multistream select":
test "e2e - select one with both valid": test "e2e - select one with both valid":
proc endToEnd(): Future[bool] {.async.} = proc endToEnd(): Future[bool] {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0") let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
var protocol: LPProtocol = new LPProtocol var protocol: LPProtocol = new LPProtocol
proc testHandler(conn: Connection, proc testHandler(conn: Connection,

View File

@ -77,7 +77,7 @@ suite "Noise":
test "e2e: handle write + noise": test "e2e: handle write + noise":
proc testListenerDialer(): Future[bool] {.async.} = proc testListenerDialer(): Future[bool] {.async.} =
let let
server: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0") server: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
serverInfo = PeerInfo.init(PrivateKey.random(ECDSA).get(), [server]) serverInfo = PeerInfo.init(PrivateKey.random(ECDSA).get(), [server])
serverNoise = newNoise(serverInfo.privateKey, outgoing = false) serverNoise = newNoise(serverInfo.privateKey, outgoing = false)
@ -115,7 +115,7 @@ suite "Noise":
test "e2e: handle read + noise": test "e2e: handle read + noise":
proc testListenerDialer(): Future[bool] {.async.} = proc testListenerDialer(): Future[bool] {.async.} =
let let
server: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0") server: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
serverInfo = PeerInfo.init(PrivateKey.random(ECDSA).get(), [server]) serverInfo = PeerInfo.init(PrivateKey.random(ECDSA).get(), [server])
serverNoise = newNoise(serverInfo.privateKey, outgoing = false) serverNoise = newNoise(serverInfo.privateKey, outgoing = false)
readTask = newFuture[void]() readTask = newFuture[void]()
@ -156,7 +156,7 @@ suite "Noise":
test "e2e: handle read + noise fragmented": test "e2e: handle read + noise fragmented":
proc testListenerDialer(): Future[bool] {.async.} = proc testListenerDialer(): Future[bool] {.async.} =
let let
server: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0") server: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
serverInfo = PeerInfo.init(PrivateKey.random(ECDSA).get(), [server]) serverInfo = PeerInfo.init(PrivateKey.random(ECDSA).get(), [server])
serverNoise = newNoise(serverInfo.privateKey, outgoing = false) serverNoise = newNoise(serverInfo.privateKey, outgoing = false)
readTask = newFuture[void]() readTask = newFuture[void]()
@ -199,8 +199,8 @@ suite "Noise":
test "e2e use switch dial proto string": test "e2e use switch dial proto string":
proc testSwitch(): Future[bool] {.async, gcsafe.} = proc testSwitch(): Future[bool] {.async, gcsafe.} =
let ma1: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0") let ma1: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
let ma2: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0") let ma2: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
var peerInfo1, peerInfo2: PeerInfo var peerInfo1, peerInfo2: PeerInfo
var switch1, switch2: Switch var switch1, switch2: Switch

View File

@ -57,8 +57,8 @@ suite "Switch":
test "e2e use switch dial proto string": test "e2e use switch dial proto string":
proc testSwitch() {.async, gcsafe.} = proc testSwitch() {.async, gcsafe.} =
let ma1: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0") let ma1: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
let ma2: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0") let ma2: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
var peerInfo1, peerInfo2: PeerInfo var peerInfo1, peerInfo2: PeerInfo
var switch1, switch2: Switch var switch1, switch2: Switch
@ -104,8 +104,8 @@ suite "Switch":
test "e2e use switch no proto string": test "e2e use switch no proto string":
proc testSwitch(): Future[bool] {.async, gcsafe.} = proc testSwitch(): Future[bool] {.async, gcsafe.} =
let ma1: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0") let ma1: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
let ma2: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0") let ma2: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
var peerInfo1, peerInfo2: PeerInfo var peerInfo1, peerInfo2: PeerInfo
var switch1, switch2: Switch var switch1, switch2: Switch

View File

@ -16,7 +16,7 @@ suite "TCP transport":
test "test listener: handle write": test "test listener: handle write":
proc testListener(): Future[bool] {.async, gcsafe.} = proc testListener(): Future[bool] {.async, gcsafe.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0") let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
let handlerWait = newFuture[void]() let handlerWait = newFuture[void]()
proc connHandler(conn: Connection) {.async, gcsafe.} = proc connHandler(conn: Connection) {.async, gcsafe.} =
await conn.write(cstring("Hello!"), 6) await conn.write(cstring("Hello!"), 6)
@ -42,7 +42,7 @@ suite "TCP transport":
test "test listener: handle read": test "test listener: handle read":
proc testListener(): Future[bool] {.async.} = proc testListener(): Future[bool] {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0") let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
let handlerWait = newFuture[void]() let handlerWait = newFuture[void]()
proc connHandler(conn: Connection) {.async, gcsafe.} = proc connHandler(conn: Connection) {.async, gcsafe.} =
var msg = newSeq[byte](6) var msg = newSeq[byte](6)
@ -82,7 +82,7 @@ suite "TCP transport":
var server = createStreamServer(address, serveClient, {ReuseAddr}) var server = createStreamServer(address, serveClient, {ReuseAddr})
server.start() server.start()
let ma: MultiAddress = MultiAddress.init(server.sock.getLocalAddress()) let ma: MultiAddress = MultiAddress.init(server.sock.getLocalAddress()).tryGet()
let transport: TcpTransport = TcpTransport.init() let transport: TcpTransport = TcpTransport.init()
let conn = await transport.dial(ma) let conn = await transport.dial(ma)
var msg = newSeq[byte](6) var msg = newSeq[byte](6)
@ -119,7 +119,7 @@ suite "TCP transport":
var server = createStreamServer(address, serveClient, {ReuseAddr}) var server = createStreamServer(address, serveClient, {ReuseAddr})
server.start() server.start()
let ma: MultiAddress = MultiAddress.init(server.sock.getLocalAddress()) let ma: MultiAddress = MultiAddress.init(server.sock.getLocalAddress()).tryGet()
let transport: TcpTransport = TcpTransport.init() let transport: TcpTransport = TcpTransport.init()
let conn = await transport.dial(ma) let conn = await transport.dial(ma)
await conn.write(cstring("Hello!"), 6) await conn.write(cstring("Hello!"), 6)
@ -138,7 +138,7 @@ suite "TCP transport":
test "e2e: handle write": test "e2e: handle write":
proc testListenerDialer(): Future[bool] {.async.} = proc testListenerDialer(): Future[bool] {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0") let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
let handlerWait = newFuture[void]() let handlerWait = newFuture[void]()
proc connHandler(conn: Connection) {.async, gcsafe.} = proc connHandler(conn: Connection) {.async, gcsafe.} =
await conn.write(cstring("Hello!"), 6) await conn.write(cstring("Hello!"), 6)
@ -166,7 +166,7 @@ suite "TCP transport":
test "e2e: handle read": test "e2e: handle read":
proc testListenerDialer(): Future[bool] {.async.} = proc testListenerDialer(): Future[bool] {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0") let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
let handlerWait = newFuture[void]() let handlerWait = newFuture[void]()
proc connHandler(conn: Connection) {.async, gcsafe.} = proc connHandler(conn: Connection) {.async, gcsafe.} =
var msg = newSeq[byte](6) var msg = newSeq[byte](6)

View File

@ -205,8 +205,8 @@ suite "Variable integer test suite":
for i in 0 ..< len(PBedgeValues): for i in 0 ..< len(PBedgeValues):
buffer.setLen(PBedgeSizes[i]) buffer.setLen(PBedgeSizes[i])
check: check:
PB.putUVarint(buffer, length, PBedgeValues[i]) == VarintStatus.Success PB.putUVarint(buffer, length, PBedgeValues[i]).isOk()
PB.getUVarint(buffer, length, uvalue) == VarintStatus.Success PB.getUVarint(buffer, length, uvalue).isOk()
uvalue == PBedgeValues[i] uvalue == PBedgeValues[i]
toHex(buffer) == PBedgeExpects[i] toHex(buffer) == PBedgeExpects[i]
@ -214,16 +214,16 @@ suite "Variable integer test suite":
buffer.setLen(PBEdgeSignedPositiveSizes[i]) buffer.setLen(PBEdgeSignedPositiveSizes[i])
check: check:
putSVarint(buffer, length, putSVarint(buffer, length,
hint64(PBPositiveSignedEdgeValues[i])) == VarintStatus.Success hint64(PBPositiveSignedEdgeValues[i])).isOk()
getSVarint(buffer, length, ivalue) == VarintStatus.Success getSVarint(buffer, length, ivalue).isOk()
int64(ivalue) == int64(PBPositiveSignedEdgeValues[i]) int64(ivalue) == int64(PBPositiveSignedEdgeValues[i])
toHex(buffer) == PBPositiveSignedEdgeExpects[i] toHex(buffer) == PBPositiveSignedEdgeExpects[i]
buffer.setLen(PBEdgeSignedPositiveZigZagSizes[i]) buffer.setLen(PBEdgeSignedPositiveZigZagSizes[i])
check: check:
putSVarint(buffer, length, putSVarint(buffer, length,
zint64(PBPositiveSignedEdgeValues[i])) == VarintStatus.Success zint64(PBPositiveSignedEdgeValues[i])).isOk()
getSVarint(buffer, length, svalue) == VarintStatus.Success getSVarint(buffer, length, svalue).isOk()
int64(svalue) == int64(PBPositiveSignedEdgeValues[i]) int64(svalue) == int64(PBPositiveSignedEdgeValues[i])
toHex(buffer) == PBPositiveSignedZigZagEdgeExpects[i] toHex(buffer) == PBPositiveSignedZigZagEdgeExpects[i]
@ -231,16 +231,16 @@ suite "Variable integer test suite":
buffer.setLen(PBEdgeSignedNegativeSizes[i]) buffer.setLen(PBEdgeSignedNegativeSizes[i])
check: check:
putSVarint(buffer, length, putSVarint(buffer, length,
hint64(PBNegativeSignedEdgeValues[i])) == VarintStatus.Success hint64(PBNegativeSignedEdgeValues[i])).isOk()
getSVarint(buffer, length, ivalue) == VarintStatus.Success getSVarint(buffer, length, ivalue).isOk()
int64(ivalue) == int64(PBNegativeSignedEdgeValues[i]) int64(ivalue) == int64(PBNegativeSignedEdgeValues[i])
toHex(buffer) == PBNegativeSignedEdgeExpects[i] toHex(buffer) == PBNegativeSignedEdgeExpects[i]
buffer.setLen(PBEdgeSignedNegativeZigZagSizes[i]) buffer.setLen(PBEdgeSignedNegativeZigZagSizes[i])
check: check:
putSVarint(buffer, length, putSVarint(buffer, length,
zint64(PBNegativeSignedEdgeValues[i])) == VarintStatus.Success zint64(PBNegativeSignedEdgeValues[i])).isOk()
getSVarint(buffer, length, svalue) == VarintStatus.Success getSVarint(buffer, length, svalue).isOk()
int64(svalue) == int64(PBNegativeSignedEdgeValues[i]) int64(svalue) == int64(PBNegativeSignedEdgeValues[i])
toHex(buffer) == PBNegativeSignedZigZagEdgeExpects[i] toHex(buffer) == PBNegativeSignedZigZagEdgeExpects[i]
@ -252,7 +252,7 @@ suite "Variable integer test suite":
buffer.setLen(PBedgeSizes[i] - 1) buffer.setLen(PBedgeSizes[i] - 1)
let res = PB.putUVarint(buffer, length, PBedgeValues[i]) let res = PB.putUVarint(buffer, length, PBedgeValues[i])
check: check:
res == VarintStatus.Overrun res.error() == VarintError.Overrun
length == PBedgeSizes[i] length == PBedgeSizes[i]
test "[ProtoBuf] Buffer Incomplete edge cases test": test "[ProtoBuf] Buffer Incomplete edge cases test":
@ -262,10 +262,10 @@ suite "Variable integer test suite":
for i in 0..<len(PBedgeValues): for i in 0..<len(PBedgeValues):
buffer.setLen(PBedgeSizes[i]) buffer.setLen(PBedgeSizes[i])
check: check:
PB.putUVarint(buffer, length, PBedgeValues[i]) == VarintStatus.Success PB.putUVarint(buffer, length, PBedgeValues[i]).isOk()
buffer.setlen(buffer.high) buffer.setlen(buffer.high)
check: check:
PB.getUVarint(buffer, length, value) == VarintStatus.Incomplete PB.getUVarint(buffer, length, value).error() == VarintError.Incomplete
test "[ProtoBuf] Integer Overflow 32bit test": test "[ProtoBuf] Integer Overflow 32bit test":
var buffer = newSeq[byte]() var buffer = newSeq[byte]()
@ -275,8 +275,8 @@ suite "Variable integer test suite":
var value = 0'u32 var value = 0'u32
buffer.setLen(PBedgeSizes[i]) buffer.setLen(PBedgeSizes[i])
check: check:
PB.putUVarint(buffer, length, PBedgeValues[i]) == VarintStatus.Success PB.putUVarint(buffer, length, PBedgeValues[i]).isOk()
PB.getUVarint(buffer, length, value) == VarintStatus.Overflow PB.getUVarint(buffer, length, value).error() == VarintError.Overflow
test "[ProtoBuf] Integer Overflow 64bit test": test "[ProtoBuf] Integer Overflow 64bit test":
var buffer = newSeq[byte]() var buffer = newSeq[byte]()
@ -286,28 +286,28 @@ suite "Variable integer test suite":
var value = 0'u64 var value = 0'u64
buffer.setLen(PBedgeSizes[i] + 1) buffer.setLen(PBedgeSizes[i] + 1)
check: check:
PB.putUVarint(buffer, length, PBedgeValues[i]) == VarintStatus.Success PB.putUVarint(buffer, length, PBedgeValues[i]).isOk()
buffer[9] = buffer[9] or 0x80'u8 buffer[9] = buffer[9] or 0x80'u8
buffer[10] = 0x01'u8 buffer[10] = 0x01'u8
check: check:
PB.getUVarint(buffer, length, value) == VarintStatus.Overflow PB.getUVarint(buffer, length, value).error() == VarintError.Overflow
test "[ProtoBuf] Test vectors": test "[ProtoBuf] Test vectors":
# The test vectors which was obtained at: # The test vectors which was obtained at:
# https://github.com/dermesser/integer-encoding-rs/blob/master/src/varint_tests.rs # https://github.com/dermesser/integer-encoding-rs/blob/master/src/varint_tests.rs
# https://github.com/That3Percent/zigzag/blob/master/src/lib.rs # https://github.com/That3Percent/zigzag/blob/master/src/lib.rs
check: check:
PB.encodeVarint(0'u64) == @[0x00'u8] PB.encodeVarint(0'u64).get() == @[0x00'u8]
PB.encodeVarint(0'u32) == @[0x00'u8] PB.encodeVarint(0'u32).get() == @[0x00'u8]
PB.encodeVarint(hint64(0)) == @[0x00'u8] PB.encodeVarint(hint64(0)).get() == @[0x00'u8]
PB.encodeVarint(hint32(0)) == @[0x00'u8] PB.encodeVarint(hint32(0)).get() == @[0x00'u8]
PB.encodeVarint(zint64(0)) == @[0x00'u8] PB.encodeVarint(zint64(0)).get() == @[0x00'u8]
PB.encodeVarint(zint32(0)) == @[0x00'u8] PB.encodeVarint(zint32(0)).get() == @[0x00'u8]
PB.encodeVarint(zint32(-1)) == PB.encodeVarint(1'u32) PB.encodeVarint(zint32(-1)).get() == PB.encodeVarint(1'u32).get()
PB.encodeVarint(zint64(150)) == PB.encodeVarint(300'u32) PB.encodeVarint(zint64(150)).get( ) == PB.encodeVarint(300'u32).get()
PB.encodeVarint(zint64(-150)) == PB.encodeVarint(299'u32) PB.encodeVarint(zint64(-150)).get() == PB.encodeVarint(299'u32).get()
PB.encodeVarint(zint32(-2147483648)) == PB.encodeVarint(4294967295'u64) PB.encodeVarint(zint32(-2147483648)).get() == PB.encodeVarint(4294967295'u64).get()
PB.encodeVarint(zint32(2147483647)) == PB.encodeVarint(4294967294'u64) PB.encodeVarint(zint32(2147483647)).get() == PB.encodeVarint(4294967294'u64).get()
test "[LibP2P] Success edge cases test": test "[LibP2P] Success edge cases test":
var buffer = newSeq[byte]() var buffer = newSeq[byte]()
@ -316,8 +316,8 @@ suite "Variable integer test suite":
for i in 0..<len(LPedgeValues): for i in 0..<len(LPedgeValues):
buffer.setLen(LPedgeSizes[i]) buffer.setLen(LPedgeSizes[i])
check: check:
LP.putUVarint(buffer, length, LPedgeValues[i]) == VarintStatus.Success LP.putUVarint(buffer, length, LPedgeValues[i]).isOk()
LP.getUVarint(buffer, length, value) == VarintStatus.Success LP.getUVarint(buffer, length, value).isOk()
value == LPedgeValues[i] value == LPedgeValues[i]
toHex(buffer) == LPedgeExpects[i] toHex(buffer) == LPedgeExpects[i]
@ -328,7 +328,7 @@ suite "Variable integer test suite":
buffer.setLen(PBedgeSizes[i] - 1) buffer.setLen(PBedgeSizes[i] - 1)
let res = LP.putUVarint(buffer, length, LPedgeValues[i]) let res = LP.putUVarint(buffer, length, LPedgeValues[i])
check: check:
res == VarintStatus.Overrun res.error() == VarintError.Overrun
length == LPedgeSizes[i] length == LPedgeSizes[i]
test "[LibP2P] Buffer Incomplete edge cases test": test "[LibP2P] Buffer Incomplete edge cases test":
@ -338,10 +338,10 @@ suite "Variable integer test suite":
for i in 0..<len(LPedgeValues): for i in 0..<len(LPedgeValues):
buffer.setLen(LPedgeSizes[i]) buffer.setLen(LPedgeSizes[i])
check: check:
LP.putUVarint(buffer, length, LPedgeValues[i]) == VarintStatus.Success LP.putUVarint(buffer, length, LPedgeValues[i]).isOk()
buffer.setlen(buffer.high) buffer.setlen(buffer.high)
check: check:
LP.getUVarint(buffer, length, value) == VarintStatus.Incomplete LP.getUVarint(buffer, length, value).error() == VarintError.Incomplete
test "[LibP2P] Integer Overflow 32bit test": test "[LibP2P] Integer Overflow 32bit test":
var buffer = newSeq[byte]() var buffer = newSeq[byte]()
@ -351,8 +351,8 @@ suite "Variable integer test suite":
var value = 0'u32 var value = 0'u32
buffer.setLen(LPedgeSizes[i]) buffer.setLen(LPedgeSizes[i])
check: check:
LP.putUVarint(buffer, length, LPedgeValues[i]) == VarintStatus.Success LP.putUVarint(buffer, length, LPedgeValues[i]).isOk()
LP.getUVarint(buffer, length, value) == VarintStatus.Overflow LP.getUVarint(buffer, length, value).error() == VarintError.Overflow
test "[LibP2P] Integer Overflow 64bit test": test "[LibP2P] Integer Overflow 64bit test":
var buffer = newSeq[byte]() var buffer = newSeq[byte]()
@ -362,22 +362,22 @@ suite "Variable integer test suite":
var value = 0'u64 var value = 0'u64
buffer.setLen(LPedgeSizes[i] + 1) buffer.setLen(LPedgeSizes[i] + 1)
check: check:
LP.putUVarint(buffer, length, LPedgeValues[i]) == VarintStatus.Success LP.putUVarint(buffer, length, LPedgeValues[i]).isOk()
buffer[8] = buffer[8] or 0x80'u8 buffer[8] = buffer[8] or 0x80'u8
buffer[9] = 0x01'u8 buffer[9] = 0x01'u8
check: check:
LP.getUVarint(buffer, length, value) == VarintStatus.Overflow LP.getUVarint(buffer, length, value).error() == VarintError.Overflow
test "[LibP2P] Over 63bit test": test "[LibP2P] Over 63bit test":
var buffer = newSeq[byte](10) var buffer = newSeq[byte](10)
var length = 0 var length = 0
check: check:
LP.putUVarint(buffer, length, LP.putUVarint(buffer, length,
0x7FFF_FFFF_FFFF_FFFF'u64) == VarintStatus.Success 0x7FFF_FFFF_FFFF_FFFF'u64).isOk()
LP.putUVarint(buffer, length, LP.putUVarint(buffer, length,
0x8000_0000_0000_0000'u64) == VarintStatus.Overflow 0x8000_0000_0000_0000'u64).error() == VarintError.Overflow
LP.putUVarint(buffer, length, LP.putUVarint(buffer, length,
0xFFFF_FFFF_FFFF_FFFF'u64) == VarintStatus.Overflow 0xFFFF_FFFF_FFFF_FFFF'u64).error() == VarintError.Overflow
test "[LibP2P] Overlong values test": test "[LibP2P] Overlong values test":
const OverlongValues = [ const OverlongValues = [
@ -414,19 +414,19 @@ suite "Variable integer test suite":
for item in OverlongValues: for item in OverlongValues:
check: check:
LP.getUVarint(item, length, value) == VarintStatus.Overlong LP.getUVarint(item, length, value).error() == VarintError.Overlong
length == 0 length == 0
value == 0 value == 0
# We still should be able to decode zero value # We still should be able to decode zero value
check: check:
LP.getUVarint(@[0x00'u8], length, value) == VarintStatus.Success LP.getUVarint(@[0x00'u8], length, value).isOk()
length == 1 length == 1
value == 0 value == 0
# But not overlonged zero value # But not overlonged zero value
check: check:
LP.getUVarint(@[0x80'u8, 0x00'u8], length, value) == VarintStatus.Overlong LP.getUVarint(@[0x80'u8, 0x00'u8], length, value).error() == VarintError.Overlong
length == 0 length == 0
value == 0 value == 0
@ -440,11 +440,11 @@ suite "Variable integer test suite":
var ovalue: vtype var ovalue: vtype
var buffer = newSeq[byte](10) var buffer = newSeq[byte](10)
var length = 0 var length = 0
check ttype.putVarint(buffer, length, value) == VarintStatus.Success check ttype.putVarint(buffer, length, value).isOk()
buffer.setLen(length) buffer.setLen(length)
check: check:
toHex(buffer) == expect toHex(buffer) == expect
ttype.getVarint(buffer, length, ovalue) == VarintStatus.Success ttype.getVarint(buffer, length, ovalue).isOk()
ovalue == value ovalue == value
varintTest(PB, uint64, high(uint64), "FFFFFFFFFFFFFFFFFF01") varintTest(PB, uint64, high(uint64), "FFFFFFFFFFFFFFFFFF01")