From 526d954a018ed5d577c51dcb60ea3313027b8f20 Mon Sep 17 00:00:00 2001 From: Eric <5089238+emizzle@users.noreply.github.com> Date: Wed, 24 Jan 2024 18:09:47 +1100 Subject: [PATCH] Start fixing tests (mainly conversion fixes) --- ethers/provider.nim | 2 +- ethers/providers/jsonrpc/conversions.nim | 390 ++++++------------ ethers/providers/jsonrpc/json.nim | 2 +- .../providers/jsonrpc/testConversions.nim | 40 +- 4 files changed, 145 insertions(+), 289 deletions(-) diff --git a/ethers/provider.nim b/ethers/provider.nim index 51b1683..8fd3fe2 100644 --- a/ethers/provider.nim +++ b/ethers/provider.nim @@ -36,7 +36,7 @@ type Success = 1, Invalid = 2 TransactionResponse* = object - provider* {.serialize.}: Provider + provider*: Provider hash* {.serialize.}: TransactionHash TransactionReceipt* = object sender* {.serialize.}: ?Address diff --git a/ethers/providers/jsonrpc/conversions.nim b/ethers/providers/jsonrpc/conversions.nim index 1904027..8cdd5b0 100644 --- a/ethers/providers/jsonrpc/conversions.nim +++ b/ethers/providers/jsonrpc/conversions.nim @@ -36,316 +36,164 @@ proc expectFields(json: JsonNode, expectedFields: varargs[string]) = if not json.hasKey(fieldName): raiseSerializationError("'" & fieldName & "' field not found in " & $json) -# func fromJson*(T: type, json: JsonNode): T -# func fromJson*[T](json: JsonNode, result: var Option[T]) -# func fromJson*[T](json: JsonNode, result: var seq[T]) -# func fromJson*(json: JsonNode, result var T): T - - - -# byte sequence - -# func `%`*(bytes: seq[byte]): JsonNode = -# %("0x" & bytes.toHex) - -# func fromJson*(json: JsonNode, result: var seq[byte]) = -# result = hexToSeqByte(json.getStr()) - -# byte arrays - -# func `%`*[N](bytes: array[N, byte]): JsonNode = -# %("0x" & bytes.toHex) - -# func fromJson*[N](json: JsonNode, result: var array[N, byte]) = -# hexToByteArray(json.getStr(), result) - -# func fromJson*[N](json: JsonNode, result: var seq[array[N, byte]]) = -# for elem in json.getElems: -# var byteArr: array[N, byte] -# fromJson(elem, byteArr) -# result.add byteArr - # Address func `%`*(address: Address): JsonNode = %($address) -# func fromJson(jsonVal: string, result: var Address) = -# without address =? Address.init(jsonVal): -# raiseSerializationError "Failed to convert '" & jsonVal & "' to Address" -# result = address +func fromJson(_: type Address, json: JsonNode): ?!Address = + expectJsonKind(Address, JString, json) + without address =? Address.init(json.getStr), error: + return failure newException(SerializationError, + "Failed to convert '" & $json & "' to Address: " & error.msg) + success address -# func fromJson*(json: JsonNode, result: var Address) = -# let val = json.getStr -# fromJson(val, result) -proc readValue*(r: var JsonReader[JrpcConv], result: var Address) - {.raises: [SerializationError, IOError].} = - var val = r.readValue(string) - without address =? Address.init(val): - raiseSerializationError "Failed to convert '" & val & "' to Address" - result = address +# proc readValue*( +# r: var JsonReader[JrpcConv], +# result: var Address) {.raises: [SerializationError, IOError].} = -proc writeValue*( - writer: var JsonWriter[JrpcConv], - value: Address -) {.raises:[IOError].} = - writer.writeValue(%value) +# let json = r.readValue(JsonNode) +# result = Address.fromJson(json).getOrRaise(SerializationError) + +# proc writeValue*( +# writer: var JsonWriter[JrpcConv], +# value: Address +# ) {.raises:[IOError].} = +# writer.writeValue(%value) # Filter -func `%`*(filter: Filter): JsonNode = - %*{ - "fromBlock": filter.fromBlock, - "toBlock": filter.toBlock - } +# func `%`*(filter: Filter): JsonNode = +# %*{ +# "fromBlock": filter.fromBlock, +# "toBlock": filter.toBlock +# } -proc writeValue*( - writer: var JsonWriter[JrpcConv], - value: Filter -) {.raises:[IOError].} = - writer.writeValue(%value) +# proc writeValue*( +# writer: var JsonWriter[JrpcConv], +# value: Filter +# ) {.raises:[IOError].} = +# writer.writeValue(%value) # EventFilter -func `%`*(filter: EventFilter): JsonNode = - %*{ - "address": filter.address, - "topics": filter.topics - } -proc writeValue*( - writer: var JsonWriter[JrpcConv], - value: EventFilter -) {.raises:[IOError].} = - writer.writeValue(%value) +# func `%`*(filter: EventFilter): JsonNode = +# %*{ +# "address": filter.address, +# "topics": filter.topics +# } +# proc writeValue*( +# writer: var JsonWriter[JrpcConv], +# value: EventFilter +# ) {.raises:[IOError].} = +# writer.writeValue(%value) # UInt256 -# func `%`*(integer: UInt256): JsonNode = -# %("0x" & toHex(integer)) +func `%`*(integer: UInt256): JsonNode = + %("0x" & toHex(integer)) -# func fromJson*(json: JsonNode, result: var UInt256) = -# result = UInt256.fromHex(json.getStr()) +func fromJson*(_: type UInt256, json: JsonNode): ?!UInt256 = + without result =? UInt256.fromHex(json.getStr()).catch, error: + return UInt256.failure error.msg + success result -proc writeValue*( - w: var JsonWriter, value: StUint) {.inline, raises: [IOError].} = - w.writeValue $value +# proc writeValue*( +# w: var JsonWriter, value: StUint) {.inline, raises: [IOError].} = +# echo "writing UInt256 value to hex: ", value.toString, ", in hex: ", value.toHex +# w.writeValue %value -proc readValue*( - r: var JsonReader, value: var StUint -) {.inline, raises: [IOError, SerializationError].} = - let json = r.readValue(JsonNode) - value = typeof(value).fromJson(json).getOrRaise(SerializationError) +# proc readValue*( +# r: var JsonReader, value: var StUint +# ) {.inline, raises: [IOError, SerializationError].} = +# let json = r.readValue(JsonNode) +# value = typeof(value).fromJson(json).getOrRaise(SerializationError) -# # TransactionType +# TransactionHash -# func fromJson*(json: JsonNode, result: var TransactionType) = -# let val = fromHex[int](json.getStr) -# result = TransactionType(val) - -# func `%`*(txType: TransactionType): JsonNode = -# %("0x" & txType.int.toHex(1)) +# proc readValue*( +# r: var JsonReader, value: var TransactionHash +# ) {.inline, raises: [IOError, SerializationError].} = +# let json = r.readValue(JsonNode) +# value = TransactionHash.fromJson(json).getOrRaise(SerializationError) # Transaction -func `%`*(transaction: Transaction): JsonNode = - result = %{ "to": %transaction.to, "data": %transaction.data } - if sender =? transaction.sender: - result["from"] = %sender - if nonce =? transaction.nonce: - result["nonce"] = %nonce - if chainId =? transaction.chainId: - result["chainId"] = %chainId - if gasPrice =? transaction.gasPrice: - result["gasPrice"] = %gasPrice - if gasLimit =? transaction.gasLimit: - result["gas"] = %gasLimit - -proc writeValue*( - writer: var JsonWriter[JrpcConv], - value: Transaction -) {.raises:[IOError].} = - writer.writeValue(%value) +# proc writeValue*( +# writer: var JsonWriter[JrpcConv], +# value: Transaction +# ) {.raises:[IOError].} = +# writer.writeValue(%value) # Block -# func fromJson*(json: JsonNode, result: var Block) {.raises: [JsonSerializationError].} = -# var number: ?UInt256 -# var timestamp: UInt256 -# var hash: ?BlockHash -# expectFields json, "number", "timestamp", "hash" -# fromJson(json{"number"}, number) -# fromJson(json{"timestamp"}, timestamp) -# fromJson(json{"hash"}, hash) -# result = Block(number: number, timestamp: timestamp, hash: hash) -proc readValue*(r: var JsonReader[JrpcConv], result: var Option[Block]) - {.raises: [SerializationError, IOError].} = - var json = r.readValue(JsonNode) - if json.isNil or json.kind == JNull: - result = none Block +# proc readValue*(r: var JsonReader[JrpcConv], result: var Option[Block]) +# {.raises: [SerializationError, IOError].} = +# var json = r.readValue(JsonNode) +# if json.isNil or json.kind == JNull: +# result = none Block - # result = some Block() - # result.number = Json.decode(result{"number"}, Option[UInt256]) - result = Option[Block].fromJson(json).getOrRaise(SerializationError) - # without val =? Option[Block].fromJson(json) #.mapErr(e => newException(SerializationError, e.msg)) - # without blk =? Option[Block].fromJson(json), error: - # warn "failed to deserialize into Option[Block]", json - # result = none Block - # result = blk - # if json.isNil or json.kind == JNull: - # result = none Block - # var res: Block - # fromJson(Block, json, res) - # result = some res +# result = Option[Block].fromJson(json).getOrRaise(SerializationError) # BlockTag -# func `%`*(blockTag: BlockTag): JsonNode = -# %($blockTag) +# proc writeValue*( +# writer: var JsonWriter[JrpcConv], +# value: BlockTag +# ) {.raises:[IOError].} = +# writer.writeValue($value) -proc writeValue*( - writer: var JsonWriter[JrpcConv], - value: BlockTag -) {.raises:[IOError].} = - writer.writeValue($value) +func `%`*(tag: BlockTag): JsonNode = + % $tag -proc readValue*(r: var JsonReader[JrpcConv], - result: var BlockTag) {.raises:[SerializationError, IOError].} = - var json = r.readValue(JsonNode) - result = BlockTag.fromJson(json).getOrRaise(SerializationError) +func fromJson*(_: type BlockTag, json: JsonNode): ?!BlockTag = + expectJsonKind(BlockTag, JString, json) + let jsonVal = json.getStr + if jsonVal[0..1].toLowerAscii == "0x": + without blkNum =? UInt256.fromHex(jsonVal).catch, error: + return BlockTag.failure error.msg + return success BlockTag.init(blkNum) -# Log + case jsonVal: + of "earliest": return success BlockTag.earliest + of "latest": return success BlockTag.latest + of "pending": return success BlockTag.pending + else: return failure newException(SerializationError, + "Failed to convert '" & $json & + "' to BlockTag: must be one of 'earliest', 'latest', 'pending'") -# func fromJson*(json: JsonNode, result: var Log) = -# expectFields json, "data", "topics" - -# var data: seq[byte] -# var topics: seq[Topic] -# fromJson(json["data"], data) -# fromJson(json["topics"], topics) -# result = Log(data: data, topics: topics) - -# TransactionStatus - -# func fromJson*(json: JsonNode, result: var TransactionStatus) = -# let val = fromHex[int](json.getStr) -# result = TransactionStatus(val) - -# func `%`*(status: TransactionStatus): JsonNode = -# %("0x" & status.int.toHex(1)) +# proc readValue*(r: var JsonReader[JrpcConv], +# result: var BlockTag) {.raises:[SerializationError, IOError].} = +# var json = r.readValue(JsonNode) +# result = BlockTag.fromJson(json).getOrRaise(SerializationError) # PastTransaction -proc readValue*(r: var JsonReader[JrpcConv], result: var Option[PastTransaction]) - {.raises: [SerializationError, IOError].} = - var json = r.readValue(JsonNode) - result = Option[PastTransaction].fromJson(json).getOrRaise(SerializationError) - -# func fromJson*(json: JsonNode, result: var PastTransaction) = -# # Deserializes a past transaction, eg eth_getTransactionByHash. -# # Spec: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionbyhash -# json.expectFields "blockHash", "blockNumber", "from", "gas", "gasPrice", -# "hash", "input", "nonce", "to", "transactionIndex", "value", -# "v", "r", "s" - -# result = PastTransaction( -# blockHash: BlockHash.fromJson(json["blockHash"]), #, "blockHash"), -# blockNumber: UInt256.fromJson(json["blockNumber"]), #, "blockNumber"), -# sender: Address.fromJson(json["from"]), #, "from"), -# gas: UInt256.fromJson(json["gas"]), #, "gas"), -# gasPrice: UInt256.fromJson(json["gasPrice"]), #, "gasPrice"), -# hash: TransactionHash.fromJson(json["hash"]), #, "hash"), -# input: seq[byte].fromJson(json["input"]), #, "input"), -# nonce: UInt256.fromJson(json["nonce"]), #, "nonce"), -# to: Address.fromJson(json["to"]), #, "to"), -# transactionIndex: UInt256.fromJson(json["transactionIndex"]), #, "transactionIndex"), -# value: UInt256.fromJson(json["value"]), #, "value"), -# v: UInt256.fromJson(json["v"]), #, "v"), -# r: UInt256.fromJson(json["r"]), #, "r"), -# s: UInt256.fromJson(json["s"]) #, "s"), -# ) -# if json.hasKey("type"): -# result.transactionType = fromJson(?TransactionType, json["type"], "type") -# if json.hasKey("chainId"): -# result.chainId = fromJson(?UInt256, json["chainId"], "chainId") - -# func `%`*(tx: PastTransaction): JsonNode = -# let json = %*{ -# "blockHash": tx.blockHash, -# "blockNumber": tx.blockNumber, -# "from": tx.sender, -# "gas": tx.gas, -# "gasPrice": tx.gasPrice, -# "hash": tx.hash, -# "input": tx.input, -# "nonce": tx.nonce, -# "to": tx.to, -# "transactionIndex": tx.transactionIndex, -# "value": tx.value, -# "v": tx.v, -# "r": tx.r, -# "s": tx.s -# } -# if txType =? tx.transactionType: -# json["type"] = %txType -# if chainId =? tx.chainId: -# json["chainId"] = %chainId -# return json +# proc readValue*(r: var JsonReader[JrpcConv], result: var Option[PastTransaction]) +# {.raises: [SerializationError, IOError].} = +# var json = r.readValue(JsonNode) +# result = Option[PastTransaction].fromJson(json).getOrRaise(SerializationError) # TransactionReceipt -proc readValue*(r: var JsonReader[JrpcConv], result: var Option[TransactionReceipt]) - {.raises: [SerializationError, IOError].} = +# proc readValue*(r: var JsonReader[JrpcConv], result: var Option[TransactionReceipt]) +# {.raises: [SerializationError, IOError].} = +# var json = r.readValue(JsonNode) +# result = Option[TransactionReceipt].fromJson(json).getOrRaise(SerializationError) + +proc writeValue*[T: not JsonNode]( + writer: var JsonWriter[JrpcConv], + value: T) {.raises:[IOError].} = + + writer.writeValue(%value) + +proc readValue*[T: not JsonNode]( + r: var JsonReader[JrpcConv], + result: var T) {.raises: [SerializationError, IOError].} = + var json = r.readValue(JsonNode) - result = Option[TransactionReceipt].fromJson(json).getOrRaise(SerializationError) - -# func fromJson*(json: JsonNode, result: var TransactionReceipt) = -# # Deserializes a transaction receipt, eg eth_getTransactionReceipt. -# # Spec: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionreceipt -# json.expectFields "transactionHash", "transactionIndex", "cumulativeGasUsed", -# "effectiveGasPrice", "gasUsed", "logs", "logsBloom", "type", -# "status" - -# result = TransactionReceipt( -# transactionHash: fromJson(TransactionHash, json["transactionHash"], "transactionHash"), -# transactionIndex: UInt256.fromJson(json["transactionIndex"], "transactionIndex"), -# blockHash: fromJson(?BlockHash, json["blockHash"], "blockHash"), -# blockNumber: fromJson(?UInt256, json["blockNumber"], "blockNumber"), -# sender: fromJson(?Address, json["from"], "from"), -# to: fromJson(?Address, json["to"], "to"), -# cumulativeGasUsed: UInt256.fromJson(json["cumulativeGasUsed"], "cumulativeGasUsed"), -# effectiveGasPrice: fromJson(?UInt256, json["effectiveGasPrice"], "effectiveGasPrice"), -# gasUsed: UInt256.fromJson(json["gasUsed"], "gasUsed"), -# contractAddress: fromJson(?Address, json["contractAddress"], "contractAddress"), -# logs: seq[Log].fromJson(json["logs"], "logs"), -# logsBloom: seq[byte].fromJson(json["logsBloom"], "logsBloom"), -# transactionType: TransactionType.fromJson(json["type"], "type"), -# status: TransactionStatus.fromJson(json["status"], "status") -# ) - -# func fromJson*[T](json: JsonNode, result: var Option[T]) = -# if json.isNil or json.kind == JNull: -# result = none T -# return - -# var val: T -# fromJson(json, val) -# result = some val -# # if val =? T.fromJson(json): -# # result = some val - -# # # result = none T - -# func fromJson*[T](json: JsonNode, name = "", result: var seq[T]) = -# if json.kind != JArray: -# raiseSerializationError(fmt"Expected JArray to convert to seq, but got {json.kind}") - -# for elem in json.elems: -# var v: T -# fromJson(elem, name, v) -# result.add(v) - -# func fromJson*(T: type, json: JsonNode, name = ""): T = -# fromJson(json, name, result) - - -# func fromJson*(T: type, json: JsonNode, name = ""): T = -# fromJson(json, name, result) \ No newline at end of file + # when T of JsonNode: + # result = json + # return + # echo "[conversions.readValue] converting '", json, "' into ", T + static: echo "[conversions.readValue] converting into ", T + result = T.fromJson(json).getOrRaise(SerializationError) diff --git a/ethers/providers/jsonrpc/json.nim b/ethers/providers/jsonrpc/json.nim index 5160442..66f6194 100644 --- a/ethers/providers/jsonrpc/json.nim +++ b/ethers/providers/jsonrpc/json.nim @@ -63,7 +63,7 @@ template expectJsonKind( if json.isNil or json.kind notin expectedKinds: return failure(newUnexpectedKindError(expectedType, expectedKinds, json)) -template expectJsonKind( +template expectJsonKind*( expectedType: type, expectedKind: JsonNodeKind, json: JsonNode diff --git a/testmodule/providers/jsonrpc/testConversions.nim b/testmodule/providers/jsonrpc/testConversions.nim index 37ffb2b..6bee429 100644 --- a/testmodule/providers/jsonrpc/testConversions.nim +++ b/testmodule/providers/jsonrpc/testConversions.nim @@ -17,14 +17,16 @@ suite "JSON Conversions": "timestamp":"0x6285c293" } - var blk = Block.fromJson(json) - check blk.number.isNone + without blk1 =? Block.fromJson(json): + fail + check blk1.number.isNone json["number"] = newJString("") - blk = Block.fromJson(json) - check blk.number.isSome - check blk.number.get.isZero + without blk2 =? Block.fromJson(json): + fail + check blk2.number.isSome + check blk2.number.get.isZero test "missing block hash in Block isNone": @@ -37,7 +39,8 @@ suite "JSON Conversions": } } - var blk = Block.fromJson(blkJson["result"]) + without blk =? Block.fromJson(blkJson["result"]): + fail check blk.hash.isNone test "missing block number in TransactionReceipt isNone": @@ -67,13 +70,15 @@ suite "JSON Conversions": "type": "0x0" } - var receipt = TransactionReceipt.fromJson(json) - check receipt.blockNumber.isNone + without receipt1 =? TransactionReceipt.fromJson(json): + fail + check receipt1.blockNumber.isNone json["blockNumber"] = newJString("") - receipt = TransactionReceipt.fromJson(json) - check receipt.blockNumber.isSome - check receipt.blockNumber.get.isZero + without receipt2 =? TransactionReceipt.fromJson(json): + fail + check receipt2.blockNumber.isSome + check receipt2.blockNumber.get.isZero test "missing block hash in TransactionReceipt isNone": let json = %*{ @@ -102,7 +107,8 @@ suite "JSON Conversions": "type": "0x0" } - let receipt = TransactionReceipt.fromJson(json) + without receipt =? TransactionReceipt.fromJson(json): + fail check receipt.blockHash.isNone test "newHeads subcription raises exception when deserializing to Log": @@ -149,7 +155,8 @@ suite "JSON Conversions": "s":"0x33aa50bc8bd719b6b17ad0bf52006bf8943999198f2bf731eb33c118091000f2" } - let tx = PastTransaction.fromJson(json) + without tx =? PastTransaction.fromJson(json): + fail check tx.blockHash == BlockHash(array[32, byte].fromHex("0x595bffbe897e025ea2df3213c4cc52c3f3d69bc04b49011d558f1b0e70038922")) check tx.blockNumber == 0x22e.u256 check tx.sender == Address.init("0xe00b677c29ff8d8fe6068530e2bc36158c54dd34").get @@ -161,7 +168,7 @@ suite "JSON Conversions": check tx.to == Address.init("0x92f09aa59dccb892a9f5406ddd9c0b98f02ea57e").get check tx.transactionIndex == 0x3.u256 check tx.value == 0.u256 - check tx.transactionType == some TransactionType.Legacy + check tx.`type` == some TransactionType.Legacy check tx.chainId == some 0xc0de4.u256 check tx.v == 0x181bec.u256 check tx.r == UInt256.fromBytesBE(hexToSeqByte("0x57ba18460934526333b80b0fea08737c363f3cd5fbec4a25a8a25e3e8acb362a")) @@ -183,7 +190,7 @@ suite "JSON Conversions": v: 0x181bec.u256, r: UInt256.fromBytesBE(hexToSeqByte("0x57ba18460934526333b80b0fea08737c363f3cd5fbec4a25a8a25e3e8acb362a")), s: UInt256.fromBytesBE(hexToSeqByte("0x33aa50bc8bd719b6b17ad0bf52006bf8943999198f2bf731eb33c118091000f2")), - transactionType: some TransactionType.Legacy, + `type`: some TransactionType.Legacy, chainId: some 0xc0de4.u256 ) let expected = """ @@ -227,7 +234,8 @@ suite "JSON Conversions": "s":"0x33aa50bc8bd719b6b17ad0bf52006bf8943999198f2bf731eb33c118091000f2" } - let past = PastTransaction.fromJson(json) + without past =? PastTransaction.fromJson(json): + fail check %past.toTransaction == %*{ "to": !Address.init("0x92f09aa59dccb892a9f5406ddd9c0b98f02ea57e"), "data": hexToSeqByte("0x6368a471d26ff5c7f835c1a8203235e88846ce1a196d6e79df0eaedd1b8ed3deec2ae5c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000012a00000000000000000000000000000000000000000000000000000000000000"),