Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/execution api spec #69

Merged
merged 50 commits into from
Jan 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
eeb38f0
Fix problem with contract out of assets
tavurth Sep 15, 2022
7c0307b
Add nully value json test
tavurth Sep 16, 2022
f167dff
Fix bug with passing null to a few functions
tavurth Sep 16, 2022
e19e729
Typesafe U256 parsing
tavurth Sep 16, 2022
484f462
Update readme for the web3 to include runner info
tavurth Sep 16, 2022
760326c
Cleanup commits
tavurth Sep 16, 2022
cbd014a
Add specific object tests
tavurth Sep 16, 2022
6a39cb6
Ensure we cover different status types
tavurth Sep 16, 2022
7656494
Add header comments
tavurth Sep 16, 2022
5e45a69
Cleanup
tavurth Sep 16, 2022
1224c80
Add more tests
tavurth Sep 17, 2022
2a981ac
Cleanup
tavurth Sep 17, 2022
1270e05
Revert docs
tavurth Sep 17, 2022
79a08e4
Nimpretty file
tavurth Sep 21, 2022
49b8448
Fix issue in base stew
tavurth Sep 23, 2022
8c5ed8a
Add tests
tavurth Sep 20, 2022
143090a
Sorting
tavurth Sep 20, 2022
38f0129
Work on tests
tavurth Sep 20, 2022
a6a7e12
Move items to the correct location
tavurth Sep 20, 2022
fd7938e
Add TODO
tavurth Sep 20, 2022
a287a24
Add all test executables
tavurth Sep 23, 2022
fcec825
Work on generating tests
tavurth Sep 26, 2022
8ed2be0
Push latest execution API changes
tavurth Sep 26, 2022
5950e3b
Work on eth_call test
tavurth Sep 27, 2022
c92848b
Fix source type
tavurth Sep 27, 2022
d4e0f12
Latest
tavurth Sep 29, 2022
e781692
Add many more tests
tavurth Oct 5, 2022
95443a7
Add more tests
tavurth Oct 5, 2022
8554d52
Revert "from" to "source"
tavurth Oct 21, 2022
07ffa42
Try fix types
tavurth Oct 24, 2022
857b64a
Split to types which fail and those which dont
tavurth Oct 24, 2022
ed52432
Cleanup
tavurth Oct 24, 2022
49e088a
Remove whispher types again
tavurth Oct 24, 2022
7ade1dd
re-remove whisper
tavurth Oct 31, 2022
0abce71
Merge branch 'master' into feature/execution_api_spec
jangko Jan 8, 2024
9edea1c
Add more eth_api signature
jangko Jan 8, 2024
596e925
Readding executions-apis submodule
jangko Jan 8, 2024
a63ae67
Disable test_execution_api
jangko Jan 8, 2024
293c9ba
Nitpick
jangko Jan 8, 2024
afb8c0b
Merge branch 'master' into feature/execution_api_spec
jangko Jan 9, 2024
59bb4ef
Merge branch 'master' into feature/execution_api_spec
jangko Jan 10, 2024
11387cf
add handlers
jangko Jan 11, 2024
395f420
Add last line to handler
jangko Jan 11, 2024
d119665
Some handler pass
jangko Jan 11, 2024
b17a14d
Merge branch 'master' into feature/execution_api_spec
jangko Jan 11, 2024
4c058a9
Finally all tests pass
jangko Jan 11, 2024
689c106
Add the test to all_tests
jangko Jan 11, 2024
8d7795b
Consisten style
jangko Jan 11, 2024
a47f9f7
Turn on submodule downloading in CI
jangko Jan 11, 2024
3a214b9
Temporary workaround of get eth_getBlockReceipts for nim 2.0
jangko Jan 11, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true

- name: Install build dependencies (Linux i386)
if: runner.os == 'Linux' && matrix.target.cpu == 'i386'
Expand Down
14 changes: 14 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,18 @@ node_modules
nohup.out
hardhat.config.js
package-lock.json

