remove remaining `int` holdouts in rlp (#737)

these were never well defined
This commit is contained in:
Jacek Sieka 2024-09-30 18:32:36 +02:00 committed by GitHub
parent b49df0a71a
commit 119c910a4e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 112 additions and 107 deletions

View File

@ -35,7 +35,7 @@ type
msgResponse
Message* = ref object
id*: Opt[uint]
id*: Opt[uint64]
ident*: NimNode
kind*: MessageKind
procDef*: NimNode
@ -83,7 +83,7 @@ type
P2PProtocol* = ref object
# Settings
name*: string
version*: int
version*: uint64
timeouts*: int64
useRequestIds*: bool
useSingleRecordInlining*: bool
@ -148,8 +148,7 @@ const
let
# Variable names affecting the public interface of the library:
reqIdVar* {.compileTime.} = ident "reqId"
# XXX: Binding the int type causes instantiation failure for some reason
ReqIdType* {.compileTime.} = ident "uint"
ReqIdType* {.compileTime.} = ident "uint64"
peerVar* {.compileTime.} = ident "peer"
responseVar* {.compileTime.} = ident "response"
streamVar* {.compileTime.} = ident "stream"
@ -313,7 +312,7 @@ proc verifyStateType(t: NimNode): NimNode =
proc processProtocolBody*(p: P2PProtocol, protocolBody: NimNode)
proc init*(T: type P2PProtocol, backendFactory: BackendFactory,
name: string, version: int, body: NimNode,
name: string, version: uint64, body: NimNode,
timeouts: int64, useRequestIds: bool, rlpxName: string,
outgoingRequestDecorator: NimNode,
incomingRequestDecorator: NimNode,
@ -345,14 +344,14 @@ proc init*(T: type P2PProtocol, backendFactory: BackendFactory,
assert(not result.backend.implementProtocolInit.isNil)
if result.backend.ReqIdType.isNil:
result.backend.ReqIdType = ident "uint"
result.backend.ReqIdType = ident "uint64"
result.processProtocolBody body
if not result.backend.afterProtocolInit.isNil:
result.backend.afterProtocolInit(result)
proc augmentUserHandler(p: P2PProtocol, userHandlerProc: NimNode, msgId = Opt.none(uint)) =
proc augmentUserHandler(p: P2PProtocol, userHandlerProc: NimNode, msgId = Opt.none(uint64)) =
## This procs adds a set of common helpers available in all messages handlers
## (e.g. `perProtocolMsgId`, `peer.state`, etc).
@ -446,7 +445,7 @@ proc ResponderType(msg: Message): NimNode =
proc needsSingleParamInlining(msg: Message): bool =
msg.recBody.kind == nnkDistinctTy
proc newMsg(protocol: P2PProtocol, kind: MessageKind, msgId: uint,
proc newMsg(protocol: P2PProtocol, kind: MessageKind, msgId: uint64,
procDef: NimNode, response: Message = nil): Message =
if procDef[0].kind == nnkPostfix:
@ -528,7 +527,7 @@ proc newMsg(protocol: P2PProtocol, kind: MessageKind, msgId: uint,
proc isVoid(t: NimNode): bool =
t.kind == nnkEmpty or eqIdent(t, "void")
proc addMsg(p: P2PProtocol, msgId: uint, procDef: NimNode) =
proc addMsg(p: P2PProtocol, msgId: uint64, procDef: NimNode) =
var
returnType = procDef.params[0]
hasReturnValue = not isVoid(returnType)
@ -544,7 +543,7 @@ proc addMsg(p: P2PProtocol, msgId: uint, procDef: NimNode) =
let
responseIdent = ident($procDef.name & "Response")
response = Message(protocol: p,
id: Opt.none(uint),
id: Opt.none(uint64),
ident: responseIdent,
kind: msgResponse,
recName: returnType,
@ -871,7 +870,7 @@ proc processProtocolBody*(p: P2PProtocol, protocolBody: NimNode) =
##
## All messages will have properly computed numeric IDs
##
var nextId = 0u
var nextId = 0u64
for n in protocolBody:
case n.kind
@ -880,7 +879,7 @@ proc processProtocolBody*(p: P2PProtocol, protocolBody: NimNode) =
# By default message IDs are assigned in increasing order
# `nextID` can be used to skip some of the numeric slots
if n.len == 2 and n[1].kind == nnkIntLit:
nextId = n[1].intVal.uint
nextId = n[1].intVal.uint64
else:
error("nextID expects a single int value", n)
@ -895,10 +894,10 @@ proc processProtocolBody*(p: P2PProtocol, protocolBody: NimNode) =
error "requestResponse expects a block with at least two proc definitions"
var queries = newSeq[Message]()
let responseMsg = p.newMsg(msgResponse, nextId + procs.len.uint - 1, procs[^1])
let responseMsg = p.newMsg(msgResponse, nextId + procs.len.uint64 - 1, procs[^1])
for i in 0 .. procs.len - 2:
queries.add p.newMsg(msgRequest, nextId + i.uint, procs[i], response = responseMsg)
queries.add p.newMsg(msgRequest, nextId + i.uint64, procs[i], response = responseMsg)
p.requests.add Request(queries: queries, response: responseMsg)
@ -991,7 +990,7 @@ proc genTypeSection*(p: P2PProtocol): NimNode =
if p.isRlpx:
result.add quote do:
template msgId*(`MSG`: type `msgStrongRecName`): uint = `msgId`
template msgId*(`MSG`: type `msgStrongRecName`): uint64 = `msgId`
proc genCode*(p: P2PProtocol): NimNode =
for msg in p.messages:
@ -1027,7 +1026,7 @@ proc genCode*(p: P2PProtocol): NimNode =
macro emitForSingleBackend(
name: static[string],
version: static[int],
version: static[uint64],
backend: static[BackendFactory],
body: untyped,
# TODO Nim can't handle a proper duration parameter here

View File

@ -40,7 +40,7 @@ type
protocolStates*: seq[RootRef]
discovery*: DiscoveryProtocol
when useSnappy:
protocolVersion*: uint
protocolVersion*: uint64
rng*: ref HmacDrbgContext
Peer* = ref object
@ -50,7 +50,7 @@ type
# Private fields:
transport*: StreamTransport
dispatcher*: Dispatcher
lastReqId*: Opt[uint]
lastReqId*: Opt[uint64]
secretsState*: SecretState
connectionState*: ConnectionState
protocolStates*: seq[RootRef]
@ -86,7 +86,7 @@ type
Capability* = object
name*: string
version*: int
version*: uint64
EthP2PError* = object of CatchableError
@ -112,7 +112,7 @@ type
ProtocolInfo* = ref object
name*: string
version*: int
version*: uint64
messages*: seq[MessageInfo]
index*: int # the position of the protocol in the
# ordered list of supported protocols
@ -124,7 +124,7 @@ type
disconnectHandler*: DisconnectionHandler
MessageInfo* = ref object
id*: uint # this is a `msgId` (as opposed to a `reqId`)
id*: uint64 # this is a `msgId` (as opposed to a `reqId`)
name*: string
# Private fields:
@ -142,11 +142,11 @@ type
# protocol. If the other peer also supports the protocol, the stored
# offset indicates the numeric value of the first message of the protocol
# (for this particular connection). If the other peer doesn't support the
# particular protocol, the stored offset is `Opt.none(uint)`.
# particular protocol, the stored offset is `Opt.none(uint64)`.
#
# `messages` holds a mapping from valid message IDs to their handler procs.
#
protocolOffsets*: seq[Opt[uint]]
protocolOffsets*: seq[Opt[uint64]]
messages*: seq[MessageInfo] # per `msgId` table (se above)
activeProtocols*: seq[ProtocolInfo]
@ -155,14 +155,14 @@ type
##
OutstandingRequest* = object
id*: uint # a `reqId` that may be used for response
id*: uint64 # a `reqId` that may be used for response
future*: FutureBase
timeoutAt*: Moment
# Private types:
MessageHandlerDecorator* = proc(msgId: uint, n: NimNode): NimNode
MessageHandlerDecorator* = proc(msgId: uint64, n: NimNode): NimNode
ThunkProc* = proc(x: Peer, msgId: uint, data: Rlp): Future[void]
ThunkProc* = proc(x: Peer, msgId: uint64, data: Rlp): Future[void]
{.gcsafe, async: (raises: [RlpError, EthP2PError]).}
MessageContentPrinter* = proc(msg: pointer): string

View File

@ -64,7 +64,7 @@ logScope:
type
ResponderWithId*[MsgType] = object
peer*: Peer
reqId*: uint
reqId*: uint64
ResponderWithoutId*[MsgType] = distinct Peer
@ -126,14 +126,14 @@ when tracingEnabled:
init, writeValue, getOutput
proc init*[MsgName](T: type ResponderWithId[MsgName],
peer: Peer, reqId: uint): T =
peer: Peer, reqId: uint64): T =
T(peer: peer, reqId: reqId)
proc init*[MsgName](T: type ResponderWithoutId[MsgName], peer: Peer): T =
T(peer)
chronicles.formatIt(Peer): $(it.remote)
chronicles.formatIt(Opt[uint]): (if it.isSome(): $it.value else: "-1")
chronicles.formatIt(Opt[uint64]): (if it.isSome(): $it.value else: "-1")
include p2p_backends_helpers
@ -247,9 +247,9 @@ proc getDispatcher(node: EthereumNode,
new result
newSeq(result.protocolOffsets, protocolCount())
result.protocolOffsets.fill Opt.none(uint)
result.protocolOffsets.fill Opt.none(uint64)
var nextUserMsgId = 0x10u
var nextUserMsgId = 0x10u64
for localProtocol in node.protocols:
let idx = localProtocol.index
@ -258,7 +258,7 @@ proc getDispatcher(node: EthereumNode,
if localProtocol.name == remoteCapability.name and
localProtocol.version == remoteCapability.version:
result.protocolOffsets[idx] = Opt.some(nextUserMsgId)
nextUserMsgId += localProtocol.messages.len.uint
nextUserMsgId += localProtocol.messages.len.uint64
break findMatchingProtocol
template copyTo(src, dest; index: int) =
@ -275,9 +275,9 @@ proc getDispatcher(node: EthereumNode,
localProtocol.messages.copyTo(result.messages,
result.protocolOffsets[idx].value.int)
proc getMsgName*(peer: Peer, msgId: uint): string =
proc getMsgName*(peer: Peer, msgId: uint64): string =
if not peer.dispatcher.isNil and
msgId < peer.dispatcher.messages.len.uint and
msgId < peer.dispatcher.messages.len.uint64 and
not peer.dispatcher.messages[msgId].isNil:
return peer.dispatcher.messages[msgId].name
else:
@ -288,14 +288,14 @@ proc getMsgName*(peer: Peer, msgId: uint): string =
of 3: "pong"
else: $msgId
proc getMsgMetadata*(peer: Peer, msgId: uint): (ProtocolInfo, MessageInfo) =
proc getMsgMetadata*(peer: Peer, msgId: uint64): (ProtocolInfo, MessageInfo) =
doAssert msgId >= 0
let dpInfo = devp2pInfo()
if msgId <= dpInfo.messages[^1].id:
return (dpInfo, dpInfo.messages[msgId])
if msgId < peer.dispatcher.messages.len.uint:
if msgId < peer.dispatcher.messages.len.uint64:
let numProtocol = protocolCount()
for i in 0 ..< numProtocol:
let protocol = getProtocol(i)
@ -307,7 +307,7 @@ proc getMsgMetadata*(peer: Peer, msgId: uint): (ProtocolInfo, MessageInfo) =
# Protocol info objects
#
proc initProtocol(name: string, version: int,
proc initProtocol(name: string, version: uint64,
peerInit: PeerStateInitializer,
networkInit: NetworkStateInitializer): ProtocolInfo =
ProtocolInfo(
@ -338,13 +338,13 @@ proc nextMsgResolver[MsgType](msgData: Rlp, future: FutureBase)
MsgType.rlpFieldsCount > 1)
proc registerMsg(protocol: ProtocolInfo,
msgId: uint,
msgId: uint64,
name: string,
thunk: ThunkProc,
printer: MessageContentPrinter,
requestResolver: RequestResolver,
nextMsgResolver: NextMsgResolver) =
if protocol.messages.len.uint <= msgId:
if protocol.messages.len.uint64 <= msgId:
protocol.messages.setLen(msgId + 1)
protocol.messages[msgId] = MessageInfo(
id: msgId,
@ -357,7 +357,7 @@ proc registerMsg(protocol: ProtocolInfo,
# Message composition and encryption
#
proc perPeerMsgIdImpl(peer: Peer, proto: ProtocolInfo, msgId: uint): uint =
proc perPeerMsgIdImpl(peer: Peer, proto: ProtocolInfo, msgId: uint64): uint64 =
result = msgId
if not peer.dispatcher.isNil:
result += peer.dispatcher.protocolOffsets[proto.index].value
@ -373,10 +373,10 @@ proc supports*(peer: Peer, Protocol: type): bool =
## Checks whether a Peer supports a particular protocol
peer.supports(Protocol.protocolInfo)
template perPeerMsgId(peer: Peer, MsgType: type): uint =
template perPeerMsgId(peer: Peer, MsgType: type): uint64 =
perPeerMsgIdImpl(peer, MsgType.msgProtocol.protocolInfo, MsgType.msgId)
proc invokeThunk*(peer: Peer, msgId: uint, msgData: Rlp): Future[void]
proc invokeThunk*(peer: Peer, msgId: uint64, msgData: Rlp): Future[void]
{.async: (raises: [rlp.RlpError, EthP2PError]).} =
template invalidIdError: untyped =
raise newException(UnsupportedMessageError,
@ -384,7 +384,7 @@ proc invokeThunk*(peer: Peer, msgId: uint, msgData: Rlp): Future[void]
" on a connection supporting " & peer.dispatcher.describeProtocols)
# msgId can be negative as it has int as type and gets decoded from rlp
if msgId >= peer.dispatcher.messages.len.uint: invalidIdError()
if msgId >= peer.dispatcher.messages.len.uint64: invalidIdError()
if peer.dispatcher.messages[msgId].isNil: invalidIdError()
let thunk = peer.dispatcher.messages[msgId].thunk
@ -423,8 +423,8 @@ proc send*[Msg](peer: Peer, msg: Msg): Future[void] =
proc registerRequest(peer: Peer,
timeout: Duration,
responseFuture: FutureBase,
responseMsgId: uint): uint =
result = if peer.lastReqId.isNone: 0u else: peer.lastReqId.value + 1u
responseMsgId: uint64): uint64 =
result = if peer.lastReqId.isNone: 0u64 else: peer.lastReqId.value + 1u64
peer.lastReqId = Opt.some(result)
let timeoutAt = Moment.fromNow(timeout)
@ -440,7 +440,7 @@ proc registerRequest(peer: Peer,
discard setTimer(timeoutAt, timeoutExpired, nil)
proc resolveResponseFuture(peer: Peer, msgId: uint, msg: pointer) =
proc resolveResponseFuture(peer: Peer, msgId: uint64, msg: pointer) =
## This function is a split off from the previously combined version with
## the same name using optional request ID arguments. This here is the
## version without a request ID (there is the other part below.).
@ -485,7 +485,7 @@ proc resolveResponseFuture(peer: Peer, msgId: uint, msg: pointer) =
else:
trace "late or dup RPLx reply ignored", msgId
proc resolveResponseFuture(peer: Peer, msgId: uint, msg: pointer, reqId: uint) =
proc resolveResponseFuture(peer: Peer, msgId: uint64, msg: pointer, reqId: uint64) =
## Variant of `resolveResponseFuture()` for request ID argument.
logScope:
msg = peer.dispatcher.messages[msgId].name
@ -544,7 +544,7 @@ proc resolveResponseFuture(peer: Peer, msgId: uint, msg: pointer, reqId: uint) =
trace "late or dup RPLx reply ignored"
proc recvMsg*(peer: Peer): Future[tuple[msgId: uint, msgData: Rlp]] {.async.} =
proc recvMsg*(peer: Peer): Future[tuple[msgId: uint64, msgData: Rlp]] {.async.} =
## This procs awaits the next complete RLPx message in the TCP stream
var headerBytes: array[32, byte]
@ -610,7 +610,7 @@ proc recvMsg*(peer: Peer): Future[tuple[msgId: uint, msgData: Rlp]] {.async.} =
try:
# uint32 as this seems more than big enough for the amount of msgIds
msgId = rlp.read(uint32)
result = (msgId.uint, rlp)
result = (msgId.uint64, rlp)
except RlpError:
await peer.disconnectAndRaise(BreachOfProtocol,
"Cannot read RLPx message id")
@ -680,7 +680,7 @@ proc nextMsg*(peer: Peer, MsgType: type): Future[MsgType] =
# message handler code as the TODO mentions already.
proc dispatchMessages*(peer: Peer) {.async.} =
while peer.connectionState notin {Disconnecting, Disconnected}:
var msgId: uint
var msgId: uint64
var msgData: Rlp
try:
(msgId, msgData) = await peer.recvMsg()
@ -721,7 +721,7 @@ proc dispatchMessages*(peer: Peer) {.async.} =
# The documentation will need to be updated, explaining the fact that
# nextMsg will be resolved only if the message handler has executed
# successfully.
if msgId < peer.awaitedMessages.len.uint and
if msgId < peer.awaitedMessages.len.uint64 and
peer.awaitedMessages[msgId] != nil:
let msgInfo = peer.dispatcher.messages[msgId]
try:
@ -791,7 +791,7 @@ proc p2pProtocolBackendImpl*(protocol: P2PProtocol): Backend =
msgIdent = msg.ident
msgName = $msgIdent
msgRecName = msg.recName
responseMsgId = if msg.response.isNil: Opt.none(uint) else: msg.response.id
responseMsgId = if msg.response.isNil: Opt.none(uint64) else: msg.response.id
hasReqId = msg.hasReqId
protocol = msg.protocol
@ -812,7 +812,7 @@ proc p2pProtocolBackendImpl*(protocol: P2PProtocol): Backend =
if hasReqId:
# Messages using request Ids
readParams.add quote do:
let `reqIdVar` = `read`(`receivedRlp`, uint)
let `reqIdVar` = `read`(`receivedRlp`, uint64)
case msg.kind
of msgRequest:
@ -887,7 +887,7 @@ proc p2pProtocolBackendImpl*(protocol: P2PProtocol): Backend =
thunkName = ident(msgName & "Thunk")
msg.defineThunk quote do:
proc `thunkName`(`peerVar`: `Peer`, _: uint, data: Rlp)
proc `thunkName`(`peerVar`: `Peer`, _: uint64, data: Rlp)
# Fun error if you just use `RlpError` instead of `rlp.RlpError`:
# "Error: type expected, but got symbol 'RlpError' of kind 'EnumField'"
{.async: (raises: [rlp.RlpError, EthP2PError]).} =
@ -973,7 +973,7 @@ proc p2pProtocolBackendImpl*(protocol: P2PProtocol): Backend =
p2pProtocol DevP2P(version = 5, rlpxName = "p2p"):
proc hello(peer: Peer,
version: uint,
version: uint64,
clientId: string,
capabilities: seq[Capability],
listenPort: uint,
@ -1082,7 +1082,7 @@ proc initPeerState*(peer: Peer, capabilities: openArray[Capability])
# Similarly, we need a bit of book-keeping data to keep track
# of the potentially concurrent calls to `nextMsg`.
peer.awaitedMessages.newSeq(peer.dispatcher.messages.len)
peer.lastReqId = Opt.some(0u)
peer.lastReqId = Opt.some(0u64)
peer.initProtocolStates peer.dispatcher.activeProtocols
proc postHelloSteps(peer: Peer, h: DevP2P.hello) {.async.} =
@ -1145,10 +1145,10 @@ proc initSecretState(p: Peer, hs: Handshake, authMsg, ackMsg: openArray[byte]) =
template setSnappySupport(peer: Peer, node: EthereumNode, handshake: Handshake) =
when useSnappy:
peer.snappyEnabled = node.protocolVersion >= devp2pSnappyVersion.uint and
handshake.version >= devp2pSnappyVersion.uint
peer.snappyEnabled = node.protocolVersion >= devp2pSnappyVersion.uint64 and
handshake.version >= devp2pSnappyVersion.uint64
template getVersion(handshake: Handshake): uint =
template getVersion(handshake: Handshake): uint64 =
when useSnappy:
handshake.version
else:
@ -1160,7 +1160,7 @@ template baseProtocolVersion(node: EthereumNode): untyped =
else:
devp2pVersion
template baseProtocolVersion(peer: Peer): uint =
template baseProtocolVersion(peer: Peer): uint64 =
when useSnappy:
if peer.snappyEnabled: devp2pSnappyVersion
else: devp2pVersion
@ -1473,10 +1473,10 @@ when isMainModule:
# are considered GcSafe. The short answer is that they aren't, because
# they dispatch into user code that might use the GC.
type
GcSafeDispatchMsg = proc (peer: Peer, msgId: uint, msgData: var Rlp)
GcSafeDispatchMsg = proc (peer: Peer, msgId: uint64, msgData: var Rlp)
GcSafeRecvMsg = proc (peer: Peer):
Future[tuple[msgId: uint, msgData: Rlp]] {.gcsafe.}
Future[tuple[msgId: uint64, msgData: Rlp]] {.gcsafe.}
GcSafeAccept = proc (transport: StreamTransport, myKeys: KeyPair):
Future[Peer] {.gcsafe.}

View File

@ -502,10 +502,7 @@ func validate*(self: Rlp) =
# score in order to facilitate easier overloading with user types:
template read*(rlp: var Rlp, T: type): auto =
when T is SomeSignedInt:
let value = readImpl(rlp, uint64)
if value > uint64(T.high()):
raiseIntOutOfBounds()
T value
{.error "Signed integer encoding is not defined for rlp".}
else:
readImpl(rlp, T)

View File

@ -301,15 +301,15 @@ proc appendImpl(self: var RlpWriter, data: tuple) {.inline.} =
# We define a single `append` template with a pretty low specificity
# score in order to facilitate easier overloading with user types:
template append*[T](w: var RlpWriter; data: T) =
when data is (SomeSignedInt|enum|bool):
when data is SomeSignedInt:
# TODO potentially remove signed integer support - we should never make it
# this far!
{.warning: "Signed integers cannot reliably be encoded using RLP".}
when data is (enum|bool):
# TODO detect negative enum values at compile time?
appendImpl(w, uint64(data))
else:
appendImpl(w, data)
template append*(w: var RlpWriter; data: SomeSignedInt) =
{.error: "Signed integer encoding is not defined for rlp".}
proc initRlpList*(listSize: int): RlpWriter =
result = initRlpWriter()
startList(result, listSize)

View File

@ -20,7 +20,7 @@ proc generate() =
# valid data for a Ping packet
block:
let payload = rlp.encode((4, fromAddr, toAddr, expiration()))
let payload = rlp.encode((uint64 4, fromAddr, toAddr, expiration()))
let encodedData = @[1.byte] & payload
debug "Ping", data=byteutils.toHex(encodedData)

View File

@ -23,9 +23,8 @@ test:
testDecode(payload, uint16)
testDecode(payload, uint32)
testDecode(payload, uint64)
testDecode(payload, int)
testDecode(payload, bool)
testDecode(payload, seq[byte])
testDecode(payload, (string, int32))
testDecode(payload, (string, uint32))
testDecode(payload, TestEnum)
testDecode(payload, TestObject)

View File

@ -64,16 +64,24 @@ suite "test api usage":
MyObj = object
a: array[3, char]
b: int
b: uint64
c: MyEnum
IntObj = object
v: int
var input: MyObj
input.a = ['e', 't', 'h']
input.b = 63
input.c = bar
var writer = initRlpWriter()
writer.append(input)
check:
not compiles(writer.append(default(IntObj)))
let bytes = writer.finish()
var rlp = rlpFromBytes(bytes)
@ -85,7 +93,7 @@ suite "test api usage":
var writer = initRlpList(3)
writer.append "foo"
writer.append ["bar", "baz"]
writer.append [30, 40, 50]
writer.append [uint64 30, 40, 50]
var
bytes = writer.finish
@ -108,14 +116,14 @@ suite "test api usage":
}
"""
bytes = encodeList(6000,
bytes = encodeList(uint64 6000,
"Lorem ipsum dolor sit amet",
"Donec ligula tortor, egestas eu est vitae")
rlp = rlpFromBytes bytes
check:
rlp.listLen == 3
rlp.listElem(0).toInt(int) == 6000
rlp.listElem(0).toInt(uint64) == 6000
rlp.listElem(1).toString == "Lorem ipsum dolor sit amet"
rlp.listElem(2).toString == "Donec ligula tortor, egestas eu est vitae"
@ -127,8 +135,8 @@ suite "test api usage":
check list.toString == "Lorem ipsum dolor sit amet"
list.skipElem
check list.toInt(int32) == 6000.int32
var intVar: int
check list.toInt(uint32) == 6000.uint32
var intVar: uint32
list >> intVar
check intVar == 6000
@ -146,19 +154,19 @@ suite "test api usage":
tok.toHex == "40ef02798f211da2e8173d37f255be908871ae65060dbb2f77fb29c0421447f4"
test "nested lists":
let listBytes = encode([[1, 2, 3], [5, 6, 7]])
let listBytes = encode([[uint64 1, 2, 3], [uint64 5, 6, 7]])
let listRlp = rlpFromBytes listBytes
let sublistRlp0 = listRlp.listElem(0)
let sublistRlp1 = listRlp.listElem(1)
check sublistRlp0.listElem(0).toInt(int) == 1
check sublistRlp0.listElem(1).toInt(int) == 2
check sublistRlp0.listElem(2).toInt(int) == 3
check sublistRlp1.listElem(0).toInt(int) == 5
check sublistRlp1.listElem(1).toInt(int) == 6
check sublistRlp1.listElem(2).toInt(int) == 7
check sublistRlp0.listElem(0).toInt(uint64) == 1
check sublistRlp0.listElem(1).toInt(uint64) == 2
check sublistRlp0.listElem(2).toInt(uint64) == 3
check sublistRlp1.listElem(0).toInt(uint64) == 5
check sublistRlp1.listElem(1).toInt(uint64) == 6
check sublistRlp1.listElem(2).toInt(uint64) == 7
test "encoding length":
let listBytes = encode([1,2,3,4,5])
let listBytes = encode([uint64 1,2,3,4,5])
let listRlp = rlpFromBytes listBytes
check listRlp.listLen == 5
@ -208,8 +216,8 @@ suite "test api usage":
bar = 0x01
var writer = initRlpWriter()
writer.append(1) # valid
writer.append(2) # invalid
writer.append(byte 1) # valid
writer.append(byte 2) # invalid
writer.append(cast[uint64](-1)) # invalid
let bytes = writer.finish()
var rlp = rlpFromBytes(bytes)
@ -231,10 +239,10 @@ suite "test api usage":
baz = 0x0100
var writer = initRlpWriter()
writer.append(1) # valid
writer.append(2) # invalid - enum hole value
writer.append(256) # valid
writer.append(257) # invalid - too large
writer.append(1'u64) # valid
writer.append(2'u64) # invalid - enum hole value
writer.append(256'u64) # valid
writer.append(257'u64) # invalid - too large
let bytes = writer.finish()
var rlp = rlpFromBytes(bytes)

View File

@ -9,7 +9,7 @@ type
HelloObj = object
version*: uint
clientId*: string
capabilities*: seq[(string,int)]
capabilities*: seq[(string,uint)]
listenPort*: uint
nodeId*: array[64, byte]

View File

@ -8,15 +8,15 @@ import
type
Transaction = object
amount: int
time: Time
amount: uint64
time: uint64
sender: string
receiver: string
Foo = object
x: uint64
y: string
z: seq[int]
z: seq[uint64]
Bar = object
b: string
@ -24,7 +24,7 @@ type
CustomSerialized = object
customFoo {.rlpCustomSerialization.}: Foo
ignored {.rlpIgnore.}: int
ignored {.rlpIgnore.}: uint64
rlpFields Foo,
x, y, z
@ -34,19 +34,19 @@ rlpFields Transaction,
proc append*(rlpWriter: var RlpWriter, holder: CustomSerialized, f: Foo) =
rlpWriter.append(f.x)
rlpWriter.append(f.y.len)
rlpWriter.append(uint64 f.y.len)
rlpWriter.append(holder.ignored)
proc read*(rlp: var Rlp, holder: var CustomSerialized, T: type Foo): Foo =
result.x = rlp.read(uint64)
result.y = newString(rlp.read(int))
holder.ignored = rlp.read(int) * 2
result.y = newString(rlp.read(uint64))
holder.ignored = rlp.read(uint64) * 2
proc suite() =
suite "object serialization":
test "encoding and decoding an object":
var originalBar = Bar(b: "abracadabra",
f: Foo(x: 5'u64, y: "hocus pocus", z: @[100, 200, 300]))
f: Foo(x: 5'u64, y: "hocus pocus", z: @[uint64 100, 200, 300]))
var bytes = encode(originalBar)
var r = rlpFromBytes(bytes)
@ -55,13 +55,13 @@ proc suite() =
check:
originalBar == restoredBar
var t1 = Transaction(time: getTime(), amount: 1000, sender: "Alice", receiver: "Bob")
var t1 = Transaction(time: 100, amount: 1000, sender: "Alice", receiver: "Bob")
bytes = encode(t1)
var t2 = bytes.decode(Transaction)
check:
bytes.toHex == "cd85416c69636583426f628203e8" # verifies that Alice comes first
t2.time == default(Time)
t2.time == 0
t2.sender == "Alice"
t2.receiver == "Bob"
t2.amount == 1000

View File

@ -9,9 +9,11 @@ proc append(output: var RlpWriter, js: JsonNode) =
of JNull, JFloat, JObject:
raise newException(ValueError, "Unsupported JSON value type " & $js.kind)
of JBool:
output.append js.bval.int
output.append js.bval
of JInt:
output.append int(js.num)
if js.num < 0:
raise newException(ValueError, "Integer out of range: " & $js.num)
output.append uint64(js.num)
of JString:
output.append js.str
of JArray: