Bump nim-web3 and others

Bump nim-json-rpc and nimbus-eth2 too.
Reason: both nim-json-rpc and nim-web3 migrate from
stdlib/json to nim-json-serialization
This commit is contained in:
jangko 2024-01-13 08:41:57 +07:00
parent 964b355dc8
commit 3e21281d12
No known key found for this signature in database
GPG Key ID: 31702AE10541E6B9
32 changed files with 359 additions and 331 deletions

View File

@ -1,12 +1,12 @@
# Nimbus # Nimbus
# Copyright (c) 2021-2022 Status Research & Development GmbH # Copyright (c) 2021-2024 Status Research & Development GmbH
# Licensed and distributed under either of # Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). # * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). # * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms. # at your option. This file may not be copied, modified, or distributed except according to those terms.
import import
std/os, std/[os, json],
json_rpc/rpcclient, json_rpc/rpcclient,
json_rpc/errors, # TODO: should be exported in json_rpc/clients/httpclient json_rpc/errors, # TODO: should be exported in json_rpc/clients/httpclient
./rpc_types, rpc_discovery_api # for the PongResponse ./rpc_types, rpc_discovery_api # for the PongResponse

View File

@ -1,3 +1,10 @@
# Nimbus
# Copyright (c) 2021-2024 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
## Portal State Network json-rpc calls ## Portal State Network json-rpc calls
proc portal_stateNodeInfo(): NodeInfo proc portal_stateNodeInfo(): NodeInfo
proc portal_stateRoutingTableInfo(): RoutingTableInfo proc portal_stateRoutingTableInfo(): RoutingTableInfo
@ -6,8 +13,7 @@ proc portal_stateAddEnrs(enrs: seq[Record]): bool
proc portal_stateGetEnr(nodeId: NodeId): Record proc portal_stateGetEnr(nodeId: NodeId): Record
proc portal_stateDeleteEnr(nodeId: NodeId): bool proc portal_stateDeleteEnr(nodeId: NodeId): bool
proc portal_stateLookupEnr(nodeId: NodeId): Record proc portal_stateLookupEnr(nodeId: NodeId): Record
proc portal_statePing(enr: Record): tuple[ proc portal_statePing(enr: Record): PingResult
enrSeq: uint64, customPayload: string]
proc portal_stateFindNodes(enr: Record): seq[Record] proc portal_stateFindNodes(enr: Record): seq[Record]
proc portal_stateFindContent(enr: Record, contentKey: string): JsonNode proc portal_stateFindContent(enr: Record, contentKey: string): JsonNode
proc portal_stateOffer( proc portal_stateOffer(
@ -26,8 +32,7 @@ proc portal_historyAddEnrs(enrs: seq[Record]): bool
proc portal_historyGetEnr(nodeId: NodeId): Record proc portal_historyGetEnr(nodeId: NodeId): Record
proc portal_historyDeleteEnr(nodeId: NodeId): bool proc portal_historyDeleteEnr(nodeId: NodeId): bool
proc portal_historyLookupEnr(nodeId: NodeId): Record proc portal_historyLookupEnr(nodeId: NodeId): Record
proc portal_historyPing(enr: Record): tuple[ proc portal_historyPing(enr: Record): PingResult
enrSeq: uint64, customPayload: string]
proc portal_historyFindNodes(enr: Record): seq[Record] proc portal_historyFindNodes(enr: Record): seq[Record]
proc portal_historyFindContent(enr: Record, contentKey: string): JsonNode proc portal_historyFindContent(enr: Record, contentKey: string): JsonNode
proc portal_historyOffer( proc portal_historyOffer(
@ -46,8 +51,7 @@ proc portal_beaconAddEnrs(enrs: seq[Record]): bool
proc portal_beaconGetEnr(nodeId: NodeId): Record proc portal_beaconGetEnr(nodeId: NodeId): Record
proc portal_beaconDeleteEnr(nodeId: NodeId): bool proc portal_beaconDeleteEnr(nodeId: NodeId): bool
proc portal_beaconLookupEnr(nodeId: NodeId): Record proc portal_beaconLookupEnr(nodeId: NodeId): Record
proc portal_beaconPing(enr: Record): tuple[ proc portal_beaconPing(enr: Record): PingResult
enrSeq: uint64, customPayload: string]
proc portal_beaconFindNodes(enr: Record): seq[Record] proc portal_beaconFindNodes(enr: Record): seq[Record]
proc portal_beaconFindContent(enr: Record, contentKey: string): JsonNode proc portal_beaconFindContent(enr: Record, contentKey: string): JsonNode
proc portal_beaconOffer( proc portal_beaconOffer(

View File

@ -1,5 +1,5 @@
# Nimbus # Nimbus
# Copyright (c) 2021-2023 Status Research & Development GmbH # Copyright (c) 2021-2024 Status Research & Development GmbH
# Licensed and distributed under either of # Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). # * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). # * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
@ -21,6 +21,8 @@ type
recipientIP: string recipientIP: string
recipientPort: uint16 recipientPort: uint16
PongResponse.useDefaultSerializationIn JrpcConv
proc installDiscoveryApiHandlers*(rpcServer: RpcServer|RpcProxy, proc installDiscoveryApiHandlers*(rpcServer: RpcServer|RpcProxy,
d: discv5_protocol.Protocol) = d: discv5_protocol.Protocol) =
## Discovery v5 JSON-RPC API such as defined here: ## Discovery v5 JSON-RPC API such as defined here:
@ -30,7 +32,7 @@ proc installDiscoveryApiHandlers*(rpcServer: RpcServer|RpcProxy,
return d.routingTable.getNodeInfo() return d.routingTable.getNodeInfo()
rpcServer.rpc("discv5_updateNodeInfo") do( rpcServer.rpc("discv5_updateNodeInfo") do(
kvPairs: seq[tuple[key: string, value: string]]) -> NodeInfo: kvPairs: seq[(string, string)]) -> NodeInfo:
# TODO: Not according to spec, as spec only allows socket address. # TODO: Not according to spec, as spec only allows socket address.
# portal-specs PR has been created with suggested change as is here. # portal-specs PR has been created with suggested change as is here.
let enrFields = kvPairs.map( let enrFields = kvPairs.map(

View File

@ -1,5 +1,5 @@
# Nimbus # Nimbus
# Copyright (c) 2021-2023 Status Research & Development GmbH # Copyright (c) 2021-2024 Status Research & Development GmbH
# Licensed and distributed under either of # Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). # * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). # * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
@ -8,13 +8,17 @@
{.push raises: [].} {.push raises: [].}
import import
std/sequtils, std/[sequtils, json],
json_rpc/[rpcproxy, rpcserver], stew/byteutils, json_rpc/[rpcproxy, rpcserver],
json_serialization/std/tables,
stew/byteutils,
eth/p2p/discoveryv5/nodes_verification, eth/p2p/discoveryv5/nodes_verification,
../network/wire/portal_protocol, ../network/wire/portal_protocol,
./rpc_types ./rpc_types
export rpcserver export
rpcserver,
tables
# Portal Network JSON-RPC impelentation as per specification: # Portal Network JSON-RPC impelentation as per specification:
# https://github.com/ethereum/portal-network-specs/tree/master/jsonrpc # https://github.com/ethereum/portal-network-specs/tree/master/jsonrpc
@ -24,6 +28,11 @@ type
content: string content: string
utpTransfer: bool utpTransfer: bool
ContentInfo.useDefaultSerializationIn JrpcConv
TraceContentLookupResult.useDefaultSerializationIn JrpcConv
TraceObject.useDefaultSerializationIn JrpcConv
NodeMetadata.useDefaultSerializationIn JrpcConv
TraceResponse.useDefaultSerializationIn JrpcConv
# Note: # Note:
# Using a string for the network parameter will give an error in the rpc macro: # Using a string for the network parameter will give an error in the rpc macro:
@ -87,7 +96,7 @@ proc installPortalApiHandlers*(
raise newException(ValueError, "Record not found in DHT lookup.") raise newException(ValueError, "Record not found in DHT lookup.")
rpcServer.rpc("portal_" & network & "Ping") do( rpcServer.rpc("portal_" & network & "Ping") do(
enr: Record) -> tuple[enrSeq: uint64, dataRadius: UInt256]: enr: Record) -> PingResult:
let let
node = toNodeWithAddress(enr) node = toNodeWithAddress(enr)
pong = await p.ping(node) pong = await p.ping(node)
@ -119,7 +128,7 @@ proc installPortalApiHandlers*(
return nodes.get().map(proc(n: Node): Record = n.record) return nodes.get().map(proc(n: Node): Record = n.record)
rpcServer.rpc("portal_" & network & "FindContent") do( rpcServer.rpc("portal_" & network & "FindContent") do(
enr: Record, contentKey: string) -> JsonNode: enr: Record, contentKey: string) -> JsonString:
let let
node = toNodeWithAddress(enr) node = toNodeWithAddress(enr)
foundContentResult = await p.findContent( foundContentResult = await p.findContent(
@ -131,14 +140,15 @@ proc installPortalApiHandlers*(
let foundContent = foundContentResult.get() let foundContent = foundContentResult.get()
case foundContent.kind: case foundContent.kind:
of Content: of Content:
return %ContentInfo( let res = ContentInfo(
content: foundContent.content.to0xHex(), content: foundContent.content.to0xHex(),
utpTransfer: foundContent.utpTransfer utpTransfer: foundContent.utpTransfer
) )
return JrpcConv.encode(res).JsonString
of Nodes: of Nodes:
var rpcRes = newJObject() let enrs = foundContent.nodes.map(proc(n: Node): Record = n.record)
rpcRes["enrs"] = %foundContent.nodes.map(proc(n: Node): Record = n.record) let jsonEnrs = JrpcConv.encode(enrs)
return rpcRes return ("{\"enrs\":" & jsonEnrs & "}").JsonString
rpcServer.rpc("portal_" & network & "Offer") do( rpcServer.rpc("portal_" & network & "Offer") do(
enr: Record, contentKey: string, contentValue: string) -> string: enr: Record, contentKey: string, contentValue: string) -> string:

View File

@ -1,5 +1,5 @@
# Nimbus # Nimbus
# Copyright (c) 2021-2023 Status Research & Development GmbH # Copyright (c) 2021-2024 Status Research & Development GmbH
# Licensed and distributed under either of # Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). # * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). # * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
@ -8,6 +8,7 @@
{.push raises: [].} {.push raises: [].}
import import
stint,
json_rpc/jsonmarshal, json_rpc/jsonmarshal,
stew/[results, byteutils], stew/[results, byteutils],
eth/p2p/discoveryv5/[routing_table, enr, node] eth/p2p/discoveryv5/[routing_table, enr, node]
@ -23,6 +24,12 @@ type
localNodeId*: NodeId localNodeId*: NodeId
buckets*: seq[seq[NodeId]] buckets*: seq[seq[NodeId]]
PingResult* = tuple[enrSeq: uint64, dataRadius: UInt256]
NodeInfo.useDefaultSerializationIn JrpcConv
RoutingTableInfo.useDefaultSerializationIn JrpcConv
(string,string).useDefaultSerializationIn JrpcConv
func getNodeInfo*(r: RoutingTable): NodeInfo = func getNodeInfo*(r: RoutingTable): NodeInfo =
NodeInfo(enr: r.localNode.record, nodeId: r.localNode.id) NodeInfo(enr: r.localNode.record, nodeId: r.localNode.id)
@ -50,49 +57,61 @@ func toNodeWithAddress*(enr: Record): Node {.raises: [ValueError].} =
else: else:
node node
func `%`*(value: Record): JsonNode = proc writeValue*(w: var JsonWriter[JrpcConv], v: Record)
newJString(value.toURI()) {.gcsafe, raises: [IOError].} =
w.writeValue(v.toURI())
func fromJson*(n: JsonNode, argName: string, result: var Record) proc readValue*(r: var JsonReader[JrpcConv], val: var Record)
{.raises: [ValueError].} = {.gcsafe, raises: [IOError, JsonReaderError].} =
n.kind.expect(JString, argName) if not fromURI(val, r.parseString()):
if not fromURI(result, n.getStr()): r.raiseUnexpectedValue("Invalid ENR")
raise newException(ValueError, "Invalid ENR")
func `%`*(value: NodeId): JsonNode = proc writeValue*(w: var JsonWriter[JrpcConv], v: NodeId)
%("0x" & value.toHex()) {.gcsafe, raises: [IOError].} =
w.writeValue("0x" & v.toHex())
func `%`*(value: Opt[NodeId]): JsonNode = proc writeValue*(w: var JsonWriter[JrpcConv], v: Opt[NodeId])
if value.isSome(): {.gcsafe, raises: [IOError].} =
%("0x" & value.get().toHex()) if v.isSome():
w.writeValue("0x" & v.get().toHex())
else: else:
%("0x") w.writeValue("0x")
func `%`*(value: Opt[seq[byte]]): JsonNode = proc readValue*(r: var JsonReader[JrpcConv], val: var NodeId)
if value.isSome(): {.gcsafe, raises: [IOError, JsonReaderError].} =
%(value.get().to0xHex()) try:
val = NodeId.fromHex(r.parseString())
except ValueError as exc:
r.raiseUnexpectedValue("NodeId parser error: " & exc.msg)
proc writeValue*(w: var JsonWriter[JrpcConv], v: Opt[seq[byte]])
{.gcsafe, raises: [IOError].} =
if v.isSome():
w.writeValue(v.get().to0xHex())
else: else:
%("0x") w.writeValue("0x")
func fromJson*(n: JsonNode, argName: string, result: var NodeId) proc readValue*(r: var JsonReader[JrpcConv], val: var seq[byte])
{.raises: [ValueError].} = {.gcsafe, raises: [IOError, JsonReaderError].} =
n.kind.expect(JString, argName) try:
val = hexToSeqByte(r.parseString())
except ValueError as exc:
r.raiseUnexpectedValue("seq[byte] parser error: " & exc.msg)
# TODO: fromHex (and thus parse) call seems to let pass several invalid proc writeValue*(w: var JsonWriter[JrpcConv], v: PingResult)
# UInt256. {.gcsafe, raises: [IOError].} =
result = UInt256.fromHex(n.getStr()) w.beginRecord()
w.writeField("enrSeq", v.enrSeq)
w.writeField("dataRadius", "0x" & v.dataRadius.toHex)
w.endRecord()
# TODO: This one should go to nim-json-rpc but before we can do that we will proc readValue*(r: var JsonReader[JrpcConv], val: var PingResult)
# have to update the vendor module to the current latest. {.gcsafe, raises: [IOError, SerializationError].} =
func fromJson*(n: JsonNode, argName: string, result: var uint16) try:
{.raises: [ValueError].} = for field in r.readObjectFields():
n.kind.expect(JInt, argName) case field:
let asInt = n.getBiggestInt() of "enrSeq": val.enrSeq = r.parseInt(uint64)
if asInt < 0: of "dataRadius": val.dataRadius = UInt256.fromHex(r.parseString())
raise newException( else: discard
ValueError, "JSON-RPC input is an unexpected negative value") except ValueError as exc:
if asInt > BiggestInt(uint16.high()): r.raiseUnexpectedValue("PingResult parser error: " & exc.msg)
raise newException(
ValueError, "JSON-RPC input is too large for uint32")
result = uint16(asInt)

View File

@ -1,5 +1,5 @@
# Nimbus - Portal Network # Nimbus - Portal Network
# Copyright (c) 2021 Status Research & Development GmbH # Copyright (c) 2021-2024 Status Research & Development GmbH
# Licensed and distributed under either of # Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). # * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). # * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
@ -48,7 +48,8 @@ procSuite "Discovery RPC":
asyncTest "Get local node info": asyncTest "Get local node info":
let tc = await setupTest(rng) let tc = await setupTest(rng)
let resp = await tc.client.call("discv5_nodeInfo", %[]) let jsonBytes = await tc.client.call("discv5_nodeInfo", %[])
let resp = JrpcConv.decode(jsonBytes.string, JsonNode)
check: check:
resp.contains("nodeId") resp.contains("nodeId")

View File

@ -669,7 +669,9 @@ proc run(config: BeaconBridgeConf) {.raises: [CatchableError].} =
waitFor (RpcHttpClient(web3Client.get())).connect(config.web3Url.get().web3Url) waitFor (RpcHttpClient(web3Client.get())).connect(config.web3Url.get().web3Url)
info "Listening to incoming network requests" info "Listening to incoming network requests"
network.initBeaconSync(cfg, forkDigests, genesisBlockRoot, getBeaconTime) network.registerProtocol(
PeerSync, PeerSync.NetworkState.init(
cfg, forkDigests, genesisBlockRoot, getBeaconTime))
network.addValidator( network.addValidator(
getBeaconBlocksTopic(forkDigests.phase0), getBeaconBlocksTopic(forkDigests.phase0),
proc (signedBlock: phase0.SignedBeaconBlock): errors.ValidationResult = proc (signedBlock: phase0.SignedBeaconBlock): errors.ValidationResult =

View File

@ -1,4 +1,4 @@
# Copyright (c) 2022-2023 Status Research & Development GmbH # Copyright (c) 2022-2024 Status Research & Development GmbH
# Licensed and distributed under either of # Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). # * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). # * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
@ -8,37 +8,39 @@
import import
std/hashes, std/[hashes, json],
json_rpc/jsonmarshal, json_rpc/jsonmarshal,
stew/[byteutils, endians2], stew/[byteutils, endians2],
eth/p2p/discoveryv5/node, eth/p2p/discoveryv5/node,
eth/utp/[utp_discv5_protocol, utp_router] eth/utp/[utp_discv5_protocol, utp_router]
export jsonmarshal export jsonmarshal, json
type SKey* = object type SKey* = object
id*: uint16 id*: uint16
nodeId*: NodeId nodeId*: NodeId
proc `%`*(value: SKey): JsonNode = proc writeValue*(w: var JsonWriter[JrpcConv], v: SKey)
let hex = value.nodeId.toBytesBE().toHex() {.gcsafe, raises: [IOError].} =
let numId = value.id.toBytesBE().toHex() let hex = v.nodeId.toBytesBE().toHex()
let numId = v.id.toBytesBE().toHex()
let finalStr = hex & numId let finalStr = hex & numId
newJString(finalStr) w.writeValue(finalStr)
proc fromJson*(n: JsonNode, argName: string, result: var SKey) proc readValue*(r: var JsonReader[JrpcConv], val: var SKey)
{.raises: [ValueError].} = {.gcsafe, raises: [IOError, JsonReaderError].} =
n.kind.expect(JString, argName) let str = r.parseString()
let str = n.getStr() if str.len < 64:
let strLen = len(str) r.raiseUnexpectedValue("SKey: too short string")
if (strLen >= 64):
try:
let nodeIdStr = str.substr(0, 63) let nodeIdStr = str.substr(0, 63)
let connIdStr = str.substr(64) let connIdStr = str.substr(64)
let nodeId = NodeId.fromHex(nodeIdStr) let nodeId = NodeId.fromHex(nodeIdStr)
let connId = uint16.fromBytesBE(connIdStr.hexToSeqByte()) let connId = uint16.fromBytesBE(connIdStr.hexToSeqByte())
result = SKey(nodeId: nodeId, id: connId) val = SKey(nodeId: nodeId, id: connId)
else: except ValueError as exc:
raise newException(ValueError, "Too short string") r.raiseUnexpectedValue("Skey parser error: " & exc.msg)
proc hash*(x: SKey): Hash = proc hash*(x: SKey): Hash =
var h = 0 var h = 0

View File

@ -1,4 +1,4 @@
# Copyright (c) 2022-2023 Status Research & Development GmbH # Copyright (c) 2022-2024 Status Research & Development GmbH
# Licensed and distributed under either of # Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). # * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). # * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
@ -17,7 +17,8 @@ import
eth/p2p/discoveryv5/enr, eth/p2p/discoveryv5/enr,
eth/utp/[utp_discv5_protocol, utp_router], eth/utp/[utp_discv5_protocol, utp_router],
eth/keys, eth/keys,
../../rpc/rpc_discovery_api ../../rpc/rpc_discovery_api,
./utp_rpc_types
const const
defaultListenAddress* = (static parseIpAddress("127.0.0.1")) defaultListenAddress* = (static parseIpAddress("127.0.0.1"))
@ -43,49 +44,14 @@ type AppConf* = object
desc: "RPC listening address" desc: "RPC listening address"
name: "rpc-listen-address" .}: IpAddress name: "rpc-listen-address" .}: IpAddress
proc `%`*(value: enr.Record): JsonNode = proc writeValue*(w: var JsonWriter[JrpcConv], v: Record)
newJString(value.toURI()) {.gcsafe, raises: [IOError].} =
w.writeValue(v.toURI())
proc fromJson*(n: JsonNode, argName: string, result: var Record) proc readValue*(r: var JsonReader[JrpcConv], val: var Record)
{.raises: [ValueError].} = {.gcsafe, raises: [IOError, JsonReaderError].} =
n.kind.expect(JString, argName) if not fromURI(val, r.parseString()):
echo "ENr looks " & n.getStr() r.raiseUnexpectedValue("Invalid ENR")
if not fromURI(result, n.getStr()):
raise newException(ValueError, "Invalid ENR")
type SKey = object
id: uint16
nodeId: NodeId
proc `%`*(value: SKey): JsonNode =
let hex = value.nodeId.toBytesBE().toHex()
let numId = value.id.toBytesBE().toHex()
let finalStr = hex & numId
newJString(finalStr)
proc fromJson*(n: JsonNode, argName: string, result: var SKey)
{.raises: [ValueError].} =
n.kind.expect(JString, argName)
let str = n.getStr()
let strLen = len(str)
if (strLen >= 64):
let nodeIdStr = str.substr(0, 63)
let connIdStr = str.substr(64)
let nodeId = NodeId.fromHex(nodeIdStr)
let connId = uint16.fromBytesBE(connIdStr.hexToSeqByte())
result = SKey(nodeId: nodeId, id: connId)
else:
raise newException(ValueError, "Too short string")
proc hash(x: SKey): Hash =
var h = 0
h = h !& x.id.hash
h = h !& x.nodeId.hash
!$h
func toSKey(k: UtpSocketKey[NodeAddress]): SKey =
SKey(id: k.rcvId, nodeId: k.remoteAddress.nodeId)
proc installUtpHandlers( proc installUtpHandlers(
srv: RpcHttpServer, srv: RpcHttpServer,

View File

@ -1,5 +1,5 @@
# Nimbus # Nimbus
# Copyright (c) 2023 Status Research & Development GmbH # Copyright (c) 2023-2024 Status Research & Development GmbH
# Licensed under either of # Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or # * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0) # http://www.apache.org/licenses/LICENSE-2.0)
@ -14,6 +14,7 @@ import
chronicles, chronicles,
nimcrypto/[hmac], nimcrypto/[hmac],
web3/engine_api_types, web3/engine_api_types,
web3/conversions,
json_rpc/[rpcclient], json_rpc/[rpcclient],
./types ./types
@ -23,6 +24,9 @@ const
maxTimeDriftSeconds = 60'i64 maxTimeDriftSeconds = 60'i64
defaultProtectedHeader = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9" defaultProtectedHeader = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9"
createRpcSigsFromNim(RpcClient):
proc engine_exchangeTransitionConfigurationV1(transitionConfiguration: TransitionConfigurationV1): TransitionConfigurationV1
proc base64urlEncode(x: auto): string = proc base64urlEncode(x: auto): string =
base64.encode(x, safe = true).replace("=", "") base64.encode(x, safe = true).replace("=", "")
@ -62,7 +66,7 @@ template genAuthTest(procName: untyped, timeDriftSeconds: int64, customAuthSecre
let client = getClient(env, token) let client = getClient(env, token)
try: try:
discard waitFor client.call("engine_exchangeTransitionConfigurationV1", %[%tConf]) discard waitFor client.engine_exchangeTransitionConfigurationV1(tConf)
testCond authOk: testCond authOk:
error "Authentication was supposed to fail authentication but passed" error "Authentication was supposed to fail authentication but passed"
except CatchableError: except CatchableError:

View File

@ -1,5 +1,5 @@
# Nimbus # Nimbus
# Copyright (c) 2023 Status Research & Development GmbH # Copyright (c) 2023-2024 Status Research & Development GmbH
# Licensed under either of # Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or # * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0) # http://www.apache.org/licenses/LICENSE-2.0)
@ -208,19 +208,19 @@ proc verifyBeaconRootStorage*(client: RpcClient, payload: ExecutionPayload): boo
error "verifyBeaconRootStorage", msg=r.error error "verifyBeaconRootStorage", msg=r.error
return false return false
if r.get != payload.timestamp.uint64.u256: if r.get.u256 != payload.timestamp.uint64.u256:
error "verifyBeaconRootStorage storage 1", error "verifyBeaconRootStorage storage 1",
expect=payload.timestamp.uint64.u256, expect=payload.timestamp.uint64.u256,
get=r.get get=r.get.u256
return false return false
# Verify the beacon root key # Verify the beacon root key
r = client.storageAt(precompileAddress, beaconRootKey, blockNumber) r = client.storageAt(precompileAddress, beaconRootKey, blockNumber)
let parentBeaconBlockRoot = timestampToBeaconRoot(payload.timestamp) let parentBeaconBlockRoot = timestampToBeaconRoot(payload.timestamp)
if parentBeaconBlockRoot != beaconRoot(r.get): if parentBeaconBlockRoot != r.get:
error "verifyBeaconRootStorage storage 2", error "verifyBeaconRootStorage storage 2",
expect=parentBeaconBlockRoot.toHex, expect=parentBeaconBlockRoot.toHex,
get=beaconRoot(r.get).toHex get=r.get.toHex
return false return false
return true return true

View File

@ -1,5 +1,5 @@
# Nimbus # Nimbus
# Copyright (c) 2023 Status Research & Development GmbH # Copyright (c) 2023-2024 Status Research & Development GmbH
# Licensed under either of # Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or # * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0) # http://www.apache.org/licenses/LICENSE-2.0)
@ -522,12 +522,12 @@ proc txByHash*(client: RpcClient, txHash: Hash256): Result[RPCTx, string] =
return err("failed to get transaction: " & txHash.data.toHex) return err("failed to get transaction: " & txHash.data.toHex)
return ok(res.toRPCTx) return ok(res.toRPCTx)
proc storageAt*(client: RpcClient, address: EthAddress, slot: UInt256): Result[UInt256, string] = proc storageAt*(client: RpcClient, address: EthAddress, slot: UInt256): Result[FixedBytes[32], string] =
wrapTry: wrapTry:
let res = waitFor client.eth_getStorageAt(w3Addr(address), slot, blockId("latest")) let res = waitFor client.eth_getStorageAt(w3Addr(address), slot, blockId("latest"))
return ok(res) return ok(res)
proc storageAt*(client: RpcClient, address: EthAddress, slot: UInt256, number: common.BlockNumber): Result[UInt256, string] = proc storageAt*(client: RpcClient, address: EthAddress, slot: UInt256, number: common.BlockNumber): Result[FixedBytes[32], string] =
wrapTry: wrapTry:
let res = waitFor client.eth_getStorageAt(w3Addr(address), slot, blockId(number.truncate(uint64))) let res = waitFor client.eth_getStorageAt(w3Addr(address), slot, blockId(number.truncate(uint64)))
return ok(res) return ok(res)
@ -562,19 +562,30 @@ proc verifyPoWProgress*(client: RpcClient, lastBlockHash: Hash256): Future[Resul
return err("verify PoW Progress timeout") return err("verify PoW Progress timeout")
type
TraceOpts = object
disableStorage: bool
disableMemory: bool
disableState: bool
disableStateDiff: bool
TraceOpts.useDefaultSerializationIn JrpcConv
createRpcSigsFromNim(RpcClient):
proc debug_traceTransaction(hash: TxHash, opts: TraceOpts): JsonNode
proc debugPrevRandaoTransaction*(client: RpcClient, tx: Transaction, expectedPrevRandao: Hash256): Result[void, string] = proc debugPrevRandaoTransaction*(client: RpcClient, tx: Transaction, expectedPrevRandao: Hash256): Result[void, string] =
wrapTry: wrapTry:
let hash = w3Hash tx.rlpHash let hash = w3Hash tx.rlpHash
# we only interested in stack, disable all other elems # we only interested in stack, disable all other elems
let opts = %* { let opts = TraceOpts(
"disableStorage": true, disableStorage: true,
"disableMemory": true, disableMemory: true,
"disableState": true, disableState: true,
"disableStateDiff": true disableStateDiff: true
} )
let res = waitFor client.call("debug_traceTransaction", %[%hash, opts]) let res = waitFor client.debug_traceTransaction(hash, opts)
let structLogs = res["structLogs"] let structLogs = res["structLogs"]
var prevRandaoFound = false var prevRandaoFound = false
@ -607,8 +618,8 @@ template expectBalanceEqual*(res: Result[UInt256, string], account: EthAddress,
return err("invalid wd balance at $1, expect $2, get $3" % [ return err("invalid wd balance at $1, expect $2, get $3" % [
account.toHex, $expectedBalance, $res.get]) account.toHex, $expectedBalance, $res.get])
template expectStorageEqual*(res: Result[UInt256, string], account: EthAddress, template expectStorageEqual*(res: Result[FixedBytes[32], string], account: EthAddress,
expectedValue: UInt256): auto = expectedValue: FixedBytes[32]): auto =
if res.isErr: if res.isErr:
return err(res.error) return err(res.error)
if res.get != expectedValue: if res.get != expectedValue:

View File

@ -1,5 +1,5 @@
# Nimbus # Nimbus
# Copyright (c) 2023 Status Research & Development GmbH # Copyright (c) 2023-2024 Status Research & Development GmbH
# Licensed under either of # Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or # * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0) # http://www.apache.org/licenses/LICENSE-2.0)
@ -25,6 +25,6 @@ proc txInPayload*(payload: ExecutionPayload, txHash: common.Hash256): bool =
proc checkPrevRandaoValue*(client: RpcClient, expectedPrevRandao: common.Hash256, blockNumber: uint64): bool = proc checkPrevRandaoValue*(client: RpcClient, expectedPrevRandao: common.Hash256, blockNumber: uint64): bool =
let storageKey = blockNumber.u256 let storageKey = blockNumber.u256
let r = client.storageAt(prevRandaoContractAddr, storageKey) let r = client.storageAt(prevRandaoContractAddr, storageKey)
let expected = UInt256.fromBytesBE(expectedPrevRandao.data) let expected = FixedBytes[32](expectedPrevRandao.data)
r.expectStorageEqual(expected) r.expectStorageEqual(expected)
return true return true

View File

@ -1,5 +1,5 @@
# Nimbus # Nimbus
# Copyright (c) 2023 Status Research & Development GmbH # Copyright (c) 2023-2024 Status Research & Development GmbH
# Licensed under either of # Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or # * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0) # http://www.apache.org/licenses/LICENSE-2.0)
@ -86,9 +86,6 @@ func timestampToBeaconRoot*(timestamp: Quantity): FixedBytes[32] =
let h = keccakHash(timestamp.uint64.toBytesBE) let h = keccakHash(timestamp.uint64.toBytesBE)
FixedBytes[32](h.data) FixedBytes[32](h.data)
func beaconRoot*(x: UInt256): FixedBytes[32] =
FixedBytes[32](x.toByteArrayBE)
proc randomBytes*(_: type common.Hash256): common.Hash256 = proc randomBytes*(_: type common.Hash256): common.Hash256 =
doAssert randomBytes(result.data) == 32 doAssert randomBytes(result.data) == 32
@ -248,7 +245,7 @@ template expectHash*(res: untyped, hash: common.Hash256) =
testCond s.blockHash == hash: testCond s.blockHash == hash:
error "Unexpected expectHash", expect=hash.short, get=s.blockHash.short error "Unexpected expectHash", expect=hash.short, get=s.blockHash.short
template expectStorageEqual*(res: untyped, expectedValue: UInt256) = template expectStorageEqual*(res: untyped, expectedValue: FixedBytes[32]) =
testCond res.isOk: testCond res.isOk:
error "expectStorageEqual", msg=res.error error "expectStorageEqual", msg=res.error
testCond res.get == expectedValue: testCond res.get == expectedValue:

View File

@ -1,5 +1,5 @@
# Nimbus # Nimbus
# Copyright (c) 2023 Status Research & Development GmbH # Copyright (c) 2023-2024 Status Research & Development GmbH
# Licensed under either of # Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or # * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0) # http://www.apache.org/licenses/LICENSE-2.0)
@ -162,12 +162,12 @@ proc verifyContractsStorage(ws: WDBaseSpec, env: TestEnv): Result[void, string]
if latestPayloadNumber.truncate(int) >= ws.forkHeight: if latestPayloadNumber.truncate(int) >= ws.forkHeight:
# Shanghai # Shanghai
r.expectStorageEqual(WARM_COINBASE_ADDRESS, 100.u256) # WARM_STORAGE_READ_COST r.expectStorageEqual(WARM_COINBASE_ADDRESS, 100.u256.w3FixedBytes) # WARM_STORAGE_READ_COST
p.expectStorageEqual(PUSH0_ADDRESS, latestPayloadNumber) # tx succeeded p.expectStorageEqual(PUSH0_ADDRESS, latestPayloadNumber.w3FixedBytes) # tx succeeded
else: else:
# Pre-Shanghai # Pre-Shanghai
r.expectStorageEqual(WARM_COINBASE_ADDRESS, 2600.u256) # COLD_ACCOUNT_ACCESS_COST r.expectStorageEqual(WARM_COINBASE_ADDRESS, 2600.u256.w3FixedBytes) # COLD_ACCOUNT_ACCESS_COST
p.expectStorageEqual(PUSH0_ADDRESS, 0.u256) # tx must've failed p.expectStorageEqual(PUSH0_ADDRESS, 0.u256.w3FixedBytes) # tx must've failed
ok() ok()

View File

@ -1,5 +1,5 @@
# Nimbus # Nimbus
# Copyright (c) 2023 Status Research & Development GmbH # Copyright (c) 2023-2024 Status Research & Development GmbH
# Licensed under either of # Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or # * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0) # http://www.apache.org/licenses/LICENSE-2.0)
@ -14,7 +14,8 @@ import
json_rpc/[rpcclient], json_rpc/[rpcclient],
stew/[byteutils, results], stew/[byteutils, results],
../engine_client, ../engine_client,
../../../nimbus/utils/utils ../../../nimbus/utils/utils,
../../../nimbus/beacon/web3_eth_conv
type type
Withdrawals* = ref object Withdrawals* = ref object
@ -93,7 +94,7 @@ proc verifyWithdrawals*(wh: WDHistory, blockNumber: uint64, rpcBlock: Option[UIn
client.storageAt(account, 0.u256, rpcBlock.get) client.storageAt(account, 0.u256, rpcBlock.get)
else: else:
client.storageAt(account, 0.u256) client.storageAt(account, 0.u256)
s.expectStorageEqual(account, 0.u256) s.expectStorageEqual(account, 0.u256.w3FixedBytes)
ok() ok()
# Create a new copy of the withdrawals history # Create a new copy of the withdrawals history

View File

@ -1,5 +1,5 @@
# Nimbus # Nimbus
# Copyright (c) 2023 Status Research & Development GmbH # Copyright (c) 2023-2024 Status Research & Development GmbH
# Licensed under either of # Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE)) # * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
# * MIT license ([LICENSE-MIT](LICENSE-MIT)) # * MIT license ([LICENSE-MIT](LICENSE-MIT))
@ -101,7 +101,7 @@ proc validatePostState(node: JsonNode, t: TestEnv): bool =
echo sRes.error echo sRes.error
return false return false
if val != sRes.value: if val.w3FixedBytes != sRes.value:
echo "storage recieved from account 0x", echo "storage recieved from account 0x",
account.toHex, account.toHex,
" at slot 0x", " at slot 0x",

View File

@ -1,5 +1,5 @@
# Nimbus # Nimbus
# Copyright (c) 2023 Status Research & Development GmbH # Copyright (c) 2023-2024 Status Research & Development GmbH
# Licensed under either of # Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE)) # * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
# * MIT license ([LICENSE-MIT](LICENSE-MIT)) # * MIT license ([LICENSE-MIT](LICENSE-MIT))
@ -86,6 +86,9 @@ func u64*(x: Option[Web3Quantity]): Option[uint64] =
func u256*(x: Web3Quantity): UInt256 = func u256*(x: Web3Quantity): UInt256 =
u256(x.uint64) u256(x.uint64)
func u256*(x: FixedBytes[32]): UInt256 =
UInt256.fromBytesBE(x.bytes)
func ethTime*(x: Web3Quantity): common.EthTime = func ethTime*(x: Web3Quantity): common.EthTime =
common.EthTime(x) common.EthTime(x)
@ -103,7 +106,7 @@ func ethHashes*(list: openArray[Web3Hash]): seq[common.Hash256] =
func ethHashes*(list: Option[seq[Web3Hash]]): Option[seq[common.Hash256]] = func ethHashes*(list: Option[seq[Web3Hash]]): Option[seq[common.Hash256]] =
if list.isNone: none(seq[common.Hash256]) if list.isNone: none(seq[common.Hash256])
else: some ethHashes(list.get) else: some ethHashes(list.get)
func ethAddr*(x: Web3Address): common.EthAddress = func ethAddr*(x: Web3Address): common.EthAddress =
EthAddress x EthAddress x
@ -218,6 +221,9 @@ func w3Qty*(x: Option[uint64]): Option[Web3Quantity] =
func w3Qty*(x: uint64): Web3Quantity = func w3Qty*(x: uint64): Web3Quantity =
Web3Quantity(x) Web3Quantity(x)
func w3FixedBytes*(x: UInt256): FixedBytes[32] =
FixedBytes[32](x.toBytesBE)
func w3ExtraData*(x: common.Blob): Web3ExtraData = func w3ExtraData*(x: common.Blob): Web3ExtraData =
Web3ExtraData x Web3ExtraData x

View File

@ -25,17 +25,20 @@ import
../../../sync/protocol, ../../../sync/protocol,
../../../db/[core_db, distinct_tries, incomplete_db, storage_types], ../../../db/[core_db, distinct_tries, incomplete_db, storage_types],
../data_sources, ../data_sources,
../../../beacon/web3_eth_conv ../../../beacon/web3_eth_conv,
web3/conversions,
web3
when defined(legacy_eth66_enabled): when defined(legacy_eth66_enabled):
import import
../../../sync/protocol/eth66 as proto_eth66 ../../../sync/protocol/eth66 as proto_eth66
from ../../../sync/protocol/eth66 import getNodeData from ../../../sync/protocol/eth66 import getNodeData
from web3 import Web3, BlockHash, BlockObject, FixedBytes, Address, ProofResponse, StorageProof, newWeb3, fromJson, fromHex, eth_getBlockByHash, eth_getBlockByNumber, eth_getCode, eth_getProof, blockId, `%`
export AsyncOperationFactory, AsyncDataSource export AsyncOperationFactory, AsyncDataSource
type
BlockHeader = eth_types.BlockHeader
var durationSpentDoingFetches*: times.Duration var durationSpentDoingFetches*: times.Duration
var fetchCounter*: int var fetchCounter*: int

View File

@ -1,5 +1,5 @@
# Nimbus # Nimbus
# Copyright (c) 2018-2023 Status Research & Development GmbH # Copyright (c) 2018-2024 Status Research & Development GmbH
# Licensed under either of # Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE)) # * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
# * MIT license ([LICENSE-MIT](LICENSE-MIT)) # * MIT license ([LICENSE-MIT](LICENSE-MIT))
@ -29,6 +29,9 @@ type
ip : string # address string ip : string # address string
ports : NodePorts ports : NodePorts
NodePorts.useDefaultSerializationIn JrpcConv
NodeInfo.useDefaultSerializationIn JrpcConv
proc setupCommonRpc*(node: EthereumNode, conf: NimbusConf, server: RpcServer) = proc setupCommonRpc*(node: EthereumNode, conf: NimbusConf, server: RpcServer) =
server.rpc("web3_clientVersion") do() -> string: server.rpc("web3_clientVersion") do() -> string:
result = conf.agentString result = conf.agentString

View File

@ -1,5 +1,5 @@
# Nimbus # Nimbus
# Copyright (c) 2018-2023 Status Research & Development GmbH # Copyright (c) 2018-2024 Status Research & Development GmbH
# Licensed under either of # Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE)) # * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
# * MIT license ([LICENSE-MIT](LICENSE-MIT)) # * MIT license ([LICENSE-MIT](LICENSE-MIT))
@ -9,7 +9,7 @@
import import
std/json, std/json,
json_rpc/rpcserver, json_rpc/rpcserver,
./rpc_utils, ./rpc_utils,
./rpc_types, ./rpc_types,
../tracer, ../vm_types, ../tracer, ../vm_types,
@ -27,6 +27,8 @@ type
disableState: Option[bool] disableState: Option[bool]
disableStateDiff: Option[bool] disableStateDiff: Option[bool]
TraceOptions.useDefaultSerializationIn JrpcConv
proc isTrue(x: Option[bool]): bool = proc isTrue(x: Option[bool]): bool =
result = x.isSome and x.get() == true result = x.isSome and x.get() == true

View File

@ -1,5 +1,5 @@
# Nimbus # Nimbus
# Copyright (c) 2022-2023 Status Research & Development GmbH # Copyright (c) 2022-2024 Status Research & Development GmbH
# Licensed and distributed under either of # Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). # * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). # * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
@ -17,7 +17,6 @@ export rpc_types
type type
BlockHeader = eth_types.BlockHeader BlockHeader = eth_types.BlockHeader
Hash256 = eth_types.Hash256
{.push raises: [].} {.push raises: [].}
@ -28,13 +27,6 @@ proc topicToDigest(t: seq[eth_types.Topic]): seq[Web3Topic] =
resSeq.add(ht) resSeq.add(ht)
return resSeq return resSeq
func ethTopics(topics: openArray[Option[seq[Web3Hash]]]): seq[Option[seq[Hash256]]] =
for x in topics:
if x.isSome:
result.add some(ethHashes(x.get))
else:
result.add none(seq[Hash256])
proc deriveLogs*(header: BlockHeader, transactions: seq[Transaction], receipts: seq[Receipt]): seq[FilterLog] = proc deriveLogs*(header: BlockHeader, transactions: seq[Transaction], receipts: seq[Receipt]): seq[FilterLog] =
## Derive log fields, does not deal with pending log, only the logs with ## Derive log fields, does not deal with pending log, only the logs with
## full data set ## full data set
@ -67,37 +59,51 @@ proc deriveLogs*(header: BlockHeader, transactions: seq[Transaction], receipts:
return resLogs return resLogs
func participateInFilter(x: AddressOrList): bool =
if x.kind == slkNull:
return false
if x.kind == slkList:
if x.list.len == 0:
return false
true
proc bloomFilter*( proc bloomFilter*(
bloom: eth_types.BloomFilter, bloom: eth_types.BloomFilter,
addresses: seq[EthAddress], addresses: AddressOrList,
topics: seq[Option[seq[Hash256]]]): bool = topics: seq[TopicOrList]): bool =
let bloomFilter = bFilter.BloomFilter(value: StUint[2048].fromBytesBE(bloom)) let bloomFilter = bFilter.BloomFilter(value: StUint[2048].fromBytesBE(bloom))
if len(addresses) > 0: if addresses.participateInFilter():
var addrIncluded: bool = false var addrIncluded: bool = false
for address in addresses: if addresses.kind == slkSingle:
if bloomFilter.contains(address): addrIncluded = bloomFilter.contains(addresses.single.bytes)
addrIncluded = true elif addresses.kind == slkList:
break for address in addresses.list:
if bloomFilter.contains(address.bytes):
addrIncluded = true
break
if not addrIncluded: if not addrIncluded:
return false return false
for sub in topics: for sub in topics:
if sub.kind == slkNull:
if sub.isNone():
# catch all wildcard # catch all wildcard
continue continue
let subTops = sub.unsafeGet() var topicIncluded = false
var topicIncluded = len(subTops) == 0 if sub.kind == slkSingle:
for topic in subTops: if bloomFilter.contains(sub.single.bytes):
# This is is quite not obvious, but passing topic as MDigest256 fails, as
# it does not use internal keccak256 hashing. To achieve desired semantics,
# we need use digest bare bytes so that they will be properly kec256 hashes
if bloomFilter.contains(topic.data):
topicIncluded = true topicIncluded = true
break else:
topicIncluded = sub.list.len == 0
for topic in sub.list:
# This is is quite not obvious, but passing topic as MDigest256 fails, as
# it does not use internal keccak256 hashing. To achieve desired semantics,
# we need use digest bare bytes so that they will be properly kec256 hashes
if bloomFilter.contains(topic.bytes):
topicIncluded = true
break
if not topicIncluded: if not topicIncluded:
return false return false
@ -106,34 +112,29 @@ proc bloomFilter*(
proc headerBloomFilter*( proc headerBloomFilter*(
header: BlockHeader, header: BlockHeader,
addresses: seq[EthAddress], addresses: AddressOrList,
topics: seq[Option[seq[Hash256]]]): bool = topics: seq[TopicOrList]): bool =
return bloomFilter(header.bloom, addresses, topics) return bloomFilter(header.bloom, addresses, topics)
proc headerBloomFilter*( proc matchTopics(log: FilterLog, topics: seq[TopicOrList]): bool =
header: BlockHeader,
addresses: seq[Web3Address],
topics: seq[Option[seq[Web3Hash]]]): bool =
headerBloomFilter(header, addresses.ethAddrs, topics.ethTopics)
proc matchTopics(log: FilterLog, topics: seq[Option[seq[Hash256]]]): bool =
for i, sub in topics: for i, sub in topics:
if sub.isNone(): if sub.kind == slkNull:
# null subtopic i.e it matches all possible move to nex # null subtopic i.e it matches all possible move to nex
continue continue
let subTops = sub.unsafeGet() var match = false
if sub.kind == slkSingle:
# treat empty as wildcard, although caller should rather use none kind of match = log.topics[i] == sub.single
# option to indicate that. If nim would have NonEmptySeq type that would be else:
# use case for it. # treat empty as wildcard, although caller should rather use none kind of
var match = len(subTops) == 0 # option to indicate that. If nim would have NonEmptySeq type that would be
# use case for it.
for topic in subTops: match = sub.list.len == 0
if log.topics[i].ethHash == topic: for topic in sub.list:
match = true if log.topics[i] == topic:
break match = true
break
if not match: if not match:
return false return false
@ -142,13 +143,18 @@ proc matchTopics(log: FilterLog, topics: seq[Option[seq[Hash256]]]): bool =
proc filterLogs*( proc filterLogs*(
logs: openArray[FilterLog], logs: openArray[FilterLog],
addresses: seq[EthAddress], addresses: AddressOrList,
topics: seq[Option[seq[Hash256]]]): seq[FilterLog] = topics: seq[TopicOrList]): seq[FilterLog] =
var filteredLogs: seq[FilterLog] = newSeq[FilterLog]() var filteredLogs: seq[FilterLog] = newSeq[FilterLog]()
for log in logs: for log in logs:
if len(addresses) > 0 and (not addresses.contains(log.address.ethAddr)): if addresses.kind == slkSingle and (addresses.single != log.address):
continue
if addresses.kind == slkList and
addresses.list.len > 0 and
(not addresses.list.contains(log.address)):
continue continue
if len(topics) > len(log.topics): if len(topics) > len(log.topics):
@ -160,9 +166,3 @@ proc filterLogs*(
filteredLogs.add(log) filteredLogs.add(log)
return filteredLogs return filteredLogs
proc filterLogs*(
logs: openArray[FilterLog],
addresses: seq[Web3Address],
topics: seq[Option[seq[Web3Hash]]]): seq[FilterLog] =
filterLogs(logs, addresses.ethAddrs, topics.ethTopics)

View File

@ -59,7 +59,7 @@ proc setupEthRpc*(
server.rpc("eth_chainId") do() -> Web3Quantity: server.rpc("eth_chainId") do() -> Web3Quantity:
return w3Qty(distinctBase(com.chainId)) return w3Qty(distinctBase(com.chainId))
server.rpc("eth_syncing") do() -> JsonNode: server.rpc("eth_syncing") do() -> SyncingStatus:
## Returns SyncObject or false when not syncing. ## Returns SyncObject or false when not syncing.
# TODO: make sure we are not syncing # TODO: make sure we are not syncing
# when we reach the recent block # when we reach the recent block
@ -70,9 +70,9 @@ proc setupEthRpc*(
currentBlock : w3Qty com.syncCurrent, currentBlock : w3Qty com.syncCurrent,
highestBlock : w3Qty com.syncHighest highestBlock : w3Qty com.syncHighest
) )
result = %sync result = SyncingStatus(syncing: true, syncObject: sync)
else: else:
result = newJBool(false) result = SyncingStatus(syncing: false)
server.rpc("eth_coinbase") do() -> Web3Address: server.rpc("eth_coinbase") do() -> Web3Address:
## Returns the current coinbase address. ## Returns the current coinbase address.
@ -114,7 +114,7 @@ proc setupEthRpc*(
address = data.ethAddr address = data.ethAddr
result = accDB.getBalance(address) result = accDB.getBalance(address)
server.rpc("eth_getStorageAt") do(data: Web3Address, slot: UInt256, quantityTag: BlockTag) -> UInt256: server.rpc("eth_getStorageAt") do(data: Web3Address, slot: UInt256, quantityTag: BlockTag) -> FixedBytes[32]:
## Returns the value from a storage position at a given address. ## Returns the value from a storage position at a given address.
## ##
## data: address of the storage. ## data: address of the storage.
@ -124,7 +124,7 @@ proc setupEthRpc*(
let let
accDB = stateDBFromTag(quantityTag) accDB = stateDBFromTag(quantityTag)
address = data.ethAddr address = data.ethAddr
result = accDB.getStorage(address, slot)[0] result = accDB.getStorage(address, slot)[0].w3FixedBytes
server.rpc("eth_getTransactionCount") do(data: Web3Address, quantityTag: BlockTag) -> Web3Quantity: server.rpc("eth_getTransactionCount") do(data: Web3Address, quantityTag: BlockTag) -> Web3Quantity:
## Returns the number of transactions sent from an address. ## Returns the number of transactions sent from an address.
@ -279,7 +279,7 @@ proc setupEthRpc*(
res = rpcCallEvm(callData, header, com) res = rpcCallEvm(callData, header, com)
result = res.output result = res.output
server.rpc("eth_estimateGas") do(call: EthCall, quantityTag: BlockTag) -> Web3Quantity: server.rpc("eth_estimateGas") do(call: EthCall) -> Web3Quantity:
## Generates and returns an estimate of how much gas is necessary to allow the transaction to complete. ## Generates and returns an estimate of how much gas is necessary to allow the transaction to complete.
## The transaction will not be added to the blockchain. Note that the estimate may be significantly more than ## The transaction will not be added to the blockchain. Note that the estimate may be significantly more than
## the amount of gas actually used by the transaction, for a variety of reasons including EVM mechanics and node performance. ## the amount of gas actually used by the transaction, for a variety of reasons including EVM mechanics and node performance.
@ -288,7 +288,8 @@ proc setupEthRpc*(
## quantityTag: integer block number, or the string "latest", "earliest" or "pending", see the default block parameter. ## quantityTag: integer block number, or the string "latest", "earliest" or "pending", see the default block parameter.
## Returns the amount of gas used. ## Returns the amount of gas used.
let let
header = chainDB.headerFromTag(quantityTag) # TODO: use latest spec EthCall
header = chainDB.headerFromTag(blockId("latest"))
callData = callData(call) callData = callData(call)
# TODO: DEFAULT_RPC_GAS_CAP should configurable # TODO: DEFAULT_RPC_GAS_CAP should configurable
gasUsed = rpcEstimateGas(callData, header, com, DEFAULT_RPC_GAS_CAP) gasUsed = rpcEstimateGas(callData, header, com, DEFAULT_RPC_GAS_CAP)
@ -492,7 +493,7 @@ proc setupEthRpc*(
# would operate on this enum instead of raw strings. This change would need # would operate on this enum instead of raw strings. This change would need
# to be done on every endpoint to be consistent. # to be done on every endpoint to be consistent.
let fromHeader = chainDB.headerFromTag(filterOptions.fromBlock) let fromHeader = chainDB.headerFromTag(filterOptions.fromBlock)
let toHeader = chainDB.headerFromTag(filterOptions.fromBlock) let toHeader = chainDB.headerFromTag(filterOptions.toBlock)
# Note: if fromHeader.blockNumber > toHeader.blockNumber, no logs will be # Note: if fromHeader.blockNumber > toHeader.blockNumber, no logs will be
# returned. This is consistent with, what other ethereum clients return # returned. This is consistent with, what other ethereum clients return

View File

@ -1,5 +1,5 @@
# Nimbus # Nimbus
# Copyright (c) 2019-2023 Status Research & Development GmbH # Copyright (c) 2019-2024 Status Research & Development GmbH
# Licensed under either of # Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or # * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0) # http://www.apache.org/licenses/LICENSE-2.0)
@ -65,7 +65,7 @@ proc captureAccount(n: JsonNode, db: LedgerRef, address: EthAddress, name: strin
let codeHash = db.getCodeHash(address) let codeHash = db.getCodeHash(address)
let storageRoot = db.getStorageRoot(address) let storageRoot = db.getStorageRoot(address)
jaccount["nonce"] = %(nonce.Web3Quantity) jaccount["nonce"] = %(conversions.`$`(nonce.Web3Quantity))
jaccount["balance"] = %("0x" & balance.toHex) jaccount["balance"] = %("0x" & balance.toHex)
let code = db.getCode(address) let code = db.getCode(address)

View File

@ -126,7 +126,9 @@ proc run(config: VerifiedProxyConf) {.raises: [CatchableError].} =
verifiedProxy.installEthApiHandlers() verifiedProxy.installEthApiHandlers()
info "Listening to incoming network requests" info "Listening to incoming network requests"
network.initBeaconSync(cfg, forkDigests, genesisBlockRoot, getBeaconTime) network.registerProtocol(
PeerSync, PeerSync.NetworkState.init(
cfg, forkDigests, genesisBlockRoot, getBeaconTime))
network.addValidator( network.addValidator(
getBeaconBlocksTopic(forkDigests.phase0), getBeaconBlocksTopic(forkDigests.phase0),
proc (signedBlock: phase0.SignedBeaconBlock): ValidationResult = proc (signedBlock: phase0.SignedBeaconBlock): ValidationResult =

View File

@ -1,5 +1,5 @@
# Nimbus # Nimbus
# Copyright (c) 2020-2023 Status Research & Development GmbH # Copyright (c) 2020-2024 Status Research & Development GmbH
# Licensed under either of # Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or # * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0) # http://www.apache.org/licenses/LICENSE-2.0)
@ -36,12 +36,14 @@ proc request*(
params: JsonNode, params: JsonNode,
client: Option[RpcClient] = none[RpcClient]()): JsonNode = client: Option[RpcClient] = none[RpcClient]()): JsonNode =
if client.isSome(): if client.isSome():
result = waitFor client.unsafeGet().call(methodName, params) let res = waitFor client.unsafeGet().call(methodName, params)
result = JrpcConv.decode(res.string, JsonNode)
else: else:
var client = newRpcHttpClient() var client = newRpcHttpClient()
#client.httpMethod(MethodPost) #client.httpMethod(MethodPost)
waitFor client.connect("127.0.0.1", Port(8545), false) waitFor client.connect("127.0.0.1", Port(8545), false)
result = waitFor client.call(methodName, params) let res = waitFor client.call(methodName, params)
result = JrpcConv.decode(res.string, JsonNode)
waitFor client.close() waitFor client.close()
proc requestBlockBody( proc requestBlockBody(

View File

@ -1,4 +1,4 @@
# Copyright (c) 2022-2023 Status Research & Development GmbH # Copyright (c) 2022-2024 Status Research & Development GmbH
# Licensed under either of # Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE)) # * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
# * MIT license ([LICENSE-MIT](LICENSE-MIT)) # * MIT license ([LICENSE-MIT](LICENSE-MIT))
@ -8,10 +8,9 @@
import import
std/[options, strutils, typetraits], std/[options, typetraits],
unittest2, unittest2,
eth/[common/eth_types], eth/[common/eth_types],
nimcrypto/hash,
stew/byteutils, stew/byteutils,
../nimbus/rpc/filters, ../nimbus/rpc/filters,
../nimbus/beacon/web3_eth_conv, ../nimbus/beacon/web3_eth_conv,
@ -36,52 +35,52 @@ proc filtersMain*() =
log.logIndex.unsafeGet() == w3Qty(i.uint64) log.logIndex.unsafeGet() == w3Qty(i.uint64)
test "Filter with empty parameters should return all logs": test "Filter with empty parameters should return all logs":
let addrs = newSeq[EthAddress]() let addrs = newSeq[Address]()
let filtered = filterLogs(allLogs, addrs, @[]) let filtered = filterLogs(allLogs, AddressOrList(kind: slkList, list: addrs), @[])
check: check:
len(filtered) == len(allLogs) len(filtered) == len(allLogs)
test "Filter and BloomFilter for one address with one valid log": test "Filter and BloomFilter for one address with one valid log":
let address = hexToByteArray[20]("0x0e0989b1f9b8a38983c2ba8053269ca62ec9b195") let address = Address.fromHex("0x0e0989b1f9b8a38983c2ba8053269ca62ec9b195")
let filteredLogs = filterLogs(allLogs, @[address], @[]) let filteredLogs = filterLogs(allLogs, AddressOrList(kind: slkList, list: @[address]), @[])
check: check:
headerBloomFilter(blockHeader4514995, @[address], @[]) headerBloomFilter(blockHeader4514995, AddressOrList(kind: slkList, list: @[address]), @[])
len(filteredLogs) == 1 len(filteredLogs) == 1
filteredLogs[0].address == w3Addr address filteredLogs[0].address == address
test "Filter and BloomFilter for one address with multiple valid logs": test "Filter and BloomFilter for one address with multiple valid logs":
let address = hexToByteArray[20]("0x878d7ed5c194349f37b18688964e8db1eb0fcca1") let address = Address.fromHex("0x878d7ed5c194349f37b18688964e8db1eb0fcca1")
let filteredLogs = filterLogs(allLogs, @[address], @[]) let filteredLogs = filterLogs(allLogs, AddressOrList(kind: slkSingle, single: address), @[])
check: check:
headerBloomFilter(blockHeader4514995, @[address], @[]) headerBloomFilter(blockHeader4514995, AddressOrList(kind: slkList, list: @[address]), @[])
len(filteredLogs) == 2 len(filteredLogs) == 2
for log in filteredLogs: for log in filteredLogs:
check: check:
log.address == w3Addr address log.address == address
test "Filter and BloomFilter for multiple address with multiple valid logs": test "Filter and BloomFilter for multiple address with multiple valid logs":
let address = hexToByteArray[20]("0x878d7ed5c194349f37b18688964e8db1eb0fcca1") let address = Address.fromHex("0x878d7ed5c194349f37b18688964e8db1eb0fcca1")
let address1 = hexToByteArray[20]("0x0e0989b1f9b8a38983c2ba8053269ca62ec9b195") let address1 = Address.fromHex("0x0e0989b1f9b8a38983c2ba8053269ca62ec9b195")
let filteredLogs = filterLogs(allLogs, @[address, address1], @[]) let filteredLogs = filterLogs(allLogs, AddressOrList(kind: slkList, list: @[address, address1]), @[])
check: check:
headerBloomFilter(blockHeader4514995, @[address, address1], @[]) headerBloomFilter(blockHeader4514995, AddressOrList(kind: slkList, list: @[address, address1]), @[])
len(filteredLogs) == 3 len(filteredLogs) == 3
test "Filter topics, too many filters": test "Filter topics, too many filters":
let filteredLogs = let filteredLogs =
filterLogs( filterLogs(
allLogs, allLogs,
@[], AddressOrList(kind: slkList, list: @[]),
@[ @[
none[seq[Web3Hash]](), TopicOrList(kind: slkNull),
none[seq[Web3Hash]](), TopicOrList(kind: slkNull),
none[seq[Web3Hash]](), TopicOrList(kind: slkNull),
none[seq[Web3Hash]](), TopicOrList(kind: slkNull),
none[seq[Web3Hash]]() TopicOrList(kind: slkNull)
] ]
) )
@ -94,8 +93,8 @@ proc filtersMain*() =
let filteredLogs = let filteredLogs =
filterLogs( filterLogs(
allLogs, allLogs,
@[], AddressOrList(kind: slkList, list: @[]),
@[some(@[topic])] @[TopicOrList(kind: slkList, list: @[topic])]
) )
check: check:
@ -113,8 +112,8 @@ proc filtersMain*() =
let filteredLogs = let filteredLogs =
filterLogs( filterLogs(
allLogs, allLogs,
@[], AddressOrList(kind: slkList, list: @[]),
@[some(@[topic]), some(@[topic1])] @[TopicOrList(kind: slkList, list: @[topic]), TopicOrList(kind: slkList, list: @[topic1])]
) )
check: check:
@ -133,8 +132,12 @@ proc filtersMain*() =
let filteredLogs = let filteredLogs =
filterLogs( filterLogs(
allLogs, allLogs,
@[], AddressOrList(kind: slkList, list: @[]),
@[some(@[topic]), none[seq[Web3Hash]](), some(@[topic1])] @[
TopicOrList(kind: slkList, list: @[topic]),
TopicOrList(kind: slkNull),
TopicOrList(kind: slkList, list: @[topic1])
]
) )
check: check:
@ -152,9 +155,9 @@ proc filtersMain*() =
let filteredLogs = let filteredLogs =
filterLogs( filterLogs(
allLogs, allLogs,
@[], AddressOrList(kind: slkList, list: @[]),
@[ @[
some(@[topic, topic1]) TopicOrList(kind: slkList, list: @[topic, topic1])
] ]
) )
@ -175,10 +178,10 @@ proc filtersMain*() =
let filteredLogs = let filteredLogs =
filterLogs( filterLogs(
allLogs, allLogs,
@[], AddressOrList(kind: slkNull),
@[ @[
some(@[topic, topic1]), TopicOrList(kind: slkList, list: @[topic, topic1]),
some(@[topic2, topic3]) TopicOrList(kind: slkList, list: @[topic2, topic3])
] ]
) )
@ -193,7 +196,7 @@ proc filtersMain*() =
# general propety based tests # general propety based tests
test "Specific address query should provide results only with given address": test "Specific address query should provide results only with given address":
for log in allLogs: for log in allLogs:
let filtered = filterLogs(allLogs, @[log.address], @[]) let filtered = filterLogs(allLogs, AddressOrList(kind: slkSingle, single: log.address), @[])
check: check:
len(filtered) > 0 len(filtered) > 0

View File

@ -1,5 +1,5 @@
# Nimbus # Nimbus
# Copyright (c) 2018-2023 Status Research & Development GmbH # Copyright (c) 2018-2024 Status Research & Development GmbH
# Licensed under either of # Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE)) # * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
# * MIT license ([LICENSE-MIT](LICENSE-MIT)) # * MIT license ([LICENSE-MIT](LICENSE-MIT))
@ -8,10 +8,10 @@
# those terms. # those terms.
import import
std/[json, os, strutils, typetraits], std/[json, os, typetraits],
unittest2, unittest2,
json_rpc/[rpcserver, rpcclient], json_rpc/[rpcserver, rpcclient],
web3/[engine_api_types], web3/[engine_api_types, conversions],
../nimbus/sync/protocol, ../nimbus/sync/protocol,
../nimbus/rpc, ../nimbus/rpc,
../nimbus/common, ../nimbus/common,
@ -26,53 +26,38 @@ const
stepsFile = baseDir / "steps.json" stepsFile = baseDir / "steps.json"
type type
Step = ref object StepObj = object
name: string name: string
meth: string `method`: string
params: JSonNode params: JSonNode
expect: JsonNode expect: JsonString
error : bool error : JsonString
Steps = ref object Step = ref StepObj
list: seq[Step] Steps = seq[Step]
proc parseStep(s: Step, node: JsonNode) = StepObj.useDefaultSerializationIn JrpcConv
for k, v in node:
case k
of "name": s.name = v.getStr()
of "method": s.meth = v.getStr()
of "params": s.params = v
of "expect": s.expect = v
of "error": s.error = true
else:
doAssert(false, "unknown key: " & k)
proc parseSteps(node: JsonNode): Steps =
let ss = Steps(list: @[])
for n in node:
let s = Step()
s.parseStep(n)
ss.list.add s
ss
proc forkChoiceUpdate(step: Step, client: RpcClient, testStatusIMPL: var TestStatus) = proc forkChoiceUpdate(step: Step, client: RpcClient, testStatusIMPL: var TestStatus) =
let arg = step.params[1] let jsonBytes = waitFor client.call(step.`method`, step.params)
if arg.kind == JNull: let resA = JrpcConv.decode(jsonBytes.string, ForkchoiceUpdatedResponse)
step.params.elems.setLen(1) let resB = JrpcConv.decode(step.expect.string, ForkchoiceUpdatedResponse)
check resA == resB
let res = waitFor client.call(step.meth, step.params)
check toLowerAscii($res) == toLowerAscii($step.expect)
proc getPayload(step: Step, client: RpcClient, testStatusIMPL: var TestStatus) = proc getPayload(step: Step, client: RpcClient, testStatusIMPL: var TestStatus) =
try: try:
let res = waitFor client.call(step.meth, step.params) let jsonBytes = waitFor client.call(step.`method`, step.params)
check toLowerAscii($res) == toLowerAscii($step.expect) let resA = JrpcConv.decode(jsonBytes.string, ExecutionPayloadV1)
let resB = JrpcConv.decode(step.expect.string, ExecutionPayloadV1)
check resA == resB
except CatchableError: except CatchableError:
check step.error == true check step.error.string.len > 0
proc newPayload(step: Step, client: RpcClient, testStatusIMPL: var TestStatus) = proc newPayload(step: Step, client: RpcClient, testStatusIMPL: var TestStatus) =
let res = waitFor client.call(step.meth, step.params) let jsonBytes = waitFor client.call(step.`method`, step.params)
check toLowerAscii($res) == toLowerAscii($step.expect) let resA = JrpcConv.decode(jsonBytes.string, PayloadStatusV1)
let resB = JrpcConv.decode(step.expect.string, PayloadStatusV1)
check resA == resB
proc runTest(steps: Steps) = proc runTest(steps: Steps) =
let let
@ -107,9 +92,9 @@ proc runTest(steps: Steps) =
waitFor client.connect("127.0.0.1", conf.rpcPort) waitFor client.connect("127.0.0.1", conf.rpcPort)
suite "Engine API tests": suite "Engine API tests":
for i, step in steps.list: for i, step in steps:
test $i & " " & step.name: test $i & " " & step.name:
case step.meth case step.`method`
of "engine_forkchoiceUpdatedV1": of "engine_forkchoiceUpdatedV1":
forkChoiceUpdate(step, client, testStatusIMPL) forkChoiceUpdate(step, client, testStatusIMPL)
of "engine_getPayloadV1": of "engine_getPayloadV1":
@ -117,7 +102,7 @@ proc runTest(steps: Steps) =
of "engine_newPayloadV1": of "engine_newPayloadV1":
newPayload(step, client, testStatusIMPL) newPayload(step, client, testStatusIMPL)
else: else:
doAssert(false, "unknown method: " & step.meth) doAssert(false, "unknown method: " & step.`method`)
waitFor client.close() waitFor client.close()
waitFor sealingEngine.stop() waitFor sealingEngine.stop()
@ -125,8 +110,7 @@ proc runTest(steps: Steps) =
waitFor rpcServer.closeWait() waitFor rpcServer.closeWait()
proc testEngineAPI() = proc testEngineAPI() =
let node = parseJSON(readFile(stepsFile)) let steps = JrpcConv.loadFile(stepsFile, Steps)
let steps = parseSteps(node)
runTest(steps) runTest(steps)
proc toId(x: int): PayloadId = proc toId(x: int): PayloadId =

View File

@ -289,14 +289,13 @@ proc rpcMain*() =
test "eth_syncing": test "eth_syncing":
let res = await client.eth_syncing() let res = await client.eth_syncing()
if res.kind == JBool: if res.syncing == false:
let syncing = ethNode.peerPool.connectedNodes.len > 0 let syncing = ethNode.peerPool.connectedNodes.len > 0
check res.getBool() == syncing check syncing == false
else: else:
check res.kind == JObject check com.syncStart == res.syncObject.startingBlock.uint64.u256
check com.syncStart == UInt256.fromHex(res["startingBlock"].getStr()) check com.syncCurrent == res.syncObject.currentBlock.uint64.u256
check com.syncCurrent == UInt256.fromHex(res["currentBlock"].getStr()) check com.syncHighest == res.syncObject.highestBlock.uint64.u256
check com.syncHighest == UInt256.fromHex(res["highestBlock"].getStr())
test "eth_coinbase": test "eth_coinbase":
let res = await client.eth_coinbase() let res = await client.eth_coinbase()
@ -337,7 +336,7 @@ proc rpcMain*() =
test "eth_getStorageAt": test "eth_getStorageAt":
let res = await client.eth_getStorageAt(w3Addr("0xfff33a3bd36abdbd412707b8e310d6011454a7ae"), 0.u256, blockId(0'u64)) let res = await client.eth_getStorageAt(w3Addr("0xfff33a3bd36abdbd412707b8e310d6011454a7ae"), 0.u256, blockId(0'u64))
check 0.u256 == res check w3Hash() == res
test "eth_getTransactionCount": test "eth_getTransactionCount":
let res = await client.eth_getTransactionCount(w3Addr("0xfff7ac99c8e4feb60c9750054bdc14ce1857f181"), blockId(0'u64)) let res = await client.eth_getTransactionCount(w3Addr("0xfff7ac99c8e4feb60c9750054bdc14ce1857f181"), blockId(0'u64))
@ -369,7 +368,7 @@ proc rpcMain*() =
let msg = "hello world" let msg = "hello world"
let msgBytes = @(msg.toOpenArrayByte(0, msg.len-1)) let msgBytes = @(msg.toOpenArrayByte(0, msg.len-1))
expect ValueError: expect JsonRpcError:
discard await client.eth_sign(w3Addr(ks2), msgBytes) discard await client.eth_sign(w3Addr(ks2), msgBytes)
let res = await client.eth_sign(w3Addr(signer), msgBytes) let res = await client.eth_sign(w3Addr(signer), msgBytes)
@ -404,7 +403,7 @@ proc rpcMain*() =
test "eth_call": test "eth_call":
var ec = EthCall( var ec = EthCall(
source: w3Addr(signer).some, `from`: w3Addr(signer).some,
to: w3Addr(ks2).some, to: w3Addr(ks2).some,
gas: w3Qty(100000'u).some, gas: w3Qty(100000'u).some,
gasPrice: none(Quantity), gasPrice: none(Quantity),
@ -416,14 +415,14 @@ proc rpcMain*() =
test "eth_estimateGas": test "eth_estimateGas":
var ec = EthCall( var ec = EthCall(
source: w3Addr(signer).some, `from`: w3Addr(signer).some,
to: w3Addr(ks3).some, to: w3Addr(ks3).some,
gas: w3Qty(42000'u).some, gas: w3Qty(42000'u).some,
gasPrice: w3Qty(100'u).some, gasPrice: w3Qty(100'u).some,
value: some 100.u256 value: some 100.u256
) )
let res = await client.eth_estimateGas(ec, "latest") let res = await client.eth_estimateGas(ec)
check res == w3Qty(21000'u64) check res == w3Qty(21000'u64)
test "eth_getBlockByHash": test "eth_getBlockByHash":
@ -535,7 +534,7 @@ proc rpcMain*() =
l.logIndex.unsafeGet() == w3Qty(i.uint64) l.logIndex.unsafeGet() == w3Qty(i.uint64)
inc i inc i
test "eth_getLogs by blockhash, filter logs at specific postions": test "eth_getLogs by blockhash, filter logs at specific positions":
let testHeader = getBlockHeader4514995() let testHeader = getBlockHeader4514995()
let testHash = testHeader.blockHash let testHash = testHeader.blockHash
@ -544,7 +543,11 @@ proc rpcMain*() =
let filterOptions = FilterOptions( let filterOptions = FilterOptions(
blockHash: some(w3Hash testHash), blockHash: some(w3Hash testHash),
topics: @[some(@[topic]), none[seq[Web3Hash]](), some(@[topic1])] topics: @[
TopicOrList(kind: slkList, list: @[topic]),
TopicOrList(kind: slkNull),
TopicOrList(kind: slkList, list: @[topic1])
]
) )
let logs = await client.eth_getLogs(filterOptions) let logs = await client.eth_getLogs(filterOptions)
@ -568,8 +571,8 @@ proc rpcMain*() =
let filterOptions = FilterOptions( let filterOptions = FilterOptions(
blockHash: some(w3Hash testHash), blockHash: some(w3Hash testHash),
topics: @[ topics: @[
some(@[topic, topic1]), TopicOrList(kind: slkList, list: @[topic, topic1]),
some(@[topic2, topic3]) TopicOrList(kind: slkList, list: @[topic2, topic3])
] ]
) )

2
vendor/nim-json-rpc vendored

@ -1 +1 @@
Subproject commit a8731e91bc336d930ac66f985d3b88ed7cf2a7d7 Subproject commit f90e946b6a92432cbfe7abb59f9c05af17bfddde

2
vendor/nim-web3 vendored

@ -1 +1 @@
Subproject commit be1bb307dc40afb329e559eda601b74f9ab476d5 Subproject commit 4ab592bddb0d0c7c27d5f19a303f2e4a262b6f95

2
vendor/nimbus-eth2 vendored

@ -1 +1 @@
Subproject commit c815e71af028f5610cd52d678dd3cbdda9bfece1 Subproject commit 5404178a4004c4bc13c75853a02b1a74f2ca302c