# Individual test executables
all_tests
test_contract_dsl
test_contracts
test_deposit_contract
test_execution_api
test_execution_debug_apis
test_execution_types
test_json_marshalling
test_logs
test_null_conversion
test_primitives
test_signed_tx
test_string_decoder
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "tests/execution-apis"]
path = tests/execution-apis
url = https://github.com/ethereum/execution-apis
3 changes: 2 additions & 1 deletion tests/all_tests.nim
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ import
test_signed_tx,
test_execution_types,
test_string_decoder,
test_contract_dsl
test_contract_dsl,
test_execution_api
1 change: 1 addition & 0 deletions tests/execution-apis
Submodule execution-apis added at cea7ee
159 changes: 159 additions & 0 deletions tests/helpers/handlers.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
# json-rpc
# Copyright (c) 2024 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
# at your option.
# This file may not be copied, modified, or distributed except according to
# those terms.

import
stint,
eth/common,
json_rpc/rpcserver,
../../web3/conversions,
../../web3/eth_api_types,
../../web3/primitives as w3

type
Hash256 = w3.Hash256

proc installHandlers*(server: RpcServer) =
server.rpc("eth_syncing") do(x: JsonString, ) -> bool:
return false

server.rpc("eth_sendRawTransaction") do(x: JsonString, data: seq[byte]) -> TxHash:
let tx = rlp.decode(data, Transaction)
let h = rlpHash(tx)
return TxHash(h.data)

server.rpc("eth_getTransactionReceipt") do(x: JsonString, data: TxHash) -> ReceiptObject:
var r: ReceiptObject
if x != "-1".JsonString:
r = JrpcConv.decode(x.string, ReceiptObject)
return r

server.rpc("eth_getTransactionByHash") do(x: JsonString, data: TxHash) -> TransactionObject:
var tx: TransactionObject
if x != "-1".JsonString:
tx = JrpcConv.decode(x.string, TransactionObject)
return tx

server.rpc("eth_getTransactionByBlockNumberAndIndex") do(x: JsonString, blockId: RtBlockIdentifier, quantity: Quantity) -> TransactionObject:
var tx: TransactionObject
if x != "-1".JsonString:
tx = JrpcConv.decode(x.string, TransactionObject)
return tx

server.rpc("eth_getTransactionByBlockHashAndIndex") do(x: JsonString, data: Hash256, quantity: Quantity) -> TransactionObject:
var tx: TransactionObject
if x != "-1".JsonString:
tx = JrpcConv.decode(x.string, TransactionObject)
return tx

server.rpc("eth_getTransactionCount") do(x: JsonString, data: Address, blockId: RtBlockIdentifier) -> Quantity:
if x != "-1".JsonString:
result = JrpcConv.decode(x.string, Quantity)

server.rpc("eth_getStorageAt") do(x: JsonString, data: Address, slot: UInt256, blockId: RtBlockIdentifier) -> FixedBytes[32]:
if x != "-1".JsonString:
result = JrpcConv.decode(x.string, FixedBytes[32])

server.rpc("eth_getProof") do(x: JsonString, address: Address, slots: seq[UInt256], blockId: RtBlockIdentifier) -> ProofResponse:
var p: ProofResponse
if x != "-1".JsonString:
p = JrpcConv.decode(x.string, ProofResponse)
return p

server.rpc("eth_getCode") do(x: JsonString, data: Address, blockId: RtBlockIdentifier) -> seq[byte]:
if x != "-1".JsonString:
result = JrpcConv.decode(x.string, seq[byte])

server.rpc("eth_getBlockTransactionCountByNumber") do(x: JsonString, blockId: RtBlockIdentifier) -> Quantity:
if x != "-1".JsonString:
result = JrpcConv.decode(x.string, Quantity)

server.rpc("eth_getBlockTransactionCountByHash") do(x: JsonString, data: BlockHash) -> Quantity:
if x != "-1".JsonString:
result = JrpcConv.decode(x.string, Quantity)

when NimMajor >= 2:
server.rpc("eth_getBlockReceipts") do(x: JsonString, blockId: RtBlockIdentifier) -> JsonString:
# TODO: cannot prove obj is not nil
return x
else:
server.rpc("eth_getBlockReceipts") do(x: JsonString, blockId: RtBlockIdentifier) -> Option[seq[ReceiptObject]]:
if x == "null".JsonString:
var n: Option[seq[ReceiptObject]]
return n
if x != "-1".JsonString:
let r = JrpcConv.decode(x.string, seq[ReceiptObject])
return some(r)

