Bugfix/nully values (#61)

* Fix problem with contract out of assets

* Add nully value json test

* Fix bug with passing null to a few functions

* Typesafe U256 parsing

* Update readme for the web3 to include runner info

* Cleanup commits

Strip out unused JSON

Update comment

Remove echo

Added DynamicBytes test

More correct naming

Remove one extra double check

* Add specific object tests

* Ensure we cover different status types

* Add header comments

* Cleanup

* Add more tests

* Cleanup

* Revert docs

* Nimpretty file

* Fix issue in base stew

* v0.2.4

* Fix test

---------

Co-authored-by: jangko <jangko128@gmail.com>
This commit is contained in:
Will 2023-12-14 07:56:54 +08:00 committed by GitHub
parent 195c8c60b4
commit 23c06ca6d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 162 additions and 27 deletions

1
.gitignore vendored
View File

@ -16,3 +16,4 @@ node_modules
nohup.out
hardhat.config.js
package-lock.json
test_null_conversion

View File

@ -10,18 +10,25 @@ The humble beginnings of a Nim library similar to web3.[js|py]
## Installation
You can install the developement version of the library through nimble with the following command
```
nimble install https://github.com/status-im/nim-web3@#master
```
## Development
You should first run `./simulator.sh` which runs `ganache-cli`
This creates a local simulated Ethereum network on your local machine and the tests will use this for their E2E processing
## License
Licensed and distributed under either of
* MIT license: [LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT
- MIT license: [LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT
or
* Apache License, Version 2.0, ([LICENSE-APACHEv2](LICENSE-APACHEv2) or http://www.apache.org/licenses/LICENSE-2.0)
- Apache License, Version 2.0, ([LICENSE-APACHEv2](LICENSE-APACHEv2) or http://www.apache.org/licenses/LICENSE-2.0)
at your option. This file may not be copied, modified, or distributed except according to those terms.

12
simulator.sh Executable file
View File

@ -0,0 +1,12 @@
#!/usr/bin/env bash
# NOTE: Requires nodemon (https://github.com/remy/nodemon)
# npm i -g nodemon
# Watch all nim files for changes
# When a file change is detected we will restart ganache-cli
# This ensures that our deposit contracts have enough ETH as
# it seems like some of the tests do not properly initialise
# their contracts at this time. (state persists across runs)
nodemon --ext '.nim' --watch tests --watch web3 --exec "ganache-cli"

View File

@ -10,6 +10,7 @@
{. warning[UnusedImport]:off .}
import
test_null_conversion,
test_primitives,
test_contracts,
test_deposit_contract,

View File

@ -69,4 +69,8 @@ suite "Deposit contract":
echo "hash_tree_root: ", await ns.get_deposit_root().call()
await web3.close()
waitFor test()
try:
waitFor test()
except CatchableError as err:
echo "Failed to process deposit contract", err.msg
fail()

View File

@ -0,0 +1,109 @@
import
std/[json, strutils],
pkg/unittest2,
stint,
json_rpc/jsonmarshal,
../web3,
../web3/[conversions, eth_api_types, engine_api_types]
template should_be_value_error(input: string, value: untyped): void =
expect ValueError:
fromJson(%input, "", value)
template should_not_error(input: string, value: untyped): void =
fromJson(%input, "", value)
suite "Null conversion":
var resAddress: Address
var resDynamicBytes: DynamicBytes[32]
var resFixedBytes: FixedBytes[5]
var resQuantity: Quantity
var resRlpEncodedBytes: RlpEncodedBytes
var resTypedTransaction: TypedTransaction
var resUInt256: UInt256
var resUInt256Ref: ref UInt256
## Covers the converters which can be found in web3/conversions.nim
## Ensure that when passing a nully value they respond with a ValueError
test "passing null values to normal convertors":
should_be_value_error("null", resAddress)
should_be_value_error("null", resDynamicBytes)
should_be_value_error("null", resFixedBytes)
should_be_value_error("null", resQuantity)
should_be_value_error("null", resRlpEncodedBytes)
should_be_value_error("null", resTypedTransaction)
should_be_value_error("null", resUInt256)
should_be_value_error("null", resUInt256Ref)
test "passing empty values to normal convertors":
should_be_value_error("", resAddress)
should_be_value_error("", resDynamicBytes)
should_be_value_error("", resFixedBytes)
should_be_value_error("", resQuantity)
should_be_value_error("", resRlpEncodedBytes)
should_be_value_error("", resTypedTransaction)
should_be_value_error("", resUInt256)
should_be_value_error("", resUInt256Ref)
test "passing invalid hex (0x) values to normal convertors":
should_be_value_error("0x", resAddress)
should_be_value_error("0x", resDynamicBytes)
should_be_value_error("0x", resFixedBytes)
should_be_value_error("0x", resQuantity)
should_be_value_error("0x", resUInt256)
should_be_value_error("0x", resUInt256Ref)
test "passing hex (0x) values to normal convertors":
should_not_error("0x", resRlpEncodedBytes)
should_not_error("0x", resTypedTransaction)
test "passing malformed hex (0x_) values to normal convertors":
should_be_value_error("0x_", resAddress)
should_be_value_error("0x_", resDynamicBytes)
should_be_value_error("0x_", resFixedBytes)
should_be_value_error("0x_", resQuantity)
should_be_value_error("0x_", resRlpEncodedBytes)
should_be_value_error("0x_", resTypedTransaction)
should_be_value_error("0x_", resUInt256)
should_be_value_error("0x_", resUInt256Ref)
## Covering the web3/engine_api_types
##
## NOTE: These will be transformed by the fromJson imported from
## nim-json-rpc/json_rpc/jsonmarshal
test "passing nully values to specific convertors":
let payloadAttributesV1 = """{ "timestamp": {item}, "prevRandao": {item}, "suggestedFeeRecipient": {item} }"""
let forkchoiceStateV1 = """{ "status": {item}, "safeBlockHash": {item}, "finalizedBlockHash": {item} }"""
let forkchoiceUpdatedResponse = """{ "payloadStatus": {item}, "payloadId": {item} }"""
let transitionConfigurationV1 = """{ "terminalTotalDifficulty": {item}, "terminalBlockHash": {item}, "terminalBlockNumber": {item} }"""
var resPayloadAttributesV1: PayloadAttributesV1
var resForkchoiceStateV1: ForkchoiceStateV1
var resForkchoiceUpdatedResponse: ForkchoiceUpdatedResponse
var resTransitionConfigurationV1: TransitionConfigurationV1
for item in @["null", "\"\"", "\"0x\"", "\"0x_\"", ""]:
template format(str: string): string =
str.replace("{item}", item)
should_be_value_error(payloadAttributesV1.format(), resPayloadAttributesV1)
should_be_value_error(forkchoiceStateV1.format(), resForkchoiceStateV1)
should_be_value_error(forkchoiceUpdatedResponse.format(), resForkchoiceUpdatedResponse)
should_be_value_error(transitionConfigurationV1.format(), resTransitionConfigurationV1)
## If different status types can have branching logic
## we should cover each status type with different null ops
test "passing nully values to specific status types":
var resPayloadStatusV1: PayloadStatusV1
for status_type in PayloadExecutionStatus:
let payloadStatusV1 = """{
"status": "status_name",
"latestValidHash": null,
"validationError": null
}""".replace("status_name", $status_type)
should_be_value_error(payloadStatusV1, resPayloadStatusV1)

View File

@ -105,4 +105,8 @@ suite "Signed transactions":
assert(n == 5.u256)
await web3.close()
waitFor test()
try:
waitFor test()
except CatchableError as err:
echo "Failed to send signed tx", err.msg
fail()

View File

@ -8,15 +8,14 @@
# those terms.
import
std/[options, math, json, tables, uri, strformat]
std/[options, json, tables, uri, strformat]
from os import DirSep, AltSep
from eth/common/eth_types import ChainId
import
stint, httputils, chronicles, chronos, nimcrypto/keccak,
stint, httputils, chronos,
json_rpc/[rpcclient, jsonmarshal], stew/byteutils, eth/keys,
chronos/apps/http/httpclient,
web3/[eth_api_types, conversions, ethhexstrings, transaction_signing, encoding, contract_dsl]

View File

@ -7,12 +7,11 @@
# This file may not be copied, modified, or distributed except according to
# those terms.
mode = ScriptMode.Verbose
version = "0.2.2"
author = "Status Research & Development GmbH"
description = "This is the humble begginings of library similar to web3.[js|py]"
license = "MIT or Apache License 2.0"
mode = ScriptMode.Verbose
version = "0.2.4"
author = "Status Research & Development GmbH"
description = "This is the humble begginings of library similar to web3.[js|py]"
license = "MIT or Apache License 2.0"
### Dependencies
requires "nim >= 1.6.0"

View File

@ -175,12 +175,6 @@ proc parseContract(body: NimNode): seq[InterfaceObject] =
macro contract*(cname: untyped, body: untyped): untyped =
var objects = parseContract(body)
result = newStmtList()
let
address = ident "address"
client = ident "client"
receipt = genSym(nskForVar)
receiver = ident "receiver"
eventListener = ident "eventListener"
result.add quote do:
type
`cname`* = object

View File

@ -34,6 +34,7 @@ template invalidQuantityPrefix(s: string): bool =
func `%`*(n: Int256|UInt256): JsonNode = %("0x" & n.toHex)
# allows UInt256 to be passed as a json string
func fromJson*(n: JsonNode, argName: string, result: var UInt256) =
# expects base 16 string, starting with "0x"
@ -43,7 +44,7 @@ func fromJson*(n: JsonNode, argName: string, result: var UInt256) =
raise newException(ValueError, "Parameter \"" & argName & "\" value too long for UInt256: " & $hexStr.len)
if hexStr.invalidQuantityPrefix:
raise newException(ValueError, "Parameter \"" & argName & "\" value has invalid leading 0")
result = hexStr.parse(StUint[256], 16) # TODO: Handle errors
result = hexStr.parse(StUint[256], 16) # TODO Add error checking
# allows ref UInt256 to be passed as a json string
func fromJson*(n: JsonNode, argName: string, result: var ref UInt256) =
@ -55,13 +56,18 @@ func fromJson*(n: JsonNode, argName: string, result: var ref UInt256) =
if hexStr.invalidQuantityPrefix:
raise newException(ValueError, "Parameter \"" & argName & "\" value has invalid leading 0")
new result
result[] = hexStr.parse(StUint[256], 16) # TODO: Handle errors
result[] = hexStr.parse(StUint[256], 16) # TODO Add error checking
func bytesFromJson(n: JsonNode, argName: string, result: var openArray[byte]) =
n.kind.expect(JString, argName)
let hexStr = n.getStr()
if not ("0x" in hexStr):
raise newException(ValueError, "Parameter \"" & argName & "\" is not a hexadecimal string")
if hexStr.len != result.len * 2 + 2: # including "0x"
raise newException(ValueError, "Parameter \"" & argName & "\" value wrong length: " & $hexStr.len)
hexToByteArray(hexStr, result)
func fromJson*[N](n: JsonNode, argName: string, result: var FixedBytes[N])

View File

@ -178,6 +178,5 @@ func encode*(x: tuple): seq[byte] =
inc i
# Obsolete
from stew/byteutils import hexToSeqByte
func decode*(input: string, offset: int, to: var DynamicBytes): int {.inline, deprecated: "Use decode(openarray[byte], ...) instead".} =
decode(hexToSeqByte(input), 0, offset div 2, to) * 2

View File

@ -172,10 +172,10 @@ type
# https://github.com/ethereum/execution-apis/blob/v1.0.0-beta.3/src/engine/paris.md#payloadstatusv1
PayloadExecutionStatus* {.pure.} = enum
syncing = "SYNCING"
valid = "VALID"
invalid = "INVALID"
accepted = "ACCEPTED"
syncing = "SYNCING"
valid = "VALID"
invalid = "INVALID"
accepted = "ACCEPTED"
invalid_block_hash = "INVALID_BLOCK_HASH"
PayloadStatusV1* = object

View File

@ -9,7 +9,7 @@
import
options,
eth_api_types, stew/byteutils, stint,
eth_api_types, stint,
eth/[common, keys, rlp], eth/common/transaction
func signTransaction(tr: var Transaction, pk: PrivateKey) =