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 =
let address = MultiAddress.init(str)
let address = MultiAddress.init(str).tryGet()
if IPFS.match(address) and matchPartial(multiaddress.TCP, address):
result = address
else:
raise newException(MultiAddressError,
raise newException(ValueError,
"Invalid bootstrap node multi-address")
proc dialPeer(p: ChatProto, address: string) {.async.} =
@ -160,10 +160,10 @@ proc processInput(rfd: AsyncFD) {.async.} =
let a = await transp.readLine()
try:
if a.len > 0:
peerInfo.addrs.add(Multiaddress.init(a))
peerInfo.addrs.add(Multiaddress.init(a).tryGet())
break
peerInfo.addrs.add(Multiaddress.init(localAddress))
peerInfo.addrs.add(Multiaddress.init(localAddress).tryGet())
break
except:
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 =
## Returns ``true`` is data has valid binary CID representation.
var version, codec: uint64
var res: VarintStatus
var res: VarintResult[void]
if len(data) < 2:
return false
let last = data.high
@ -140,7 +140,7 @@ proc validate*(ctype: typedesc[Cid], data: openarray[byte]): bool =
var offset = 0
var length = 0
res = LP.getUVarint(data.toOpenArray(offset, last), length, version)
if res != VarintStatus.Success:
if res.isErr():
return false
if version != 1'u64:
return false
@ -148,7 +148,7 @@ proc validate*(ctype: typedesc[Cid], data: openarray[byte]): bool =
if offset >= len(data):
return false
res = LP.getUVarint(data.toOpenArray(offset, last), length, codec)
if res != VarintStatus.Success:
if res.isErr():
return false
var mcodec = CodeContentIds.getOrDefault(cast[int](codec), InvalidMultiCodec)
if mcodec == InvalidMultiCodec:
@ -253,11 +253,11 @@ proc encode*(mbtype: typedesc[MultiBase], encoding: string,
cid: Cid): string {.inline.} =
## Get MultiBase encoded representation of ``cid`` using encoding
## ``encoding``.
result = MultiBase.encode(encoding, cid.data.buffer)
result = MultiBase.encode(encoding, cid.data.buffer).tryGet()
proc `$`*(cid: Cid): string =
## Return official string representation of content identifier ``cid``.
if cid.cidver == CIDv0:
result = BTCBase58.encode(cid.data.buffer)
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:
buffer = hexToSeqByte(data)
except ValueError:
return err("Hex to bytes failed")
return err("secp: Hex to bytes failed")
init(sig, buffer)
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()
ok(SkRawPrivateKeySize)
else:
err("Not enough bytes")
err("secp: Not enough bytes")
proc toBytes*(key: SkPublicKey, data: var openarray[byte]): SkResult[int] =
## 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()
ok(SkRawPublicKeySize)
else:
err("Not enough bytes")
err("secp: Not enough bytes")
proc toBytes*(sig: SkSignature, data: var openarray[byte]): int =
## 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
size: uint
length: int
res: VarintStatus
res: VarintResult[void]
var buffer = newSeq[byte](10)
try:
for i in 0..<len(buffer):
await conn.readExactly(addr buffer[i], 1)
res = PB.getUVarint(buffer.toOpenArray(0, i), length, size)
if res == VarintStatus.Success:
if res.isOk():
break
if res != VarintStatus.Success or size > MaxMessageSize:
if res.isErr() or size > MaxMessageSize:
buffer.setLen(0)
result = buffer
return
@ -521,27 +521,27 @@ proc getSocket(pattern: string,
var sockname = ""
var pid = $getProcessId()
sockname = pattern % [pid, $(count[])]
let tmpma = MultiAddress.init(sockname)
let tmpma = MultiAddress.init(sockname).tryGet()
if UNIX.match(tmpma):
while true:
count[] = count[] + 1
sockname = pattern % [pid, $(count[])]
var ma = MultiAddress.init(sockname)
var ma = MultiAddress.init(sockname).tryGet()
let res = await socketExists(ma)
if not res:
result = ma
break
elif TCP.match(tmpma):
sockname = pattern % [pid, "0"]
var ma = MultiAddress.init(sockname)
var ma = MultiAddress.init(sockname).tryGet()
var sock = createAsyncSocket(ma)
if sock.bindAsyncSocket(ma):
# Socket was successfully bound, then its free to use
count[] = count[] + 1
var ta = sock.getLocalAddress()
sockname = pattern % [pid, $ta.port]
result = MultiAddress.init(sockname)
result = MultiAddress.init(sockname).tryGet()
closeSocket(sock)
# This is forward declaration needed for newDaemonApi()
@ -649,7 +649,7 @@ proc newDaemonApi*(flags: set[P2PDaemonFlags] = {},
api.flags.excl(NoProcessCtrl)
api.address = await getSocket(patternForSocket, addr daemonsCount)
else:
api.address = MultiAddress.init(sockpath)
api.address = MultiAddress.init(sockpath).tryGet()
api.flags.incl(NoProcessCtrl)
let res = await socketExists(api.address)
if not res:
@ -830,7 +830,7 @@ proc getPeerInfo(pb: var ProtoBuffer): PeerInfo =
while pb.getBytes(2, address) != -1:
if len(address) != 0:
var copyaddr = address
result.addresses.add(MultiAddress.init(copyaddr))
result.addresses.add(MultiAddress.init(copyaddr).tryGet())
address.setLen(0)
proc identity*(api: DaemonAPI): Future[PeerInfo] {.async.} =
@ -888,7 +888,7 @@ proc openStream*(api: DaemonAPI, peer: PeerID,
raise newException(DaemonLocalError, "Missing `peer` field!")
if pb.getLengthValue(2, raddress) == -1:
raise newException(DaemonLocalError, "Missing `address` field!")
stream.raddress = MultiAddress.init(raddress)
stream.raddress = MultiAddress.init(raddress).tryGet()
if pb.getLengthValue(3, stream.protocol) == -1:
raise newException(DaemonLocalError, "Missing `proto` field!")
stream.flags.incl(Outbound)
@ -909,7 +909,7 @@ proc streamHandler(server: StreamServer, transp: StreamTransport) {.async.} =
raise newException(DaemonLocalError, "Missing `peer` field!")
if pb.getLengthValue(2, raddress) == -1:
raise newException(DaemonLocalError, "Missing `address` field!")
stream.raddress = MultiAddress.init(raddress)
stream.raddress = MultiAddress.init(raddress).tryGet()
if pb.getLengthValue(3, stream.protocol) == -1:
raise newException(DaemonLocalError, "Missing `proto` field!")
stream.flags.incl(Inbound)

View File

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

View File

@ -11,8 +11,12 @@
##
## TODO:
## 1. base32z
##
{.push raises: [Defect].}
import tables
import stew/[base32, base58, base64]
import stew/[base32, base58, base64, results]
type
MultibaseStatus* {.pure.} = enum
@ -20,22 +24,20 @@ type
MultiBase* = object
MBCodeSize = proc(length: int): int {.nimcall.}
MBCodeSize = proc(length: int): int {.nimcall, raises: [Defect].}
MBCodec = object
code: char
name: string
encr: proc(inbytes: openarray[byte],
outbytes: var openarray[char],
outlen: var int): MultibaseStatus {.nimcall.}
outlen: var int): MultibaseStatus {.nimcall, raises: [Defect].}
decr: proc(inbytes: openarray[char],
outbytes: var openarray[byte],
outlen: var int): MultibaseStatus {.nimcall.}
outlen: var int): MultibaseStatus {.nimcall, raises: [Defect].}
encl: MBCodeSize
decl: MBCodeSize
MultiBaseError* = object of CatchableError
proc idd(inbytes: openarray[char], outbytes: var openarray[byte],
outlen: var int): MultibaseStatus =
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)
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
## return encoded string.
let length = len(inbytes)
let mb = NameMultibases.getOrDefault(encoding)
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):
raise newException(MultiBaseError, "Encoding scheme is not supported!")
return err("multibase: Encoding scheme is not supported!")
var buffer: string
if length > 0:
buffer = newString(mb.encl(length) + 1)
var outlen = 0
let res = mb.encr(inbytes, buffer.toOpenArray(1, buffer.high), outlen)
if res != MultiBaseStatus.Success:
raise newException(MultiBaseError, "Encoding error [" & $res & "]")
return err("multibase: Encoding error [" & $res & "]")
buffer.setLen(outlen + 1)
buffer[0] = mb.code
else:
buffer = newString(1)
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
## bytes.
let length = len(inbytes)
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])
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):
raise newException(MultiBaseError, "MultiBase scheme is not supported!")
return err("multibase: MultiBase scheme is not supported!")
if length == 1:
result = newSeq[byte]()
let empty: seq[byte] = @[]
ok(empty) # empty
else:
var buffer = newSeq[byte](mb.decl(length - 1))
var outlen = 0
let res = mb.decr(inbytes.toOpenArray(1, length - 1),
buffer, outlen)
if res != MultiBaseStatus.Success:
raise newException(MultiBaseError, "Decoding error [" & $res & "]")
result = buffer
result.setLen(outlen)
err("multibase: Decoding error [" & $res & "]")
else:
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 =
## Returns ``true`` if array of bytes ``data`` has correct MultiHash inside.
var code, size: uint64
var res: VarintStatus
var res: VarintResult[void]
if len(data) < 2:
return false
let last = data.high
var offset = 0
var length = 0
res = LP.getUVarint(data.toOpenArray(offset, last), length, code)
if res != VarintStatus.Success:
if res.isErr():
return false
offset += length
if offset >= len(data):
return false
res = LP.getUVarint(data.toOpenArray(offset, last), length, size)
if res != VarintStatus.Success:
if res.isErr():
return false
offset += length
if size > 0x7FFF_FFFF'u64:

