Skip to content

Commit 40c9e4f

Browse files
authored
feat: adds test coverage for HAPI transactions in conformity tests (#4675)
Signed-off-by: Simeon Nakov <[email protected]>
1 parent 75f8196 commit 40c9e4f

File tree

5 files changed

+90
-87
lines changed

5 files changed

+90
-87
lines changed

docs/openrpc.json

Lines changed: 31 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -750,10 +750,7 @@
750750
"name": "Txpool content",
751751
"schema": {
752752
"type": "object",
753-
"required": [
754-
"pending",
755-
"queued"
756-
],
753+
"required": ["pending", "queued"],
757754
"properties": {
758755
"pending": {
759756
"type": "object",
@@ -799,10 +796,7 @@
799796
"name": "Txpool contentFrom",
800797
"schema": {
801798
"type": "object",
802-
"required": [
803-
"pending",
804-
"queued"
805-
],
799+
"required": ["pending", "queued"],
806800
"properties": {
807801
"pending": {
808802
"type": "object",
@@ -1754,22 +1748,16 @@
17541748
],
17551749
"properties": {
17561750
"blockHash": {
1757-
"type": [
1758-
"string"
1759-
],
1751+
"type": ["string"],
17601752
"pattern": "^0x([A-Fa-f0-9]{64})$",
17611753
"description": "Zero hex 32 bytes."
17621754
},
17631755
"blockNumber": {
1764-
"type": [
1765-
"null"
1766-
],
1756+
"type": ["null"],
17671757
"description": "Null."
17681758
},
17691759
"transactionIndex": {
1770-
"type": [
1771-
"null"
1772-
],
1760+
"type": ["null"],
17731761
"description": "Null."
17741762
},
17751763
"from": {
@@ -1798,10 +1786,7 @@
17981786
"description": "Nonce of the transaction."
17991787
},
18001788
"to": {
1801-
"type": [
1802-
"string",
1803-
"null"
1804-
],
1789+
"type": ["string", "null"],
18051790
"pattern": "^0x[a-fA-F0-9]{40}$",
18061791
"description": "Recipient address (null for contract creation)."
18071792
},
@@ -1811,9 +1796,7 @@
18111796
"description": "Value transferred."
18121797
},
18131798
"type": {
1814-
"type": [
1815-
"string"
1816-
],
1799+
"type": ["string"],
18171800
"pattern": "^0x[0-9a-fA-F]+$",
18181801
"description": "Transaction type (EIP-2718 typed transactions)."
18191802
},
@@ -1833,34 +1816,22 @@
18331816
"description": "Signature s component."
18341817
},
18351818
"chainId": {
1836-
"type": [
1837-
"string",
1838-
"null"
1839-
],
1819+
"type": ["string", "null"],
18401820
"pattern": "^0x[0-9a-fA-F]+$",
18411821
"description": "Chain ID for EIP-155 transactions."
18421822
},
18431823
"gasPrice": {
1844-
"type": [
1845-
"string",
1846-
"null"
1847-
],
1824+
"type": ["string", "null"],
18481825
"pattern": "^0x[0-9a-fA-F]+$",
18491826
"description": "Gas price."
18501827
},
18511828
"maxFeePerGas": {
1852-
"type": [
1853-
"string",
1854-
"null"
1855-
],
1829+
"type": ["string", "null"],
18561830
"pattern": "^0x[0-9a-fA-F]+$",
18571831
"description": "For EIP-1559 transactions: maximum fee per gas."
18581832
},
18591833
"maxPriorityFeePerGas": {
1860-
"type": [
1861-
"string",
1862-
"null"
1863-
],
1834+
"type": ["string", "null"],
18641835
"pattern": "^0x[0-9a-fA-F]+$",
18651836
"description": "For EIP-1559 transactions: max priority fee per gas."
18661837
}
@@ -1960,19 +1931,14 @@
19601931
"BlockTracerType": {
19611932
"title": "Block tracer type",
19621933
"type": "string",
1963-
"enum": [
1964-
"callTracer",
1965-
"prestateTracer"
1966-
]
1934+
"enum": ["callTracer", "prestateTracer"]
19671935
},
19681936
"TransactionWithSender": {
19691937
"title": "Transaction object with sender",
19701938
"type": "object",
19711939
"allOf": [
19721940
{
1973-
"required": [
1974-
"from"
1975-
],
1941+
"required": ["from"],
19761942
"properties": {
19771943
"from": {
19781944
"title": "from",
@@ -2057,14 +2023,7 @@
20572023
"TransactionLegacyUnsigned": {
20582024
"type": "object",
20592025
"title": "Legacy transaction.",
2060-
"required": [
2061-
"type",
2062-
"nonce",
2063-
"gas",
2064-
"value",
2065-
"input",
2066-
"gasPrice"
2067-
],
2026+
"required": ["type", "nonce", "gas", "value", "input", "gasPrice"],
20682027
"properties": {
20692028
"type": {
20702029
"title": "type",
@@ -2120,12 +2079,7 @@
21202079
},
21212080
{
21222081
"title": "EIP-1559 transaction signature properties.",
2123-
"required": [
2124-
"yParity",
2125-
"r",
2126-
"s",
2127-
"v"
2128-
],
2082+
"required": ["yParity", "r", "s", "v"],
21292083
"properties": {
21302084
"yParity": {
21312085
"title": "yParity",
@@ -2182,11 +2136,7 @@
21822136
},
21832137
{
21842138
"title": "Legacy transaction signature properties.",
2185-
"required": [
2186-
"v",
2187-
"r",
2188-
"s"
2189-
],
2139+
"required": ["v", "r", "s"],
21902140
"properties": {
21912141
"v": {
21922142
"title": "v",
@@ -2227,13 +2177,7 @@
22272177
"allOf": [
22282178
{
22292179
"title": "Contextual information",
2230-
"required": [
2231-
"blockHash",
2232-
"blockNumber",
2233-
"from",
2234-
"hash",
2235-
"transactionIndex"
2236-
],
2180+
"required": ["blockHash", "blockNumber", "from", "hash", "transactionIndex"],
22372181
"properties": {
22382182
"blockHash": {
22392183
"title": "block hash",
@@ -2265,9 +2209,7 @@
22652209
"Log": {
22662210
"title": "log",
22672211
"type": "object",
2268-
"required": [
2269-
"transactionHash"
2270-
],
2212+
"required": ["transactionHash"],
22712213
"properties": {
22722214
"removed": {
22732215
"title": "removed",
@@ -2329,7 +2271,17 @@
23292271
"properties": {
23302272
"type": {
23312273
"title": "type",
2332-
"$ref": "#/components/schemas/byte"
2274+
"description": "Transaction type. Null for HAPI transactions.",
2275+
"oneOf": [
2276+
{
2277+
"title": "Transaction Type",
2278+
"$ref": "#/components/schemas/byte"
2279+
},
2280+
{
2281+
"title": "Null (HAPI transaction)",
2282+
"type": "null"
2283+
}
2284+
]
23332285
},
23342286
"transactionHash": {
23352287
"title": "transaction hash",
@@ -2531,10 +2483,7 @@
25312483
"properties": {
25322484
"type": {
25332485
"type": "string",
2534-
"enum": [
2535-
"CALL",
2536-
"CREATE"
2537-
],
2486+
"enum": ["CALL", "CREATE"],
25382487
"description": "The type of action (CALL for function calls or CREATE for contract creation)."
25392488
},
25402489
"from": {
@@ -2581,11 +2530,7 @@
25812530
"description": "Sub-calls made during this call frame."
25822531
}
25832532
},
2584-
"required": [
2585-
"from",
2586-
"gas",
2587-
"input"
2588-
]
2533+
"required": ["from", "gas", "input"]
25892534
}
25902535
}
25912536
}

packages/server/tests/acceptance/conformityTests.spec.ts

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,14 @@
77
// } from '@open-rpc/meta-schema';
88
// import { parseOpenRPCDocument } from '@open-rpc/schema-utils-js';
99
// import { expect } from 'chai';
10+
import { TransferTransaction } from '@hashgraph/sdk';
1011
import fs from 'fs';
1112
import path from 'path';
1213

1314
// import WebSocket from 'ws';
1415
import openRpcData from '../../../../docs/openrpc.json';
16+
import { Utils } from '../helpers/utils';
17+
import genesisData from './data/conformity/genesis.json';
1518
// import CallerContract from '../contracts/Caller.json';
1619
// import LogsContract from '../contracts/Logs.json';
1720
import {
@@ -22,6 +25,7 @@ import {
2225
sendAccountAddress,
2326
setCreateContractLegacyTransactionAndBlockHash,
2427
setCurrentBlockHash,
28+
setHapiTransactionHash,
2529
setLegacyTransactionAndBlockHash,
2630
setTransaction1559_2930AndBlockHash,
2731
setTransaction1559AndBlockHash,
@@ -98,7 +102,7 @@ const overwritesDirectoryPath = path.resolve(__dirname, 'data/conformity/overwri
98102
* their behavior will remain consistent with the expectations.
99103
*/
100104
const initGenesisData = async function () {
101-
for (const data of require('./data/conformity/genesis.json')) {
105+
for (const data of genesisData) {
102106
const options = { maxPriorityFeePerGas: gasPrice, maxFeePerGas: gasPrice, gasLimit: gasLimit };
103107
options['to'] = data.account ? data.account : null;
104108
if (data.balance) options['value'] = `0x${data.balance.toString(16)}`;
@@ -119,6 +123,37 @@ describe('@api-conformity', async function () {
119123
await signAndSendRawTransaction(RELAY_URL, createContractLegacyTransaction),
120124
);
121125
await initGenesisData();
126+
127+
// Execute a native HAPI transaction (token transfer via SDK) to test synthetic receipt handling
128+
const servicesNode = global.servicesNode;
129+
const hapiTestAccount = await Utils.createAliasAccount(
130+
global.mirrorNode,
131+
global.accounts[0],
132+
'1000000000', // 10 HBAR
133+
);
134+
const tokenId = await servicesNode.createToken(1000);
135+
try {
136+
await hapiTestAccount.client.associateToken(tokenId);
137+
} catch (e: any) {
138+
// Ignore if already associated
139+
if (!e.message?.includes('TOKEN_ALREADY_ASSOCIATED_TO_ACCOUNT')) {
140+
throw e;
141+
}
142+
}
143+
const hapiTransaction = new TransferTransaction()
144+
.addTokenTransfer(tokenId, servicesNode._thisAccountId(), -10)
145+
.addTokenTransfer(tokenId, hapiTestAccount.accountId, 10)
146+
.setTransactionMemo('Conformity test HAPI token transfer');
147+
const hapiResp = await hapiTransaction.execute(servicesNode.client);
148+
await hapiResp.getRecord(servicesNode.client);
149+
// Wait for mirror node to index the transaction
150+
await new Promise((r) => setTimeout(r, 3000));
151+
// Get the transaction hash from mirror node logs
152+
const logsRes = await global.mirrorNode.get(`/contracts/results/logs?limit=1`);
153+
if (logsRes.logs && logsRes.logs.length > 0 && logsRes.logs[0].contract_id === tokenId.toString()) {
154+
setHapiTransactionHash(logsRes.logs[0].transaction_hash);
155+
}
156+
122157
setCurrentBlockHash(await getLatestBlockHash(RELAY_URL));
123158
});
124159
//Reading the directories within the ethereum execution api repo
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// gets the receipt for a HAPI (native Hedera) transaction
2+
// HAPI transactions are submitted via the Hedera SDK (e.g., TransferTransaction)
3+
// and appear as synthetic transactions in the relay.
4+
//
5+
// Key differences from Ethereum transactions:
6+
// - type is null (not 0x0, 0x1, or 0x2)
7+
// - from is the zero address
8+
// - gasUsed and cumulativeGasUsed are 0x0
9+
10+
## wildcard: result.blockHash, result.blockNumber, result.transactionIndex, result.transactionHash, result.to, result.contractAddress, result.logs, result.logsBloom, result.effectiveGasPrice, result.root
11+
12+
>> {"jsonrpc":"2.0","id":1,"method":"eth_getTransactionReceipt","params":["0x0000000000000000000000000000000000000000000000000000000000000000"]}
13+
<< {"jsonrpc":"2.0","id":1,"result":{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","from":"0x0000000000000000000000000000000000000000","to":"0x0000000000000000000000000000000000000000","cumulativeGasUsed":"0x0","gasUsed":"0x0","contractAddress":"0x0000000000000000000000000000000000000000","logs":[],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","effectiveGasPrice":"0x0","root":"0x0000000000000000000000000000000000000000000000000000000000000000","status":"0x1","type":null}}
14+

packages/server/tests/acceptance/data/conformity/utils/constants.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export let transaction2930AndBlockHash: TransactionResponse;
2323
export let transaction1559AndBlockHash: TransactionResponse;
2424
export let createContractLegacyTransactionAndBlockHash: TransactionResponse;
2525
export let transaction1559_2930AndBlockHash: TransactionResponse;
26+
export let hapiTransactionHash: string;
2627

2728
export function setCurrentBlockHash(value: string) {
2829
currentBlockHash = value;
@@ -47,3 +48,7 @@ export function setTransaction1559_2930AndBlockHash(value: TransactionResponse)
4748
export function setCreateContractLegacyTransactionAndBlockHash(value: TransactionResponse) {
4849
createContractLegacyTransactionAndBlockHash = value;
4950
}
51+
52+
export function setHapiTransactionHash(value: string) {
53+
hapiTransactionHash = value;
54+
}

packages/server/tests/acceptance/data/conformity/utils/overwrites.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
currentBlockHash,
77
EMPTY_TX_HASH,
88
ETHEREUM_NETWORK_ACCOUNT_HASH,
9+
hapiTransactionHash,
910
legacyTransactionAndBlockHash,
1011
localNodeAccountPrivateKey,
1112
NONEXISTENT_TX_HASH,
@@ -117,6 +118,9 @@ function buildTransactionOverrides() {
117118
['overwrites/eth_getTransactionReceipt/get-legacy-input.io']: {
118119
'0': createContractLegacyTransactionAndBlockHash.transactionHash,
119120
},
121+
['overwrites/eth_getTransactionReceipt/get-hapi-receipt.io']: {
122+
'0': hapiTransactionHash,
123+
},
120124
['overwrites/eth_getBalance/get-balance.io']: {
121125
'0': ETHEREUM_NETWORK_ACCOUNT_HASH,
122126
'1': 'latest',

0 commit comments

Comments
 (0)