server.rpc("eth_getBlockByNumber") do(x: JsonString, blockId: RtBlockIdentifier, fullTransactions: bool) -> BlockObject:
var blk: BlockObject
if x != "-1".JsonString:
blk = JrpcConv.decode(x.string, BlockObject)
return blk

server.rpc("eth_getBlockByHash") do(x: JsonString, data: BlockHash, fullTransactions: bool) -> BlockObject:
var blk: BlockObject
if x != "-1".JsonString:
blk = JrpcConv.decode(x.string, BlockObject)
return blk

server.rpc("eth_getBalance") do(x: JsonString, data: Address, blockId: RtBlockIdentifier) -> UInt256:
if x != "-1".JsonString:
result = JrpcConv.decode(x.string, UInt256)

server.rpc("eth_feeHistory") do(x: JsonString, blockCount: Quantity, newestBlock: RtBlockIdentifier, rewardPercentiles: Option[seq[float64]]) -> FeeHistoryResult:
var fh: FeeHistoryResult
if x != "-1".JsonString:
fh = JrpcConv.decode(x.string, FeeHistoryResult)
return fh

server.rpc("eth_estimateGas") do(x: JsonString, call: EthCall) -> Quantity:
if x != "-1".JsonString:
result = JrpcConv.decode(x.string, Quantity)

server.rpc("eth_createAccessList") do(x: JsonString, call: EthCall, blockId: RtBlockIdentifier) -> AccessListResult:
var z: AccessListResult
if x != "-1".JsonString:
z = JrpcConv.decode(x.string, AccessListResult)
return z

server.rpc("eth_chainId") do(x: JsonString, ) -> Quantity:
if x != "-1".JsonString:
result = JrpcConv.decode(x.string, Quantity)

server.rpc("eth_call") do(x: JsonString, call: EthCall, blockId: RtBlockIdentifier) -> seq[byte]:
if x != "-1".JsonString:
result = JrpcConv.decode(x.string, seq[byte])

server.rpc("eth_blockNumber") do(x: JsonString) -> Quantity:
if x != "-1".JsonString:
result = JrpcConv.decode(x.string, Quantity)

server.rpc("debug_getRawTransaction") do(x: JsonString, data: TxHash) -> RlpEncodedBytes:
var res: seq[byte]
if x != "-1".JsonString:
res = JrpcConv.decode(x.string, seq[byte])
return res.RlpEncodedBytes

server.rpc("debug_getRawReceipts") do(x: JsonString, blockId: RtBlockIdentifier) -> seq[RlpEncodedBytes]:
var res: seq[RlpEncodedBytes]
if x != "-1".JsonString:
res = JrpcConv.decode(x.string, seq[RlpEncodedBytes])
return res

server.rpc("debug_getRawHeader") do(x: JsonString, blockId: RtBlockIdentifier) -> RlpEncodedBytes:
var res: seq[byte]
if x != "-1".JsonString:
res = JrpcConv.decode(x.string, seq[byte])
return res.RlpEncodedBytes

server.rpc("debug_getRawBlock") do(x: JsonString, blockId: RtBlockIdentifier) -> RlpEncodedBytes:
var res: seq[byte]
if x != "-1".JsonString:
res = JrpcConv.decode(x.string, seq[byte])
return res.RlpEncodedBytes
110 changes: 110 additions & 0 deletions tests/test_execution_api.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import
std/[os, strutils],
pkg/unittest2,
chronos,
json_rpc/[rpcclient, rpcserver],
json_rpc/private/jrpc_sys,
../web3/conversions,
./helpers/handlers

type
TestData = tuple
file: string
input: RequestTx
output: ResponseRx

const
inputPath = "tests/execution-apis/tests"

func strip(line: string): string =
return line[3..^1]

func toTx(req: RequestRx): RequestTx =
RequestTx(
id: Opt.some(req.id),
`method`: req.`method`.get(),
params: req.params.toTx,
)

