Skip to content

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

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
68 changes: 40 additions & 28 deletions packages/server/tests/acceptance/conformityTests.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)])];
Copy link
Contributor

Choose a reason for hiding this comment

The 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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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.

Copy link
Contributor

Choose a reason for hiding this comment

The 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) : []);
Copy link
Contributor

Choose a reason for hiding this comment

The 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);
});
}
}
});
Expand Down
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.
// 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}
Loading
Loading