View File

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

View File

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

View File

@ -21,7 +21,7 @@ export
switch, peer, peerinfo, connection, multiaddress, crypto
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,
gossip = false,
verifySignature = libp2p_pubsub_verify,

View File

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

View File

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

View File

@ -63,7 +63,7 @@ proc connHandler*(t: TcpTransport,
initiator: bool): Connection =
trace "handling connection", address = $client.remoteAddress
let conn: Connection = newConnection(newChronosStream(client))
conn.observedAddrs = MultiAddress.init(client.remoteAddress)
conn.observedAddrs = MultiAddress.init(client.remoteAddress).tryGet()
if not initiator:
if not isNil(t.handler):
t.handlers &= t.handler(conn)
@ -142,7 +142,7 @@ method listen*(t: TcpTransport,
t.server.start()
# 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()
trace "started node on", address = t.ma
@ -156,4 +156,4 @@ method dial*(t: TcpTransport,
method handles*(t: TcpTransport, address: MultiAddress): bool {.gcsafe.} =
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
# 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.} =
## 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
## maximum size of encoded value is 9 octets (bytes).
## https://github.com/multiformats/unsigned-varint
{.push raises: [Defect].}
import bitops, typetraits
import stew/results
export results
type
VarintStatus* {.pure.} = enum
VarintError* {.pure.} = enum
Error,
Success,
Overflow,
Incomplete,
Overlong,
Overrun
VarintResult*[T] = Result[T, VarintError]
PB* = object
## Use this type to specify Google ProtoBuf's varint encoding
LP* = object
@ -49,7 +55,6 @@ type
LPSomeVarint* = LPSomeUVarint
SomeVarint* = PBSomeVarint | LPSomeVarint
SomeUVarint* = PBSomeUVarint | LPSomeUVarint
VarintError* = object of CatchableError
proc vsizeof*(x: SomeUVarint): int {.inline.} =
## 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],
pbytes: openarray[byte],
outlen: var int,
outval: var SomeUVarint): VarintStatus =
outval: var SomeUVarint): VarintResult[void] =
## Decode `unsigned varint` from buffer ``pbytes`` and store it to ``outval``.
## On success ``outlen`` will be set to number of bytes processed while
## decoding `unsigned varint`.
@ -130,38 +135,35 @@ proc getUVarint*[T: PB|LP](vtype: typedesc[T],
const MaxBits = byte(sizeof(outval) * 8)
var shift = 0'u8
result = VarintStatus.Incomplete
outlen = 0
outval = type(outval)(0)
for i in 0..<len(pbytes):
let b = pbytes[i]
if shift >= MaxBits:
result = VarintStatus.Overflow
outlen = 0
outval = type(outval)(0)
break
return err(VarintError.Overflow)
else:
outval = outval or (type(outval)(b and 0x7F'u8) shl shift)
shift += 7
inc(outlen)
if (b and 0x80'u8) == 0'u8:
result = VarintStatus.Success
break
if result == VarintStatus.Incomplete:
outlen = 0
outval = type(outval)(0)
when vtype is LP:
if result == VarintStatus.Success:
# done, success
if outlen != vsizeof(outval):
outval = type(outval)(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],
pbytes: var openarray[byte],
outlen: var int,
outval: SomeUVarint): VarintStatus =
outval: SomeUVarint): VarintResult[void] =
## Encode `unsigned varint` ``outval`` and store it to array ``pbytes``.
##
## 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:
if sizeof(outval) == 8:
if (uint64(outval) and 0x8000_0000_0000_0000'u64) != 0'u64:
result = Overflow
return
return err(VarintError.Overflow)
if value <= type(outval)(0x7F):
buffer[0] = byte(outval and 0xFF)
@ -201,12 +202,12 @@ proc putUVarint*[T: PB|LP](vtype: typedesc[T],
outlen = k
if len(pbytes) >= k:
copyMem(addr pbytes[0], addr buffer[0], k)
result = VarintStatus.Success
ok()
else:
result = VarintStatus.Overrun
err(VarintError.Overrun)
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``
## and store it to ``outval``.
##
@ -230,12 +231,13 @@ proc getSVarint*(pbytes: openarray[byte], outsize: var int,
else:
var value: uint32
result = PB.getUVarint(pbytes, outsize, value)
if result == VarintStatus.Success:
let res = PB.getUVarint(pbytes, outsize, value)
if res.isOk():
outval = cast[type(outval)](value)
res
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
## ``sint64`` ) from buffer ``pbytes`` and store it to ``outval``.
##
@ -259,15 +261,16 @@ proc getSVarint*(pbytes: openarray[byte], outsize: var int,
else:
var value: uint32
result = PB.getUVarint(pbytes, outsize, value)
if result == VarintStatus.Success:
let res = PB.getUVarint(pbytes, outsize, value)
if res.isOk():
if (value and type(value)(1)) != type(value)(0):
outval = cast[type(outval)](not(value shr 1))
else:
outval = cast[type(outval)](value shr 1)
res
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
## (``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)
else:
uint32(outval) shl 1
result = PB.putUVarint(pbytes, outsize, value)
PB.putUVarint(pbytes, outsize, value)
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
## 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 32bit integer is 5 octets.
when sizeof(outval) == 8:
result = PB.putUVarint(pbytes, outsize, uint64(outval))
PB.putUVarint(pbytes, outsize, uint64(outval))
else:
result = PB.putUVarint(pbytes, outsize, uint32(outval))
PB.putUVarint(pbytes, outsize, uint32(outval))
template varintFatal(msg) =
const m = msg
{.fatal: m.}
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 (type(value) is PBSomeSVarint) or (type(value) is PBZigVarint):
result = putSVarint(pbytes, nbytes, value)
putSVarint(pbytes, nbytes, value)
elif (type(value) is PBSomeUVarint):
result = PB.putUVarint(pbytes, nbytes, value)
PB.putUVarint(pbytes, nbytes, value)
else:
varintFatal("Protobuf's varint do not support type [" &
typetraits.name(type(value)) & "]")
elif vtype is LP:
when (type(value) is LPSomeVarint):
result = LP.putUVarint(pbytes, nbytes, value)
LP.putUVarint(pbytes, nbytes, value)
else:
varintFatal("LibP2P's varint do not support type [" &
typetraits.name(type(value)) & "]")
proc getVarint*[T: PB|LP](vtype: typedesc[T], pbytes: openarray[byte],
nbytes: var int,
value: var SomeVarint): VarintStatus {.inline.} =
value: var SomeVarint): VarintResult[void] {.inline.} =
when vtype is PB:
when (type(value) is PBSomeSVarint) or (type(value) is PBZigVarint):
result = getSVarint(pbytes, nbytes, value)
getSVarint(pbytes, nbytes, value)
elif (type(value) is PBSomeUVarint):
result = PB.getUVarint(pbytes, nbytes, value)
PB.getUVarint(pbytes, nbytes, value)
else:
varintFatal("Protobuf's varint do not support type [" &
typetraits.name(type(value)) & "]")
elif vtype is LP:
when (type(value) is LPSomeVarint):
result = LP.getUVarint(pbytes, nbytes, value)
LP.getUVarint(pbytes, nbytes, value)
else:
varintFatal("LibP2P's varint do not support type [" &
typetraits.name(type(value)) & "]")
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
## sequence of bytes as result.
## sequence of bytes as buffer.
var outsize = 0
result = newSeqOfCap[byte](10)
var buffer = newSeqOfCap[byte](10)
when sizeof(value) == 4:
result.setLen(5)
buffer.setLen(5)
else:
result.setLen(10)
buffer.setLen(10)
when (type(value) is PBSomeSVarint) or (type(value) is PBZigVarint):
let res = putSVarint(result, outsize, value)
let res = putSVarint(buffer, outsize, value)
else:
let res = PB.putUVarint(result, outsize, value)
if res == VarintStatus.Success:
result.setLen(outsize)
let res = PB.putUVarint(buffer, outsize, value)
if res.isOk():
buffer.setLen(outsize)
ok(buffer)
else:
raise newException(VarintError, "Error '" & $res & "'")
err(res.error())
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
## as result.
## as buffer.
var outsize = 0
result = newSeqOfCap[byte](9)
var buffer = newSeqOfCap[byte](9)
when sizeof(value) == 1:
result.setLen(2)
buffer.setLen(2)
elif sizeof(value) == 2:
result.setLen(3)
buffer.setLen(3)
elif sizeof(value) == 4:
result.setLen(5)
buffer.setLen(5)
else:
result.setLen(9)
let res = LP.putUVarint(result, outsize, value)
if res == VarintStatus.Success:
result.setLen(outsize)
buffer.setLen(9)
let res = LP.putUVarint(buffer, outsize, value)
if res.isOk():
buffer.setLen(outsize)
ok(buffer)
else:
raise newException(VarintError, "Error '" & $res & "'")
err(res.error)

View File

@ -8,6 +8,9 @@
## those terms.
## This module implements variable buffer.
{.push raises: [Defect].}
import varint, strutils
type
@ -66,7 +69,7 @@ proc writePBVarint*(vb: var VBuffer, value: PBSomeUVarint) =
vb.buffer.setLen(len(vb.buffer) + vsizeof(v))
let res = PB.putUVarint(toOpenArray(vb.buffer, vb.offset, vb.buffer.high),
length, v)
doAssert(res == VarintStatus.Success)
doAssert(res.isOk())
vb.offset += length
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))
let res = LP.putUVarint(toOpenArray(vb.buffer, vb.offset, vb.buffer.high),
length, v)
doAssert(res == VarintStatus.Success)
doAssert(res.isOk())
vb.offset += length
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))
let res = LP.putUVarint(toOpenArray(vb.buffer, vb.offset, vb.buffer.high),
length, uint(len(value)))
doAssert(res == VarintStatus.Success)
doAssert(res.isOk())
vb.offset += length
if len(value) > 0:
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():
let res = LP.getUVarint(
toOpenArray(vb.buffer, vb.offset, vb.buffer.high), length, value)
if res == VarintStatus.Success:
if res.isOk():
result = length
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 size = 0'u64
if not vb.isEmpty() and
LP.getUVarint(toOpenArray(vb.buffer, vb.offset, vb.buffer.high),
length, size) == VarintStatus.Success:
LP.getUVarint(toOpenArray(vb.buffer, vb.offset, vb.buffer.high), length, size).isOk():
vb.offset += length
result = length
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}``.
var state = 0
var pbuf: array[2, byte]
for part in ma.items():
let code = part.protoCode()
for rpart in ma.items():
let
part = rpart.tryGet()
rcode = part.protoCode()
code = rcode.tryGet()
if state == 0:
if code == multiCodec("ip4"):
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")
inc(state)
elif code == multiCodec("ip6"):
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")
inc(state)
elif code == multiCodec("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")
result.port = Port(1)
break
else:
raise newException(TransportAddressError,
"Could not initialize address!")
raise newException(TransportAddressError, "Could not initialize address!")
elif state == 1:
if code == multiCodec("tcp") or code == multiCodec("udp"):
if part.protoArgument(pbuf) == 0:
if part.protoArgument(pbuf).tryGet() == 0:
raise newException(TransportAddressError, "Incorrect port")
result.port = Port((cast[uint16](pbuf[0]) shl 8) or
cast[uint16](pbuf[1]))
break
else:
raise newException(TransportAddressError,
"Could not initialize address!")
raise newException(TransportAddressError, "Could not initialize address!")
proc connect*(ma: MultiAddress, bufferSize = DefaultStreamBufferSize,
child: StreamTransport = nil): Future[StreamTransport] {.async.} =
@ -63,7 +65,7 @@ proc connect*(ma: MultiAddress, bufferSize = DefaultStreamBufferSize,
let address = initTAddress(ma)
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!")
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.
var address = initTAddress(ma)
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!")
result = createStreamServer(address, cbproc, flags, udata, sock, backlog,
bufferSize, child, init)
@ -100,10 +102,10 @@ proc createAsyncSocket*(ma: MultiAddress): AsyncFD =
return asyncInvalidSocket
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
protocol = Protocol.IPPROTO_UDP
elif ma[1].protoCode() == multiCodec("tcp"):
elif ma[1].tryGet().protoCode().tryGet() == multiCodec("tcp"):
socktype = SockType.SOCK_STREAM
protocol = Protocol.IPPROTO_TCP
elif address.family in {AddressFamily.Unix}:

View File

@ -20,7 +20,7 @@ suite "Identify":
test "handle identify message":
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 remotePeerInfo = PeerInfo.init(remoteSecKey,
[ma],
@ -65,7 +65,7 @@ suite "Identify":
test "handle failed identify":
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])
let identifyProto1 = newIdentify(remotePeerInfo)
let msListen = newMultistream()