proc extractTest(fileName: string): TestData =
let
lines = readFile(fileName).split("\n")
input = lines[0].strip()
output = lines[1].strip()

return (
file: fileName,
input: JrpcSys.decode(input, RequestRx).toTx,
output: JrpcSys.decode(output, ResponseRx),
)

proc extractTests(): seq[TestData] =
for fileName in walkDirRec(inputPath):
if fileName.endsWith(".io"):
result.add(fileName.extractTest())

proc callWithParams(client: RpcClient, data: TestData): Future[bool] {.async.} =
let res = data.output

try:
var params = data.input.params
if data.output.result.string.len > 0:
params.positional.insert(data.output.result, 0)
else:
params.positional.insert("-1".JsonString, 0)

let resJson = await client.call(data.input.`method`, params)

if res.result.string.len > 0:
let wantVal = JrpcConv.decode(res.result.string, JsonValueRef[string])
let getVal = JrpcConv.decode(resJson.string, JsonValueRef[string])

if wantVal != getVal:
debugEcho data.file
debugEcho "EXPECT: ", res.result
debugEcho "GET: ", resJson.string
return false

return true
except SerializationError as exc:
debugEcho data.file
debugEcho exc.formatMsg("xxx")
return false
except CatchableError as exc:
if res.error.isSome:
return true
debugEcho data.file
debugEcho exc.msg
return false

const allowedToFail = [
"fee-history.io" # float roundtrip not match
]

suite "Ethereum execution api":
let testCases = extractTests()
if testCases.len < 1:
raise newException(ValueError, "execution_api tests not found, did you clone?")

var srv = newRpcHttpServer(["127.0.0.1:0"])
srv.installHandlers()
srv.start()

for idx, item in testCases:
let input = item.input
let methodName = input.`method`

test methodName:
let (_, fileName, ext) = splitFile(item.file)
let client = newRpcHttpClient()
waitFor client.connect("http://" & $srv.localAddress()[0])
let response = waitFor client.callWithParams(item)
let source = fileName & ext
if source in allowedToFail:
check true
else:
check response
waitFor client.close()

waitFor srv.stop()
waitFor srv.closeWait()
3 changes: 1 addition & 2 deletions tests/test_logs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ contract(LoggerContract):
proc MyEvent(sender: Address, number: UInt256) {.event.}
proc invoke(value: UInt256)

const LoggerContractCode = "6080604052348015600f57600080fd5b5060bc8061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80632b30d2b814602d575b600080fd5b604760048036036020811015604157600080fd5b50356049565b005b604080513381526020810183905281517fdf50c7bb3b25f812aedef81bc334454040e7b27e27de95a79451d663013b7e17929181900390910190a15056fea265627a7a723058202ed7f5086297d2a49fbe359f4e489a007b69eb5077f5c76328bffdb63f164b4b64736f6c63430005090032"
const LoggerContractCode = "6080604052348015600f57600080fd5b5060fb8061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80632b30d2b814602d575b600080fd5b605660048036036020811015604157600080fd5b81019080803590602001909291905050506058565b005b7fdf50c7bb3b25f812aedef81bc334454040e7b27e27de95a79451d663013b7e173382604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a15056fea265627a7a72315820cb9980a67d78ee2e84fedf080db8463ce4a944fccf8b5512448163aaff0aea8964736f6c63430005110032"

var contractAddress = Address.fromHex("0xEA255DeA28c84F698Fa195f87fC83D1d4125ef9C")

Expand All @@ -48,7 +48,6 @@ suite "Logs":
# let q = await web3.provider.eth_blockNumber()
echo "block: ", uint64(await web3.provider.eth_blockNumber())


block: # LoggerContract
let receipt = await web3.deployContract(LoggerContractCode)
contractAddress = receipt.contractAddress.get
Expand Down
3 changes: 2 additions & 1 deletion web3/conversions.nim
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ ProofResponse.useDefaultSerializationIn JrpcConv
FilterOptions.useDefaultSerializationIn JrpcConv
EthSend.useDefaultSerializationIn JrpcConv
EthCall.useDefaultSerializationIn JrpcConv
FeeHistoryResult.useDefaultSerializationIn JrpcConv

