-
Notifications
You must be signed in to change notification settings - Fork 83
feat: stop skipping the confromity tests #3824
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
base: main
Are you sure you want to change the base?
Changes from all commits
38485bc
71c9428
b3b826b
a66407f
c19fd04
61c4313
a3d44ed
7ffe1d3
473a4b5
e42da44
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ import CallerContract from '../contracts/Caller.json'; | |
import LogsContract from '../contracts/Logs.json'; | ||
|
||
const directoryPath = path.resolve(__dirname, '../../../../node_modules/execution-apis/tests'); | ||
const overwritesDirectoryPath = path.resolve(__dirname, 'data/conformity/overwrites'); | ||
|
||
let currentBlockHash; | ||
let legacyTransactionAndBlockHash; | ||
|
@@ -347,53 +348,64 @@ const synthesizeTestCases = function (testCases, updateParamIfNeeded) { | |
} | ||
}; | ||
|
||
/** | ||
* To run the Ethereum Execution API tests as defined in the repository ethereum/execution-apis, it’s necessary | ||
* to execute them against a specifically configured node. This node must use: | ||
* - Transactions from the blocks in chain.rlp (https://github.com/ethereum/execution-apis/blob/main/tests/chain.rlp), | ||
* - Account balances from genesis.json (https://github.com/ethereum/execution-apis/blob/main/tests/genesis.json). | ||
* | ||
* We cannot replay all of the chain.rlp transactions directly, as they are already signed with a chain id | ||
* that exceeds Java’s Integer.MAX_VALUE (which is also the maximum allowed chain ID in Hedera). | ||
* However, we can replicate the test environment by deploying the required smart contracts manually. | ||
* While these contracts will receive different addresses than those in the original tests, | ||
* their behavior will remain consistent with the expectations. | ||
*/ | ||
const initGenesisData = async function () { | ||
for (const data of require('./data/conformity/genesis.json')) { | ||
const options = { maxPriorityFeePerGas: gasPrice, maxFeePerGas: gasPrice, gasLimit: gasLimit }; | ||
options['to'] = data.account ? data.account : null; | ||
if (data.balance) options['value'] = `0x${data.balance.toString(16)}`; | ||
if (data.bytecode) options['data'] = data.bytecode; | ||
await signAndSendRawTransaction({ chainId, from: sendAccountAddress, type: 2, ...options }); | ||
} | ||
}; | ||
|
||
describe('@api-conformity', async function () { | ||
before(async () => { | ||
relayOpenRpcData = await parseOpenRPCDocument(JSON.stringify(openRpcData)); | ||
}); | ||
|
||
describe('@conformity-batch-1 Ethereum execution apis tests', function () { | ||
this.timeout(240 * 1000); | ||
execApisOpenRpcData = require('../../../../openrpc_exec_apis.json'); | ||
before(async () => { | ||
legacyTransactionAndBlockHash = await signAndSendRawTransaction(legacyTransaction); | ||
transaction2930AndBlockHash = await signAndSendRawTransaction(transaction2930); | ||
transaction1559AndBlockHash = await signAndSendRawTransaction(transaction1559); | ||
createContractLegacyTransactionAndBlockHash = await signAndSendRawTransaction(createContractLegacyTransaction); | ||
await initGenesisData(); | ||
currentBlockHash = await getLatestBlockHash(); | ||
}); | ||
//Reading the directories within the ethereum execution api repo | ||
let directories = fs.readdirSync(directoryPath); | ||
//Adds tests for custom Hedera methods from override directory to the list, even if they're not in the OpenRPC spec. | ||
let directories = [...new Set([...fs.readdirSync(directoryPath), ...fs.readdirSync(overwritesDirectoryPath)])]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this line needed if in overwrites we always have directories that are anyways existing in the original directorypath in the execution-apis repo? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @konstantinabl It handles the case where there's an extra directory (containing a custom method not present in the OpenRPC API specification) in the overwrite directory that doesn't exist in the overwritten directory. It may not be necessary at this point, as it is not currently in use. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay, got it |
||
const relaySupportedMethodNames = openRpcData.methods.map((method) => method.name); | ||
|
||
//Filtering in order to use only the tests for methods we support in our relay | ||
directories = directories.filter((directory) => relaySupportedMethodNames.includes(directory)); | ||
for (const directory of directories) { | ||
const filePath = path.join(directoryPath, directory); | ||
if (fs.statSync(filePath).isDirectory()) { | ||
const files = fs.readdirSync(path.resolve(directoryPath, directory)); | ||
for (const file of files) { | ||
it(`Executing for ${directory} and ${file}`, async () => { | ||
//We are excluding these directories, since these tests in execution-apis repos | ||
//use set of contracts which are not deployed on our network | ||
if ( | ||
directory === 'eth_getLogs' || | ||
directory === 'eth_call' || | ||
directory === 'eth_estimateGas' || | ||
directory === 'eth_getProof' || | ||
directory === 'eth_createAccessList' | ||
) { | ||
return; | ||
} | ||
execApisOpenRpcData = require('../../../../openrpc_exec_apis.json'); | ||
//Currently, we do not support blobs | ||
if (file.includes('blob')) { | ||
return; | ||
} | ||
const data = fs.readFileSync(path.resolve(directoryPath, directory, file)); | ||
const content = splitReqAndRes(data.toString('utf-8')); | ||
await processFileContent(directory, file, content); | ||
}); | ||
} | ||
//Lists all files (tests) in a directory (method). Returns an empty array for non-existing directory. | ||
const ls = (dir: string) => (fs.existsSync(dir) && fs.statSync(dir).isDirectory() ? fs.readdirSync(dir) : []); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we would benefit from some clarifications in the code here as well |
||
const files = [ | ||
...new Set([...ls(path.join(directoryPath, directory)), ...ls(path.join(overwritesDirectoryPath, directory))]), | ||
]; | ||
for (const file of files) { | ||
const isCustom = fs.existsSync(path.join(overwritesDirectoryPath, directory, file)); | ||
it(`Executing for ${directory} and ${file}${isCustom ? ' (overwritten)' : ''}`, async () => { | ||
const dir = isCustom ? overwritesDirectoryPath : directoryPath; | ||
const data = fs.readFileSync(path.resolve(dir, directory, file)); | ||
const content = splitReqAndRes(data.toString('utf-8')); | ||
await processFileContent(directory, file, content); | ||
}); | ||
} | ||
} | ||
}); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
[ | ||
{"account":"0x7dcd17433742f4c0ca53122ab541d0ba67fc27df","balance":10000000000}, | ||
{"account":null,"balance":0,"bytecode":"0x608060405234801561001057600080fd5b50610384806100206000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80632a4c08961461005c57806378b9a1f314610078578063c670f86414610094578063c683d6a3146100b0578063d05285d4146100cc575b600080fd5b61007660048036038101906100719190610251565b6100e8565b005b610092600480360381019061008d9190610215565b61011c565b005b6100ae60048036038101906100a991906101ec565b61014e565b005b6100ca60048036038101906100c591906102a0565b61017e565b005b6100e660048036038101906100e191906101ec565b6101be565b005b8082847fa8fb2f9a49afc2ea148319326c7208965555151db2ce137c05174098730aedc360405160405180910390a4505050565b80827f513dad7582fd8b11c8f4d05e6e7ac8caaa5eb690e9173dd2bed96b5ae0e0d02460405160405180910390a35050565b807f46692c0e59ca9cd1ad8f984a9d11715ec83424398b7eed4e05c8ce84662415a860405160405180910390a250565b8183857f75e7d95cd72588af49ce2e4b7f004bce916d422999adf262a640e4239aab00c7846040516101b09190610312565b60405180910390a450505050565b806040516101cc9190610312565b60405180910390a050565b6000813590506101e681610337565b92915050565b6000602082840312156101fe57600080fd5b600061020c848285016101d7565b91505092915050565b6000806040838503121561022857600080fd5b6000610236858286016101d7565b9250506020610247858286016101d7565b9150509250929050565b60008060006060848603121561026657600080fd5b6000610274868287016101d7565b9350506020610285868287016101d7565b9250506040610296868287016101d7565b9150509250925092565b600080600080608085870312156102b657600080fd5b60006102c4878288016101d7565b94505060206102d5878288016101d7565b93505060406102e6878288016101d7565b92505060606102f7878288016101d7565b91505092959194509250565b61030c8161032d565b82525050565b60006020820190506103276000830184610303565b92915050565b6000819050919050565b6103408161032d565b811461034b57600080fd5b5056fea2646970667358221220a395344b5de9693999e0f06fc92d3f51a0cd6f30e383c9eccda35f50c04bac6364736f6c63430008040033"}, | ||
{"account":null,"balance":0,"bytecode":"0x6080604052348015600f57600080fd5b50607680601d6000396000f3fe608060405261ff0160003560f01c1415601e5761ffee60005260206000f35b43600052466020524160405248606052446080523260a0523460c05260e06000f3fea2646970667358221220df54ebe42ca12e658508ac87a25033e061bc8839fb14f209f8a89f2f0095e91f64736f6c63430008090033"} | ||
] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
# Hedera JSON-RPC test overrides | ||
|
||
This directory contains **overridden test cases** for the [Ethereum Execution API JSON-RPC test suite](https://github.com/ethereum/execution-apis/tree/main/tests), adjusted to validate **Hedera’s JSON-RPC relay**. | ||
|
||
## Purpose | ||
|
||
The upstream `rpc-compat` test suite is designed for Ethereum clients and assumes compatibility with Ethereum-specific data (e.g., signed blocks in `chain.rlp`, Ethereum chain IDs, transaction signatures). However, due to protocol differences, **some test cases cannot be executed as-is against a Hedera node**. | ||
|
||
This directory provides **Hedera-compatible test overrides** that: | ||
|
||
- Mirror the structure of the upstream tests. | ||
- Reflect behavior specific to the Hedera JSON-RPC relay. | ||
- Serve as a drop-in replacement when upstream tests are not applicable. | ||
|
||
## Structure | ||
|
||
Each test override is stored using the `.io` format: | ||
|
||
``` | ||
Overrides | ||
eth_call/ | ||
call-callenv.io | ||
eth_getLogs/ | ||
no-topics.io | ||
```` | ||
|
||
Each file consists of a single round-trip request and response: | ||
|
||
``` | ||
>> {"jsonrpc":"2.0","id":1,"method":"eth_blockNumber"} | ||
<< {"jsonrpc":"2.0","id":1,"result":"0x3"} | ||
```` | ||
|
||
The folder structure mirrors the upstream suite (`tests/{method}/{test-name}.io`), making it easy to identify which test is being overridden. | ||
|
||
## When to create an override | ||
|
||
You should create an override when: | ||
|
||
* A test in the upstream suite fails or must be skipped due to Hedera-specific limitations (e.g., unsupported chain id, which prevents us from replaying pre-signed transactions from chain.rlp. This is especially problematic when the test depends on a smart contract being deployed to a specific address; something we cannot replicate because we can't recreate those transactions without re-signing them using the original, unsupported chain id). | ||
* You want to define a **custom behavior** or scenario that applies specifically to Hedera's implementation. | ||
* You need to **test features not currently supported in the standard Ethereum Execution APIs**, such as Hedera-specific endpoints or modified responses. | ||
|
||
## How to create a new override | ||
|
||
1. **Identify the test** that cannot be executed or validated as-is. | ||
|
||
2. **Create a new `.io` file** under `tests-overrides/{method}/{test-name}.io`. | ||
|
||
3. Use the following format: | ||
|
||
``` | ||
>> { JSON-RPC request } | ||
<< { Expected JSON-RPC response } | ||
``` | ||
|
||
4. Make sure the test reflects realistic Hedera state. You can: | ||
|
||
* Preset required accounts and balances on your local node. | ||
* Deploy required contracts manually if the original test assumes them. | ||
* Emulate necessary conditions to simulate the expected behavior. | ||
|
||
5. If applicable, **add a comment (inside the file or a companion note)** explaining why the override exists and how it differs from the upstream test. | ||
|
||
## Test format rules | ||
|
||
* Tests **must be single round-trip** (request → response). | ||
* Subscription methods are **not currently supported**. | ||
* Follow JSON-RPC 2.0 format strictly. | ||
* Avoid relying on chain.rlp or genesis.json files. Instead, manually recreate (or "shadow") the required transactions and state setup before running the tests. | ||
|
||
## Documentation and references | ||
|
||
* [Ethereum Execution APIs test suite](https://github.com/ethereum/execution-apis/tree/main/tests) | ||
* [Hive rpc-compat simulator](https://github.com/ethereum/hive/tree/master/simulators/ethereum/rpc-compat) | ||
* [Hedera JSON-RPC Relay (internal documentation)](https://your-internal-docs-link-if-applicable) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// Performs a call to the callenv contract, which echoes the EVM transaction environment. | ||
quiet-node marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// This call uses EIP1559 transaction options. | ||
// See https://github.com/ethereum/hive/tree/master/cmd/hivechain/contracts/callenv.eas for the output structure. | ||
// | ||
// Reason for override: This test uses a smart contract that was predeployed by a transaction included in the | ||
// chain.rlp block data: https://github.com/ethereum/execution-apis/blob/main/tests/chain.rlp | ||
// | ||
// Since we do not replay those transactions before starting the tests, we need a separate test that simulates | ||
// the same scenario. This is done by pointing the `to` address to the contract already deployed on our test node. | ||
// | ||
// Note: This is the original test file, modified for our test purposes: https://github.com/ethereum/execution-apis/blob/main/tests/eth_call/call-callenv-options-eip1559.io | ||
// Only the `params[0].to` field value of the request body has been changed to point to the correct deployed contract | ||
// address. | ||
// All other fields must remain unchanged to preserve the integrity of the original test case. | ||
// | ||
// Additionally, the result field in the response was updated to reflect the actual parameters of the default | ||
// local node instance. | ||
// | ||
// The smart contract should be deployed to the address: 0x2f2a392b4d7d2c2d3134e199295818a02535ef0a | ||
// It should return the value in the format of seven 32-byte fields, where each field contains the following value: | ||
// | ||
// 1. block.number — 0x2d expected, 0xac on Hedera; reflects current block height (Ethereum vs Hedera testnet). | ||
// 2. chainid — 0x0c72dd9d5e883e expected, 0x12a on Hedera; default local chain id is 298. | ||
// 3. block.coinbase — 0x00 expected, 0x62 on Hedera; miner address is simulated and node-dependent on Hedera. | ||
// 4. block.basefee — 0x05763d64 expected, 0x07 on Hedera; Hedera uses fixed or simplified basefee for EVM calls. | ||
// 5. difficulty — 0x00 expected, random 32-byte value on Hedera; represents prevrandao (random seed). | ||
// 6. tx.origin — 0x14e4...58cb2 expected and returned; caller’s address passed in transaction 'from' field. | ||
// 7. msg.value — 0x17 (23 in decimal) expected and returned; actual value sent in the eth_call or transaction. | ||
// | ||
>> {"jsonrpc":"2.0","id":1,"method":"eth_call","params":[{"from":"0x14e46043e63d0e3cdcf2530519f4cfaf35058cb2","gas":"0xea60","input":"0x333435","maxFeePerGas":"0x44103f3","maxPriorityFeePerGas":"0xb","to":"0x2f2a392b4d7d2c2d3134e199295818a02535ef0a","value":"0x17"},"latest"]} | ||
<< {"jsonrpc":"2.0","id":1,"result":"0x00000000000000000000000000000000000000000000000000000000000000ac000000000000000000000000000000000000000000000000000000000000012a0000000000000000000000000000000000000000000000000000000000000062000000000000000000000000000000000000000000000000000000000000000075def97dfe5beb77b5d1de1b71cd5bddfdf47dd77af36d5fd9e6db7f5f36e1b7000000000000000000000000435d7d41d4f69f958bda7a8d9f549a0dd9b64c860000000000000000000000000000000000000000000000000000000000000001"} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// Performs a call to the callenv contract, which echoes the EVM transaction environment. | ||
// See https://github.com/ethereum/hive/tree/master/cmd/hivechain/contracts/callenv.eas for the output structure. | ||
// | ||
// Reason for override: This test uses a smart contract that was predeployed by a transaction included in the | ||
// chain.rlp block data: https://github.com/ethereum/execution-apis/blob/main/tests/chain.rlp | ||
// | ||
// Since we do not replay those transactions before starting the tests, we need a separate test that simulates | ||
// the same scenario. This is done by pointing the `to` address to the contract already deployed on our test node. | ||
// | ||
// Note: This is the original test file, modified for our test purposes: https://github.com/ethereum/execution-apis/blob/main/tests/eth_call/call-callenv.io | ||
// Only the `params[0].to` field value has been changed to point to the correct deployed contract address. | ||
// | ||
// All other fields in the request body must remain unchanged to preserve the integrity of the original test case. | ||
// | ||
// The smart contract should be deployed to the address: 0x2f2a392b4d7d2c2d3134e199295818a02535ef0a | ||
// It should return the value in the format of seven 32-byte fields, where each field contains the following: | ||
// | ||
// 1. block.number — 0x14 expected, 0x8c1 on Hedera; block height is higher due to real-time chain state. | ||
// 2. chainid — 0x0c72dd9d5e883e expected, 0x12a on Hedera; test used a placeholder, Hedera testnet uses chain ID 298. | ||
// 3. block.coinbase — 0x00 expected, 0x62 on Hedera; coinbase is simulated and not used for rewards on Hedera. | ||
// 4. block.basefee — 0x00 expected, 0x00 on Hedera; basefee is present but set to zero when not explicitly simulated. | ||
// 5. difficulty — 0x00 expected, Hedera returned prevrandao value (randomness source in PoS networks). | ||
// 6. tx.origin — 0x00 expected and returned; tx sent from 0x0, so origin is also zero. | ||
// 7. msg.value — 0x00 expected and returned; no value was sent with the call, as expected. | ||
// | ||
>> {"jsonrpc":"2.0","id":1,"method":"eth_call","params":[{"from":"0x0000000000000000000000000000000000000000","to":"0x2f2a392b4d7d2c2d3134e199295818a02535ef0a"},"latest"]} | ||
<< {"jsonrpc":"2.0","id":1,"result":"0x00000000000000000000000000000000000000000000000000000000000008c1000000000000000000000000000000000000000000000000000000000000012a00000000000000000000000000000000000000000000000000000000000000620000000000000000000000000000000000000000000000000000000000000000ddef36f5bedc6b4f1ef766fd735d7cd1c7da7f675ddb5d5f7ddd3479cdb4f76d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// performs a basic contract call with default settings | ||
// | ||
// Reason for override: This test uses a smart contract that was predeployed by a transaction included in the | ||
// chain.rlp block data: https://github.com/ethereum/execution-apis/blob/main/tests/chain.rlp | ||
// | ||
// Since we do not replay those transactions before starting the tests, we need a separate test that simulates | ||
// the same scenario. This is done by pointing the `to` address to the contract already deployed on our test node. | ||
// | ||
// Note: This is the original test file, modified for our test purposes: https://github.com/ethereum/execution-apis/blob/main/tests/eth_call/call-contract.io | ||
// Only the `params[0].to` field value has been changed to point to the correct deployed contract address. | ||
// All other fields must remain unchanged to preserve the integrity of the original test case. | ||
>> {"jsonrpc":"2.0","id":1,"method":"eth_call","params":[{"from":"0x0000000000000000000000000000000000000000","input":"0xff01","to":"0x2f2a392b4d7d2c2d3134e199295818a02535ef0a"},"latest"]} | ||
<< {"jsonrpc":"2.0","id":1,"result":"0xffee"} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// calls a contract that reverts with an ABI-encoded Error(string) value | ||
// | ||
// Reason for override: This test uses a smart contract that was predeployed by a transaction included in the | ||
// chain.rlp block data: https://github.com/ethereum/execution-apis/blob/main/tests/chain.rlp | ||
// | ||
// Since we do not replay those transactions before starting the tests, we need a separate test that simulates | ||
// the same scenario. This is done by pointing the `to` address to the contract already deployed on our test node. | ||
// | ||
// Note: This is the original test file, modified for our test purposes: https://github.com/ethereum/execution-apis/blob/main/tests/eth_call/call-revert-abi-error.io | ||
// Only the `params[0].to` field value has been changed to point to the correct deployed contract address. | ||
// All other fields must remain unchanged to preserve the integrity of the original test case. | ||
>> {"jsonrpc":"2.0","id":1,"method":"eth_call","params":[{"from":"0x0000000000000000000000000000000000000000","gas":"0x186a0","input":"0x01","to":"0x0ee3ab1371c93e7c0c281cc0c2107cdebc8b1930"},"latest"]} | ||
<< {"result":"0x","jsonrpc":"2.0","id":1} |
Uh oh!
There was an error while loading. Please reload this page.