View File

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

View File

@ -214,7 +214,7 @@ suite "Mplex":
test "e2e - read/write receiver":
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]()
proc connHandler(conn: Connection) {.async, gcsafe.} =
@ -252,7 +252,7 @@ suite "Mplex":
test "e2e - read/write receiver lazy":
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]()
proc connHandler(conn: Connection) {.async, gcsafe.} =
@ -292,7 +292,7 @@ suite "Mplex":
test "e2e - write fragmented":
proc testNewStream() {.async.} =
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]()
var bigseq = newSeqOfCap[uint8](MaxMsgSize * 2)
@ -338,7 +338,7 @@ suite "Mplex":
test "e2e - read/write initiator":
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]()
proc connHandler(conn: Connection) {.async, gcsafe.} =
@ -375,7 +375,7 @@ suite "Mplex":
test "e2e - multiple streams":
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]()
proc connHandler(conn: Connection) {.async, gcsafe.} =
@ -417,7 +417,7 @@ suite "Mplex":
test "e2e - multiple read/write streams":
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]()
proc connHandler(conn: Connection) {.async, gcsafe.} =
@ -461,7 +461,7 @@ suite "Mplex":
test "jitter - channel should be able to handle erratic read/writes":
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]()
const MsgSize = 1024
@ -529,7 +529,7 @@ suite "Mplex":
test "jitter - channel should handle 1 byte read/write":
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]()
const MsgSize = 512

