graphql: add Shanghai and Cancun fields

This commit is contained in:
jangko 2023-07-28 17:32:49 +07:00
parent 31cff910b1
commit 81b7a8c682
No known key found for this signature in database
GPG Key ID: 31702AE10541E6B9
11 changed files with 345 additions and 92 deletions

View File

@ -91,7 +91,11 @@ proc main() =
var stat: SimStat
let start = getTime()
for fileName {.inject.} in walkDirRec(
#let fileName = caseFolder & "/37_eth_sendRawTransaction_nonceTooLow.json"
#block:
for fileName in walkDirRec(
caseFolder, yieldFilter = {pcFile,pcLinkToFile}):
if not fileName.endsWith(".json"):
continue
@ -101,6 +105,9 @@ proc main() =
let status = ctx.processNode(node, fileName)
stat.inc(name, status)
# simulate the real simulator
txPool.disposeAll()
let elpd = getTime() - start
print(stat, elpd, "graphql")

View File

@ -1,4 +1,20 @@
{
"config": {
"chainId": 1,
"homesteadBlock": 33,
"eip150Block": 33,
"eip155Block": 33,
"eip158Block": 33,
"byzantiumBlock": 33,
"constantinopleBlock": 33,
"petersburgBlock": 33,
"istanbulBlock": 33,
"muirGlacierBlock": 33,
"berlinBlock": 33,
"londonBlock": 33,
"terminalTotalDifficulty": 4357120,
"shanghaiTime": 1444660030
},
"genesis": {
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "0x020000",

View File

@ -166,6 +166,7 @@ proc readValue(reader: var JsonReader, value: var BlockNonce)
except ValueError as ex:
reader.raiseUnexpectedValue(ex.msg)
# genesis timestamp is in hex
proc readValue(reader: var JsonReader, value: var EthTime)
{.gcsafe, raises: [SerializationError, IOError].} =
try:
@ -173,6 +174,21 @@ proc readValue(reader: var JsonReader, value: var EthTime)
except ValueError as ex:
reader.raiseUnexpectedValue(ex.msg)
# but shanghaiTime and cancunTime in config is in int literal
proc readValue(reader: var JsonReader, value: var Option[EthTime])
{.gcsafe, raises: [SerializationError, IOError].} =
let tok = reader.lexer.lazyTok
if tok == tkNull:
reset value
reader.lexer.next()
else:
# both readValue(GasInt/AccountNonce) will be called if
# we use readValue(int64/uint64)
let tok {.used.} = reader.lexer.tok # resove lazy token
let val = reader.lexer.absIntVal.int64
value = some val.fromUnix
reader.lexer.next()
proc readValue(reader: var JsonReader, value: var seq[byte])
{.gcsafe, raises: [SerializationError, IOError].} =
try:

View File

@ -804,6 +804,14 @@ iterator okPairs*(xp: TxPoolRef): (Hash256, TxItemRef) =
proc numTxs*(xp: TxPoolRef): int =
xp.txDB.byItemID.len
proc disposeAll*(xp: TxpoolRef) {.gcsafe,raises: [CatchableError].} =
let numTx = xp.numTxs
var list = newSeqOfCap[TxItemRef](numTx)
for x in nextPairs(xp.txDB.byItemID):
list.add x.data
for x in list:
xp.disposeItems(x)
# ------------------------------------------------------------------------------
# Public functions, local/remote accounts
# ------------------------------------------------------------------------------

View File

@ -227,10 +227,12 @@ proc getTransactionCount*(chain: ChainDBRef, txRoot: Hash256): int =
var txCount = 0
while true:
let txKey = rlp.encode(txCount)
if txKey notin trie:
break
inc txCount
txCount
if txKey in trie:
inc txCount
else:
return txCount
doAssert(false, "unreachable")
proc getUnclesCount*(db: ChainDBRef, ommersHash: Hash256): int =
if ommersHash != EMPTY_UNCLE_HASH:
@ -263,6 +265,10 @@ iterator getWithdrawalsData*(db: ChainDBRef, withdrawalsRoot: Hash256): seq[byte
break
inc idx
proc getWithdrawals*(db: ChainDBRef, withdrawalsRoot: Hash256): seq[Withdrawal] =
for encodedWd in db.getWithdrawalsData(withdrawalsRoot):
result.add(rlp.decode(encodedWd, Withdrawal))
proc getBlockBody*(db: ChainDBRef, header: BlockHeader, output: var BlockBody): bool =
result = true
output.transactions = @[]
@ -278,10 +284,7 @@ proc getBlockBody*(db: ChainDBRef, header: BlockHeader, output: var BlockBody):
result = false
if header.withdrawalsRoot.isSome:
var withdrawals: seq[Withdrawal]
for encodedWd in db.getWithdrawalsData(header.withdrawalsRoot.get):
withdrawals.add(rlp.decode(encodedWd, Withdrawal))
output.withdrawals = some(withdrawals)
output.withdrawals = some(db.getWithdrawals(header.withdrawalsRoot.get))
proc getBlockBody*(db: ChainDBRef, blockHash: Hash256, output: var BlockBody): bool =
var header: BlockHeader

View File

@ -10,7 +10,7 @@
import
std/[strutils, times],
stew/[results, byteutils], stint,
eth/[rlp], chronos,
eth/common/eth_types_rlp, chronos,
stew/shims/net,
graphql, graphql/graphql as context,
graphql/common/types, graphql/httpserver,
@ -19,7 +19,7 @@ import
".."/[transaction, vm_state, config, constants],
../common/common,
../transaction/call_evm,
../core/tx_pool,
../core/[tx_pool, tx_pool/tx_item],
../utils/utils
from eth/p2p import EthereumNode
@ -37,6 +37,7 @@ type
ethQuery = "Query"
ethMutation = "Mutation"
ethAccessTuple = "AccessTuple"
ethWithdrawal = "Withdrawal"
HeaderNode = ref object of Node
header: BlockHeader
@ -62,6 +63,9 @@ type
AclNode = ref object of Node
acl: AccessPair
WdNode = ref object of Node
wd: Withdrawal
GraphqlContextRef = ref GraphqlContextObj
GraphqlContextObj = object of Graphql
ids: array[EthTypes, Name]
@ -79,7 +83,12 @@ proc toHash(n: Node): Hash256 =
result.data = hexToByteArray[32](n.stringVal)
proc toBlockNumber(n: Node): BlockNumber =
result = parse(n.intVal, UInt256, radix = 10)
if n.kind == nkInt:
result = parse(n.intVal, UInt256, radix = 10)
elif n.kind == nkString:
result = parse(n.stringVal, UInt256, radix = 16)
else:
doAssert(false, "unknown node type: " & $n.kind)
proc headerNode(ctx: GraphqlContextRef, header: BlockHeader): Node =
HeaderNode(
@ -128,6 +137,14 @@ proc aclNode(ctx: GraphqlContextRef, accessPair: AccessPair): Node =
acl: accessPair
)
proc wdNode(ctx: GraphqlContextRef, wd: Withdrawal): Node =
WdNode(
kind: nkMap,
typeName: ctx.ids[ethWithdrawal],
pos: Pos(),
wd: wd
)
proc getStateDB(com: CommonRef, header: BlockHeader): ReadOnlyStateDB =
## Retrieves the account db from canonical head
## we don't use accounst_cache here because it's read only operations
@ -190,6 +207,10 @@ proc bigIntNode(x: uint64 | int64): RespResult =
# stdlib toHex is not suitable for hive
const
HexChars = "0123456789abcdef"
if x == 0:
return ok(Node(kind: nkString, stringVal: "0x0", pos: Pos()))
var
n = cast[uint64](x)
r: array[2*sizeof(uint64), char]
@ -278,6 +299,19 @@ proc getTxs(ctx: GraphqlContextRef, header: BlockHeader): RespResult =
except CatchableError as e:
err("can't get transactions: " & e.msg)
proc getWithdrawals(ctx: GraphqlContextRef, header: BlockHeader): RespResult =
try:
if header.withdrawalsRoot.isSome:
let wds = getWithdrawals(ctx.chainDB, header.withdrawalsRoot.get)
var list = respList()
for wd in wds:
list.add wdNode(ctx, wd)
ok(list)
else:
ok(respNull())
except CatchableError as e:
err("can't get transactions: " & e.msg)
proc getTxAt(ctx: GraphqlContextRef, header: BlockHeader, index: int): RespResult =
try:
var tx: Transaction
@ -323,9 +357,25 @@ proc accountNode(ctx: GraphqlContextRef, header: BlockHeader, address: EthAddres
except RlpError as ex:
err(ex.msg)
func hexCharToInt(c: char): uint64 =
case c
of 'a'..'f': return c.uint64 - 'a'.uint64 + 10'u64
of 'A'..'F': return c.uint64 - 'A'.uint64 + 10'u64
of '0'..'9': return c.uint64 - '0'.uint64
else: doAssert(false, "invalid hex digit: " & $c)
proc parseU64(node: Node): uint64 =
for c in node.intVal:
result = result * 10 + uint64(c.int - '0'.int)
if node.kind == nkString:
if node.stringVal.len > 2 and node.stringVal[1] == 'x':
for i in 2..<node.stringVal.len:
let c = node.stringVal[i]
result = result * 16 + hexCharToInt(c)
else:
for c in node.stringVal:
result = result * 10 + (c.uint64 - '0'.uint64)
else:
for c in node.intVal:
result = result * 10 + (c.uint64 - '0'.uint64)
{.pragma: apiRaises, raises: [].}
@ -462,17 +512,17 @@ proc scalarLong(ctx: GraphqlRef, typeNode, node: Node): NodeResult {.cdecl, gcsa
let val = parse(node.stringVal, UInt256, radix = 16)
if val > maxU64:
return err("long value overflow")
ok(Node(kind: nkInt, pos: node.pos, intVal: $val))
ok(node)
else:
let val = parse(node.stringVal, UInt256, radix = 10)
if val > maxU64:
return err("long value overflow")
ok(Node(kind: nkInt, pos: node.pos, intVal: node.stringVal))
ok(Node(kind: nkString, pos: node.pos, stringVal: "0x" & val.toHex))
of nkInt:
let val = parse(node.intVal, UInt256, radix = 10)
if val > maxU64:
return err("long value overflow")
ok(node)
ok(Node(kind: nkString, pos: node.pos, stringVal: "0x" & val.toHex))
else:
err("expect int, but got '$1'" % [$node.kind])
except CatchableError as e:
@ -583,25 +633,35 @@ proc txIndex(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.}
ok(resp(tx.index))
proc txFrom(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
# TODO: with block param
let ctx = GraphqlContextRef(ud)
let tx = TxNode(parent)
let blockNumber = if params[0].val.kind != nkEmpty:
parseU64(params[0].val).toBlockNumber
else:
tx.blockNumber
var sender: EthAddress
if not getSender(tx.tx, sender):
return ok(respNull())
let hres = ctx.getBlockByNumber(tx.blockNumber)
let hres = ctx.getBlockByNumber(blockNumber)
if hres.isErr:
return hres
let h = HeaderNode(hres.get())
ctx.accountNode(h.header, sender)
proc txTo(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
# TODO: with block param
let ctx = GraphqlContextRef(ud)
let tx = TxNode(parent)
let blockNumber = if params[0].val.kind != nkEmpty:
parseU64(params[0].val).toBlockNumber
else:
tx.blockNumber
if tx.tx.contractCreation:
return ok(respNull())
let hres = ctx.getBlockByNumber(tx.blockNumber)
let hres = ctx.getBlockByNumber(blockNumber)
if hres.isErr:
return hres
let h = HeaderNode(hres.get())
@ -741,6 +801,35 @@ proc txAccessList(ud: RootRef, params: Args, parent: Node): RespResult {.apiPrag
list.add aclNode(ctx, x)
ok(list)
proc txMaxFeePerBlobGas(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
let ctx = GraphqlContextRef(ud)
let tx = TxNode(parent)
if tx.tx.txType < TxEIP4844:
ok(respNull())
else:
longNode(tx.tx.maxFeePerDataGas)
proc txVersionedHashes(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
let ctx = GraphqlContextRef(ud)
let tx = TxNode(parent)
if tx.tx.txType < TxEIP4844:
ok(respNull())
else:
var list = respList()
for hs in tx.tx.versionedHashes:
list.add resp("0x" & hs.data.toHex)
ok(list)
proc txRaw(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
let tx = TxNode(parent)
let txBytes = rlp.encode(tx.tx)
resp(txBytes)
proc txRawReceipt(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
let tx = TxNode(parent)
let recBytes = rlp.encode(tx.receipt)
resp(recBytes)
const txProcs = {
"from": txFrom,
"hash": txHash,
@ -765,7 +854,11 @@ const txProcs = {
"maxFeePerGas": txMaxFeePerGas,
"maxPriorityFeePerGas": txMaxPriorityFeePerGas,
"effectiveGasPrice": txEffectiveGasPrice,
"chainID": txChainId
"chainID": txChainId,
"maxFeePerBlobGas": txmaxFeePerBlobGas,
"versionedHashes": txVersionedHashes,
"raw": txRaw,
"rawReceipt": txRawReceipt
}
proc aclAddress(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
@ -787,6 +880,29 @@ const aclProcs = {
"storageKeys": aclStorageKeys
}
proc wdIndex(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
let w = WdNode(parent)
longNode(w.wd.index)
proc wdValidator(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
let w = WdNode(parent)
longNode(w.wd.validatorIndex)
proc wdAddress(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
let w = WdNode(parent)
resp(w.wd.address)
proc wdAmount(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
let w = WdNode(parent)
longNode(w.wd.amount)
const wdProcs = {
"index": wdIndex,
"validator": wdValidator,
"address": wdAddress,
"amount": wdAmount
}
proc blockNumberImpl(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
let ctx = GraphqlContextRef(ud)
let h = HeaderNode(parent)
@ -1012,6 +1128,32 @@ proc blockBaseFeePerGas(ud: RootRef, params: Args, parent: Node): RespResult {.a
else:
ok(respNull())
proc blockWithdrawalsRoot(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
let h = HeaderNode(parent)
if h.header.withdrawalsRoot.isSome:
resp(h.header.withdrawalsRoot.get)
else:
ok(respNull())
proc blockWithdrawals(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
let ctx = GraphqlContextRef(ud)
let h = HeaderNode(parent)
getWithdrawals(ctx, h.header)
proc blockBlobGasUsed(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
let h = HeaderNode(parent)
if h.header.dataGasUsed.isSome:
longNode(h.header.dataGasUsed.get)
else:
ok(respNull())
proc blockexcessBlobGas(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
let h = HeaderNode(parent)
if h.header.excessDataGas.isSome:
longNode(h.header.excessDataGas.get)
else:
ok(respNull())
const blockProcs = {
"parent": blockParent,
"number": blockNumberImpl,
@ -1040,7 +1182,11 @@ const blockProcs = {
"account": blockAccount,
"call": blockCall,
"estimateGas": blockEstimateGas,
"baseFeePerGas": blockBaseFeePerGas
"baseFeePerGas": blockBaseFeePerGas,
"withdrawalsRoot": blockWithdrawalsRoot,
"withdrawals": blockWithdrawals,
"blobGasUsed": blockBlobGasUsed,
"excessBlobGas": blockExcessBlobGas
}
proc callResultData(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
@ -1151,6 +1297,12 @@ proc queryBlock(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma
err("only one param allowed, number or hash, not both")
elif number.kind == nkInt:
getBlockByNumber(ctx, number)
elif number.kind == nkString:
try:
let blockNumber = toBlockNumber(number)
getBlockByNumber(ctx, blockNumber)
except ValueError as ex:
err(ex.msg)
elif hash.kind == nkString:
getBlockByHash(ctx, hash)
else:
@ -1241,16 +1393,26 @@ const queryProcs = {
"chainID": queryChainId
}
proc inPoolAndOk(ctx: GraphqlContextRef, txHash: Hash256): bool =
let res = ctx.txPool.getItem(txHash)
if res.isErr: return false
res.get().reject == txInfoOk
proc sendRawTransaction(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
# TODO: add tx validation and tx processing
# probably goes to tx pool
# if tx validation failed, the result will be null
let ctx = GraphqlContextRef(ud)
try:
let data = hexToSeqByte(params[0].val.stringVal)
let tx = decodeTx(data) # we want to know if it is a valid tx blob
let txHash = rlpHash(tx) # beware EIP-4844
resp(txHash)
ctx.txPool.add(tx)
if ctx.inPoolAndOk(txHash):
return resp(txHash)
else:
return err("transaction rejected by txpool")
except CatchableError as em:
return err("failed to process raw transaction: " & em.msg)
@ -1315,6 +1477,7 @@ proc initEthApi(ctx: GraphqlContextRef) =
ctx.addResolvers(ctx, ctx.ids[ethQuery ], queryProcs)
ctx.addResolvers(ctx, ctx.ids[ethMutation ], mutationProcs)
ctx.addResolvers(ctx, ctx.ids[ethAccessTuple], aclProcs)
ctx.addResolvers(ctx, ctx.ids[ethWithdrawal ], wdProcs)
var qc = newQC(ctx)
ctx.addInstrument(qc)

View File

@ -5,7 +5,7 @@ scalar Bytes32
scalar Address
# Bytes is an arbitrary length binary string, represented as 0x-prefixed hexadecimal.
# An empty byte string is represented as '0x'. Byte strings must have an even number of hexadecimal nybbles.
# An empty byte string is represented as '0x'. Byte strings must have an even number of hexadecimal nibbles.
scalar Bytes
# BigInt is a large integer. Input is accepted as either a JSON number or as a string.
@ -13,7 +13,9 @@ scalar Bytes
# 0x-prefixed hexadecimal.
scalar BigInt
# Long is a 64 bit unsigned integer.
# Long is a 64 bit unsigned integer. Input is accepted as either a JSON number or as a string.
# Strings may be either decimal or 0x-prefixed hexadecimal. Output values are all
# 0x-prefixed hexadecimal.
scalar Long
schema {
@ -46,7 +48,7 @@ type Account {
# Log is an Ethereum event log.
type Log {
# Index is the index of this log in the block.
index: Int!
index: Long!
# Account is the account which generated this log - this will always
# be a contract account.
@ -64,13 +66,28 @@ type Log {
# EIP-2718 Access List
type AccessTuple {
# access list address
# access list address.
address: Address!
# access list storage keys, null if not present
# access list storage keys, null if not present.
storageKeys: [Bytes32!]
}
# EIP-4895
type Withdrawal {
# Index is a monotonically increasing identifier issued by consensus layer.
index: Long!
# Validator is index of the validator associated with withdrawal.
validator: Long!
# Recipient address of the withdrawn amount.
address: Address!
# Amount is the withdrawal value in Gwei.
amount: Long!
}
# Transaction is an Ethereum transaction.
type Transaction {
# Hash is the hash of this transaction.
@ -81,7 +98,7 @@ type Transaction {
# Index is the index of this transaction in the parent block. This will
# be null if the transaction has not yet been mined.
index: Int
index: Long
# From is the account that sent this transaction - this will always be
# an externally owned account.
@ -157,14 +174,31 @@ type Transaction {
v: BigInt!
# EIP 2718: envelope transaction support
type: Int
type: Long
# EIP 2930: optional access list, null if not present
accessList: [AccessTuple!]
# EIP-4844: blob gas a user willing to pay
maxFeePerBlobGas: Long
# EIP-4844: represents a list of hash outputs from kzg_to_versioned_hash
versionedHashes: [Bytes32!]
#--------------------------Extensions-------------------------------
# If type == 0, chainID returns null.
# If type > 0, chainID returns replay protection chainID
chainID: Long
# Raw is the canonical encoding of the transaction.
# For legacy transactions, it returns the RLP encoding.
# For EIP-2718 typed transactions, it returns the type and payload.
raw: Bytes!
# RawReceipt is the canonical encoding of the receipt. For post EIP-2718 typed transactions
# this is equivalent to TxType || ReceiptEncoding.
rawReceipt: Bytes!
}
# BlockFilterCriteria encapsulates log filter criteria for a filter applied
@ -207,7 +241,7 @@ type Block {
# TransactionCount is the number of transactions in this block. if
# transactions are not available for this block, this field will be null.
transactionCount: Int
transactionCount: Long
# StateRoot is the keccak256 hash of the state trie after this block was processed.
stateRoot: Bytes32!
@ -249,7 +283,7 @@ type Block {
# OmmerCount is the number of ommers (AKA uncles) associated with this
# block. If ommers are unavailable, this field will be null.
ommerCount: Int
ommerCount: Long
# Ommers is a list of ommer (AKA uncle) blocks associated with this block.
# If ommers are unavailable, this field will be null. Depending on your
@ -286,6 +320,32 @@ type Block {
# EstimateGas estimates the amount of gas that will be required for
# successful execution of a transaction at the current block's state.
estimateGas(data: CallData!): Long!
# WithdrawalsRoot is the withdrawals trie root in this block.
# If withdrawals are unavailable for this block, this field will be null.
withdrawalsRoot: Bytes32
# Withdrawals is a list of withdrawals associated with this block. If
# withdrawals are unavailable for this block, this field will be null.
withdrawals: [Withdrawal!]
# EIP-4844: is the total amount of blob gas consumed by the transactions
# within the block.
blobGasUsed: Long
# EIP-4844: is a running total of blob gas consumed in excess of the target,
# prior to the block. Blocks with above-target blob gas consumption increase
# this value, blocks with below-target blob gas consumption decrease it
# (bounded at 0).
excessBlobGas: Long
#--------------------------Extensions-------------------------------
# RawHeader is the RLP encoding of the block's header.
rawHeader: Bytes!
# Raw is the RLP encoding of the block.
raw: Bytes!
}
# CallData represents the data associated with a local contract call.
@ -379,7 +439,7 @@ type SyncState{
# Pending represents the current pending state.
type Pending {
# TransactionCount is the number of transactions in the pending state.
transactionCount: Int!
transactionCount: Long!
# Transactions is a list of transactions in the current pending state.
transactions: [Transaction!]

View File

@ -1,5 +0,0 @@
per protocool folders apply, e.g.
- eth65/queries.toml (obsoleted *eth65* test specs)
- eth66/queries.toml
- ...

View File

@ -23,6 +23,7 @@
{"name":"Address"},
{"name":"Block"},
{"name":"CallResult"},
{"name":"Withdrawal"},
{"name":"Query"},
{"name":"Boolean"},
{"name":"FilterCriteria"},
@ -106,38 +107,38 @@
"""
result = """
{
"chainID":1,
"chainID":"0x1",
"block":{
"__typename":"Block",
"number":3,
"number":"0x3",
"hash":"0x72d69cc3c74c2740c27f4becae6c9f9fc524c702a9a48d23c564b13dce5fe0a1",
"parent":{
"__typename":"Block",
"number":2
"number":"0x2"
},
"nonce":"0x0000000000000000",
"transactionsRoot":"0x8c8775e959d553f9f991a21a8502dbe6819c53c518711f2cbbbd7ed998f65647",
"transactionCount":1,
"transactionCount":"0x1",
"stateRoot":"0x81b1df384897709e96a4b6319fda4e8f7682a1c9d753b1fb772ed4fb19f1e443",
"receiptsRoot":"0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
"miner":{
"__typename":"Account",
"address":"0x8888f1f195afa192cfee860698584c030f4c9db1",
"balance":"0x542253a12a8f8dc0",
"transactionCount":0,
"transactionCount":"0x0",
"code":"0x",
"storage":"0x0000000000000000000000000000000000000000000000000000000000000000"
},
"extraData":"0x42",
"gasLimit":3141592,
"gasLimit":"0x2fefd8",
"baseFeePerGas":null,
"gasUsed":21000,
"gasUsed":"0x5208",
"timestamp":"0x54c99839",
"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
"difficulty":"0x20000",
"totalDifficulty":"0x80000",
"ommerCount":1,
"ommerCount":"0x1",
"ommers":[
{
"__typename":"Block",
@ -154,7 +155,7 @@
"__typename":"Account",
"address":"0x095e7baea6a6c7c4c2dfeb977efac326af552d87",
"balance":"0x1e",
"transactionCount":0,
"transactionCount":"0x0",
"code":"0x",
"storage":"0x0000000000000000000000000000000000000000000000000000000000000000"
},
@ -226,8 +227,8 @@
{
"__typename":"Transaction",
"hash":"0xbb8e2ffb7276bc688c0305d5c35ae219cf036ac7a3b058ffa9d32275cc75f31b",
"nonce":0,
"index":0,
"nonce":"0x0",
"index":"0x0",
"from":{
"__typename":"Account",
"address":"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"
@ -238,21 +239,21 @@
},
"value":"0xa",
"gasPrice":"0x3e8",
"gas":314159,
"gas":"0x4cb2f",
"inputData":"0x",
"block":{
"__typename":"Block",
"number":1
"number":"0x1"
},
"status":1,
"gasUsed":21000,
"cumulativeGasUsed":21000,
"status":"0x1",
"gasUsed":"0x5208",
"cumulativeGasUsed":"0x5208",
"createdContract":null,
"logs":[],
"r":"0x25d49a54362b5ae38cf895fa9a1d3ded6f7d5577e572c9a93cdebff6e33ceaf7",
"s":"0x773806df18e22db29acde1dd96c0418e28738af7f520e5e2c5c673494029e5",
"v":"0x1b",
"type":0,
"type":"0x0",
"accessList":null,
"maxFeePerGas":null,
"maxPriorityFeePerGas":null,
@ -283,7 +284,7 @@
"block":{
"__typename":"Block",
"hash":"0x72d69cc3c74c2740c27f4becae6c9f9fc524c702a9a48d23c564b13dce5fe0a1",
"number":3
"number":"0x3"
}
}
"""
@ -304,7 +305,7 @@
"block":{
"__typename":"Block",
"hash":"0x72d69cc3c74c2740c27f4becae6c9f9fc524c702a9a48d23c564b13dce5fe0a1",
"number":3
"number":"0x3"
}
}
"""
@ -361,9 +362,9 @@
{
"syncing":{
"__typename":"SyncState",
"startingBlock":0,
"currentBlock":3,
"highestBlock":0,
"startingBlock":"0x0",
"currentBlock":"0x3",
"highestBlock":"0x0",
"pulledStates":null,
"knownStates":null
}
@ -386,22 +387,22 @@
"blocks":[
{
"__typename":"Block",
"number":0,
"number":"0x0",
"hash":"0x2b253498ad5e63a16978753398bad1fde371a3e513438297b52d65dc98e1db29"
},
{
"__typename":"Block",
"number":1,
"number":"0x1",
"hash":"0xa4b71270e83c38d941d61fc2d8f3842f98a83203b82c3dea3176f1feb5a67b17"
},
{
"__typename":"Block",
"number":2,
"number":"0x2",
"hash":"0x579d2bdb721bde7a6bc56b53f4962a58493ee11482e8f738702ddb3d65888a74"
},
{
"__typename":"Block",
"number":3,
"number":"0x3",
"hash":"0x72d69cc3c74c2740c27f4becae6c9f9fc524c702a9a48d23c564b13dce5fe0a1"
}
]
@ -426,7 +427,7 @@
result = """
{
"block":{
"estimateGas":21000
"estimateGas":"0x5208"
}
}
"""
@ -457,8 +458,8 @@
"call":{
"__typename":"CallResult",
"data":"0x",
"gasUsed":21000,
"status":1
"gasUsed":"0x5208",
"status":"0x1"
}
}
}
@ -471,24 +472,8 @@ mutation {
sendRawTransaction(data: "0xf86080018304cb2f94095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba077c7cd36820c71821c1aed59de46e70e701c4a8dd89c9ba508ab722210f60da8a03f29825d40c7c3f7bff3ca69267e0f3fb74b2d18b8c2c4e3c135b5d3b06e288d")
}
"""
result = """
{
"sendRawTransaction":"0x4ffa559ae277813fb886d1fa8743a590ba6b699f9893de99f5d1bcea9620b278"
}
"""
[[units]]
name = "query.protocolVersion"
code = """
{
protocolVersion
}
"""
result = """
{
"protocolVersion":66
}
"""
errors = ["[2, 3]: Fatal: Field 'sendRawTransaction' cannot be resolved: \"transaction rejected by txpool\": @[\"sendRawTransaction\"]"]
result = """null"""
[[units]]
name = "query.block(number) logs"

View File

@ -8,7 +8,7 @@
# those terms.
import
std/[os, json],
std/[json],
stew/byteutils,
eth/[p2p, rlp],
graphql, ../nimbus/graphql/ethapi, graphql/test_common,
@ -25,8 +25,8 @@ type
uncles: seq[BlockHeader]
const
caseFolder = "tests" / "graphql" / "eth" & $ethVersion
dataFolder = "tests" / "fixtures" / "eth_tests" / "BlockchainTests" / "ValidBlocks" / "bcUncleTest"
caseFolder = "tests/graphql"
dataFolder = "tests/fixtures/eth_tests/BlockchainTests/ValidBlocks/bcUncleTest"
proc toBlock(n: JsonNode, key: string): EthBlock =
let rlpBlob = hexToSeqByte(n[key].str)
@ -43,7 +43,7 @@ proc setupChain(): CommonRef =
berlinBlock : some(10.toBlockNumber)
)
var jn = json.parseFile(dataFolder / "oneUncle.json")
var jn = json.parseFile(dataFolder & "/oneUncle.json")
for k, v in jn:
if v["network"].str == "Istanbul":
jn = v