engine api test: handle JsonRpcError for each client rpc call

This commit is contained in:
jangko 2022-08-04 12:06:31 +07:00
parent 5f0e89a41e
commit 11908c78ec
No known key found for this signature in database
GPG Key ID: 31702AE10541E6B9
4 changed files with 81 additions and 99 deletions

View File

@ -1,9 +1,9 @@
import
std/[times, json],
std/[times, json, strutils],
stew/byteutils,
eth/[common, rlp], chronos,
web3/engine_api_types,
json_rpc/rpcclient,
json_rpc/[rpcclient, errors],
../../../tests/rpcclient/eth_api,
../../../premix/parser,
../../../nimbus/rpc/hexstrings,
@ -11,31 +11,35 @@ import
import web3/engine_api as web3_engine_api
template wrapTry(body: untyped) =
try:
body
except ValueError as e:
return err(e.msg)
except JsonRpcError as ex:
return err(ex.msg)
template wrapTrySimpleRes(body: untyped) =
wrapTry:
let res = waitFor body
return ok(res)
proc forkchoiceUpdatedV1*(client: RpcClient,
update: ForkchoiceStateV1,
payloadAttributes = none(PayloadAttributesV1)):
Result[ForkchoiceUpdatedResponse, string] =
try:
let res = waitFor client.engine_forkchoiceUpdatedV1(update, payloadAttributes)
return ok(res)
except ValueError as e:
return err(e.msg)
wrapTrySimpleRes:
client.engine_forkchoiceUpdatedV1(update, payloadAttributes)
proc getPayloadV1*(client: RpcClient, payloadId: PayloadID): Result[ExecutionPayloadV1, string] =
try:
let res = waitFor client.engine_getPayloadV1(payloadId)
return ok(res)
except ValueError as e:
return err(e.msg)
wrapTrySimpleRes:
client.engine_getPayloadV1(payloadId)
proc newPayloadV1*(client: RpcClient,
payload: ExecutionPayloadV1):
Result[PayloadStatusV1, string] =
try:
let res = waitFor client.engine_newPayloadV1(payload)
return ok(res)
except ValueError as e:
return err(e.msg)
wrapTrySimpleRes:
client.engine_newPayloadV1(payload)
proc toBlockNumber(n: Option[HexQuantityStr]): common.BlockNumber =
if n.isNone:
@ -95,25 +99,21 @@ proc waitForTTD*(client: RpcClient,
return (emptyHeader, false)
proc blockNumber*(client: RpcClient): Result[uint64, string] =
try:
wrapTry:
let res = waitFor client.eth_blockNumber()
return ok(hexToInt(string res, uint64))
except ValueError as e:
return err(e.msg)
proc headerByNumber*(client: RpcClient, number: uint64, output: var common.BlockHeader): Result[void, string] =
try:
wrapTry:
let qty = encodeQuantity(number)
let res = waitFor client.eth_getBlockByNumber(string qty, false)
if res.isNone:
return err("failed to get blockHeader: " & $number)
output = toBlockHeader(res.get())
return ok()
except ValueError as e:
return err(e.msg)
proc blockByNumber*(client: RpcClient, number: uint64, output: var common.EthBlock): Result[void, string] =
try:
wrapTry:
let qty = encodeQuantity(number)
let res = waitFor client.eth_getBlockByNumber(string qty, true)
if res.isNone:
@ -122,32 +122,26 @@ proc blockByNumber*(client: RpcClient, number: uint64, output: var common.EthBlo
output.header = toBlockHeader(blk)
output.txs = toTransactions(blk.transactions)
return ok()
except ValueError as e:
return err(e.msg)
proc headerByHash*(client: RpcClient, hash: Hash256, output: var common.BlockHeader): Result[void, string] =
try:
wrapTry:
let res = waitFor client.eth_getBlockByHash(hash, false)
if res.isNone:
return err("failed to get block: " & hash.data.toHex)
let blk = res.get()
output = toBlockHeader(blk)
return ok()
except ValueError as e:
return err(e.msg)
proc latestHeader*(client: RpcClient, output: var common.BlockHeader): Result[void, string] =
try:
wrapTry:
let res = waitFor client.eth_getBlockByNumber("latest", false)
if res.isNone:
return err("failed to get latest blockHeader")
output = toBlockHeader(res.get())
return ok()
except ValueError as e:
return err(e.msg)
proc latestBlock*(client: RpcClient, output: var common.EthBlock): Result[void, string] =
try:
wrapTry:
let res = waitFor client.eth_getBlockByNumber("latest", true)
if res.isNone:
return err("failed to get latest blockHeader")
@ -155,21 +149,17 @@ proc latestBlock*(client: RpcClient, output: var common.EthBlock): Result[void,
output.header = toBlockHeader(blk)
output.txs = toTransactions(blk.transactions)
return ok()
except ValueError as e:
return err(e.msg)
proc namedHeader*(client: RpcClient, name: string, output: var common.BlockHeader): Result[void, string] =
try:
wrapTry:
let res = waitFor client.eth_getBlockByNumber(name, false)
if res.isNone:
return err("failed to get named blockHeader")
output = toBlockHeader(res.get())
return ok()
except ValueError as e:
return err(e.msg)
proc sendTransaction*(client: RpcClient, tx: common.Transaction): Result[void, string] =
try:
wrapTry:
let encodedTx = rlp.encode(tx)
let res = waitFor client.eth_sendRawTransaction(hexDataStr(encodedTx))
let txHash = rlpHash(tx)
@ -177,24 +167,18 @@ proc sendTransaction*(client: RpcClient, tx: common.Transaction): Result[void, s
if txHash != getHash:
return err("sendTransaction: tx hash mismatch")
return ok()
except ValueError as e:
return err(e.msg)
proc balanceAt*(client: RpcClient, address: EthAddress): Result[UInt256, string] =
try:
wrapTry:
let res = waitFor client.eth_getBalance(ethAddressStr(address), "latest")
return ok(UInt256.fromHex(res.string))
except ValueError as e:
return err(e.msg)
proc txReceipt*(client: RpcClient, txHash: Hash256): Result[eth_api.ReceiptObject, string] =
try:
wrapTry:
let res = waitFor client.eth_getTransactionReceipt(txHash)
if res.isNone:
return err("failed to get receipt: " & txHash.data.toHex)
return ok(res.get)
except ValueError as e:
return err(e.msg)
proc toDataStr(slot: UInt256): HexDataStr =
let hex = slot.toHex
@ -202,19 +186,15 @@ proc toDataStr(slot: UInt256): HexDataStr =
HexDataStr(prefix & hex)
proc storageAt*(client: RpcClient, address: EthAddress, slot: UInt256): Result[UInt256, string] =
try:
wrapTry:
let res = waitFor client.eth_getStorageAt(ethAddressStr(address), toDataStr(slot), "latest")
return ok(UInt256.fromHex(res.string))
except ValueError as e:
return err(e.msg)
proc storageAt*(client: RpcClient, address: EthAddress, slot: UInt256, number: common.BlockNumber): Result[UInt256, string] =
try:
wrapTry:
let tag = encodeQuantity(number)
let res = waitFor client.eth_getStorageAt(ethAddressStr(address), toDataStr(slot), tag.string)
return ok(UInt256.fromHex(res.string))
except ValueError as e:
return err(e.msg)
proc verifyPoWProgress*(client: RpcClient, lastBlockHash: Hash256): Future[Result[void, string]] {.async.} =
let res = await client.eth_getBlockByHash(lastBlockHash, false)
@ -245,3 +225,40 @@ proc verifyPoWProgress*(client: RpcClient, lastBlockHash: Hash256): Future[Resul
inc loop
return err("verify PoW Progress timeout")
proc debugPrevRandaoTransaction*(client: RpcClient, tx: Transaction, expectedPrevRandao: Hash256): Result[void, string] =
wrapTry:
let hash = tx.rlpHash
# we only interested in stack, disable all other elems
let opts = %* {
"disableStorage": true,
"disableMemory": true,
"disableState": true,
"disableStateDiff": true
}
let res = waitFor client.call("debug_traceTransaction", %[%hash, opts])
let structLogs = res["structLogs"]
var prevRandaoFound = false
for i, x in structLogs.elems:
let op = x["op"].getStr
if op != "DIFFICULTY": continue
if i+1 >= structLogs.len:
return err("No information after PREVRANDAO operation")
prevRandaoFound = true
let stack = structLogs[i+1]["stack"]
if stack.len < 1:
return err("Invalid stack after PREVRANDAO operation")
let stackHash = Hash256(data: hextoByteArray[32](stack[0].getStr))
if stackHash != expectedPrevRandao:
return err("Invalid stack after PREVRANDAO operation $1 != $2" % [stackHash.data.toHex, expectedPrevRandao.data.toHex])
if not prevRandaoFound:
return err("PREVRANDAO opcode not found")
return ok()

View File

@ -1736,6 +1736,8 @@ proc prevRandaoOpcodeTx(t: TestEnv): TestStatus =
return true
))
testCond produceBlockRes
let rr = client.blockNumber()
testCond rr.isOk:
error "Unable to get latest block number"

View File

@ -1,10 +1,10 @@
import
std/[typetraits, json, strutils],
std/[typetraits, json],
nimcrypto,
test_env,
eth/[common, rlp, keys],
stew/byteutils,
json_rpc/[rpcclient, errors],
json_rpc/[rpcclient],
../../../nimbus/rpc/hexstrings,
../../../nimbus/transaction
@ -183,48 +183,6 @@ proc toExecutableData*(payload: ExecutionPayloadV1): ExecutableData =
proc customizePayload*(basePayload: ExecutionPayloadV1, customData: CustomPayload): ExecutionPayloadV1 =
customizePayload(basePayload.toExecutableData, customData)
proc debugPrevRandaoTransaction*(client: RpcClient, tx: Transaction, expectedPrevRandao: Hash256): Result[void, string] =
try:
let hash = tx.rlpHash
# we only interested in stack, disable all other elems
let opts = %* {
"disableStorage": true,
"disableMemory": true,
"disableState": true,
"disableStateDiff": true
}
let res = waitFor client.call("debug_traceTransaction", %[%hash, opts])
let structLogs = res["structLogs"]
var prevRandaoFound = false
for i, x in structLogs.elems:
let op = x["op"].getStr
if op != "DIFFICULTY": continue
if i+1 >= structLogs.len:
return err("No information after PREVRANDAO operation")
prevRandaoFound = true
let stack = structLogs[i+1]["stack"]
if stack.len < 1:
return err("Invalid stack after PREVRANDAO operation")
let stackHash = Hash256(data: hextoByteArray[32](stack[0].getStr))
if stackHash != expectedPrevRandao:
return err("Invalid stack after PREVRANDAO operation $1 != $2" % [stackHash.data.toHex, expectedPrevRandao.data.toHex])
if not prevRandaoFound:
return err("PREVRANDAO opcode not found")
ok()
except ValueError as e:
err(e.msg)
except JsonRpcError as ex:
# occasionally for unknown reason this proc will fail in CI
# let's see what actually trigger it
err(ex.msg)
proc customizeTx(baseTx: Transaction, vaultKey: PrivateKey, customTx: CustomTx): Transaction =
# Create a modified transaction base, from the base transaction and customData mix
var modTx = Transaction(

View File

@ -11,13 +11,18 @@ import
std/[typetraits, times, strutils],
stew/[objects, results, byteutils],
json_rpc/[rpcserver, errors],
web3/[conversions, engine_api_types], chronicles,
web3/[conversions, engine_api_types],
eth/[rlp, common],
".."/db/db_chain,
".."/p2p/chain/[chain_desc, persist_blocks],
".."/[sealer, constants],
".."/merge/[mergetypes, mergeutils],
".."/utils/tx_pool
".."/utils/tx_pool,
# put chronicles import last because Nim
# compiler resolve `$` for logging
# arguments differently on Windows vs posix
# if chronicles import is in the middle
chronicles
proc latestValidHash(db: BaseChainDB, parent: EthBlockHeader, ttd: DifficultyInt): Hash256 =
let ptd = db.getScore(parent.parentHash)