View File

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

View File

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

View File

@ -236,7 +236,7 @@ suite "Multistream select":
test "e2e - handle":
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
handlerWait1 = newFuture[void]()
@ -283,7 +283,7 @@ suite "Multistream select":
test "e2e - ls":
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
handlerWait = newFuture[void]()
@ -331,7 +331,7 @@ suite "Multistream select":
test "e2e - select one from a list with unsupported protos":
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
proc testHandler(conn: Connection,
@ -371,7 +371,7 @@ suite "Multistream select":
test "e2e - select one with both valid":
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
proc testHandler(conn: Connection,

View File

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

View File

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

View File

@ -16,7 +16,7 @@ suite "TCP transport":
test "test listener: handle write":
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]()
proc connHandler(conn: Connection) {.async, gcsafe.} =
await conn.write(cstring("Hello!"), 6)
@ -42,7 +42,7 @@ suite "TCP transport":
test "test listener: handle read":
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]()
proc connHandler(conn: Connection) {.async, gcsafe.} =
var msg = newSeq[byte](6)
@ -82,7 +82,7 @@ suite "TCP transport":
var server = createStreamServer(address, serveClient, {ReuseAddr})
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 conn = await transport.dial(ma)
var msg = newSeq[byte](6)
@ -119,7 +119,7 @@ suite "TCP transport":
var server = createStreamServer(address, serveClient, {ReuseAddr})
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 conn = await transport.dial(ma)
await conn.write(cstring("Hello!"), 6)
@ -138,7 +138,7 @@ suite "TCP transport":
test "e2e: handle write":
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]()
proc connHandler(conn: Connection) {.async, gcsafe.} =
await conn.write(cstring("Hello!"), 6)
@ -166,7 +166,7 @@ suite "TCP transport":
test "e2e: handle read":
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]()
proc connHandler(conn: Connection) {.async, gcsafe.} =
var msg = newSeq[byte](6)

View File

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