derefType(BlockHeader).useDefaultSerializationIn JrpcConv
derefType(BlockObject).useDefaultSerializationIn JrpcConv
Expand Down Expand Up @@ -290,7 +291,7 @@ proc readValue*(r: var JsonReader[JrpcConv], val: var RtBlockIdentifier)
val = RtBlockIdentifier(kind: bidNumber, number: fromHex[uint64](hexStr))
else:
val = RtBlockIdentifier(kind: bidAlias, alias: hexStr)

proc writeValue*(w: var JsonWriter[JrpcConv], v: RtBlockIdentifier)
{.gcsafe, raises: [IOError].} =
case v.kind
Expand Down
15 changes: 13 additions & 2 deletions web3/eth_api.nim
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,11 @@ createRpcSigsFromNim(RpcClient):
proc eth_accounts(): seq[Address]
proc eth_blockNumber(): Quantity
proc eth_getBalance(data: Address, blockId: BlockIdentifier): UInt256
proc eth_getStorageAt(data: Address, slot: UInt256, blockId: BlockIdentifier): UInt256
proc eth_getStorageAt(data: Address, slot: UInt256, blockId: BlockIdentifier): FixedBytes[32]
proc eth_getTransactionCount(data: Address, blockId: BlockIdentifier): Quantity
proc eth_getBlockTransactionCountByHash(data: BlockHash): Quantity
proc eth_getBlockTransactionCountByNumber(blockId: BlockIdentifier): Quantity
proc eth_getBlockReceipts(blockId: BlockIdentifier): Option[seq[ReceiptObject]]
proc eth_getUncleCountByBlockHash(data: BlockHash): Quantity
proc eth_getUncleCountByBlockNumber(blockId: BlockIdentifier): Quantity
proc eth_getCode(data: Address, blockId: BlockIdentifier): seq[byte]
Expand All @@ -47,7 +48,7 @@ createRpcSigsFromNim(RpcClient):
proc eth_sendTransaction(obj: EthSend): TxHash
proc eth_sendRawTransaction(data: seq[byte]): TxHash
proc eth_call(call: EthCall, blockId: BlockIdentifier): seq[byte]
proc eth_estimateGas(call: EthCall, blockId: BlockIdentifier): Quantity
proc eth_estimateGas(call: EthCall): Quantity
proc eth_createAccessList(call: EthCall, blockId: BlockIdentifier): AccessListResult
proc eth_getBlockByHash(data: BlockHash, fullTransactions: bool): BlockObject
proc eth_getBlockByNumber(blockId: BlockIdentifier, fullTransactions: bool): BlockObject
Expand Down Expand Up @@ -82,5 +83,15 @@ createRpcSigsFromNim(RpcClient):
slots: seq[UInt256],
blockId: BlockIdentifier): ProofResponse

proc eth_feeHistory(
blockCount: Quantity,
newestBlock: BlockIdentifier,
rewardPercentiles: Option[seq[float64]]): FeeHistoryResult

proc debug_getRawBlock(blockId: BlockIdentifier): RlpEncodedBytes
proc debug_getRawHeader(blockId: BlockIdentifier): RlpEncodedBytes
proc debug_getRawReceipts(blockId: BlockIdentifier): seq[RlpEncodedBytes]
proc debug_getRawTransaction(data: TxHash): RlpEncodedBytes

createSingleRpcSig(RpcClient, "eth_getJsonLogs"):
proc eth_getLogs(filterOptions: FilterOptions): seq[JsonString]
8 changes: 8 additions & 0 deletions web3/eth_api_types.nim
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,14 @@ type
of bidAlias:
alias*: string

FeeHistoryReward* = array[2, Quantity]

FeeHistoryResult* = object
oldestBlock*: Quantity
baseFeePerGas*: seq[Quantity]
gasUsedRatio*: seq[float64]
reward*: seq[FeeHistoryReward]

{.push raises: [].}

func blockId*(n: BlockNumber): RtBlockIdentifier =
Expand Down