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:
parent
195c8c60b4
commit
23c06ca6d2
|
@ -16,3 +16,4 @@ node_modules
|
|||
nohup.out
|
||||
hardhat.config.js
|
||||
package-lock.json
|
||||
test_null_conversion
|
||||
|
|
11
README.md
11
README.md
|
@ -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.
|
||||
|
|
|
@ -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"
|
|
@ -10,6 +10,7 @@
|
|||
{. warning[UnusedImport]:off .}
|
||||
|
||||
import
|
||||
test_null_conversion,
|
||||
test_primitives,
|
||||
test_contracts,
|
||||
test_deposit_contract,
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
|
@ -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()
|
||||
|
|
5
web3.nim
5
web3.nim
|
@ -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]
|
||||
|
||||
|
|
11
web3.nimble
11
web3.nimble
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) =
|
||||
|
|
Loading…
Reference in New Issue