Skip to content

Commit 69ffaca

Browse files
authored
Optimize acceptance test CI (#804)
* chore: split rpc.spec into smaller chunks Signed-off-by: Ivo Yankov <[email protected]> * fix: reset local-node files state after tests Signed-off-by: Ivo Yankov <[email protected]> * nit: resolve comment Signed-off-by: Ivo Yankov <[email protected]> * fix: error from merging Signed-off-by: Ivo Yankov <[email protected]> * chore: tweak test account balances Signed-off-by: Ivo Yankov <[email protected]> * chore: resolve conflicts Signed-off-by: Ivo Yankov <[email protected]> * chore: rename to batch Signed-off-by: Ivo Yankov <[email protected]> * nit: rename to batch Signed-off-by: Ivo Yankov <[email protected]> * chore: resolve conflicts Signed-off-by: Ivo Yankov <[email protected]> * chore: remove duplicated tests Signed-off-by: Ivo Yankov <[email protected]> --------- Signed-off-by: Ivo Yankov <[email protected]>
1 parent 51682d2 commit 69ffaca

File tree

7 files changed

+2080
-1900
lines changed

7 files changed

+2080
-1900
lines changed

.github/workflows/acceptance.yml

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,23 @@ on:
88
tags: [v*]
99

1010
jobs:
11-
api:
12-
name: API
11+
api_batch_1:
12+
name: API Batch 1
1313
uses: ./.github/workflows/acceptance-workflow.yml
1414
with:
15-
testfilter: api
15+
testfilter: api_batch1
16+
17+
api_batch_2:
18+
name: API Batch 2
19+
uses: ./.github/workflows/acceptance-workflow.yml
20+
with:
21+
testfilter: api_batch2
22+
23+
api_batch3:
24+
name: API Batch 3
25+
uses: ./.github/workflows/acceptance-workflow.yml
26+
with:
27+
testfilter: api_batch3
1628

1729
erc20:
1830
name: ERC20

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121
},
2222
"scripts": {
2323
"acceptancetest": "ts-mocha packages/server/tests/acceptance/index.spec.ts --exit",
24-
"acceptancetest:api": "ts-mocha packages/server/tests/acceptance/index.spec.ts -g '@api' --exit",
24+
"acceptancetest:api_batch1": "ts-mocha packages/server/tests/acceptance/index.spec.ts -g '@api-batch-1' --exit",
25+
"acceptancetest:api_batch2": "ts-mocha packages/server/tests/acceptance/index.spec.ts -g '@api-batch-2' --exit",
26+
"acceptancetest:api_batch3": "ts-mocha packages/server/tests/acceptance/index.spec.ts -g '@api-batch-3' --exit",
2527
"acceptancetest:erc20": "ts-mocha packages/server/tests/acceptance/index.spec.ts -g '@erc20' --exit",
2628
"acceptancetest:ratelimiter": "ts-mocha packages/server/tests/acceptance/index.spec.ts -g '@ratelimiter' --exit",
2729
"acceptancetest:tokencreate": "ts-mocha packages/server/tests/acceptance/index.spec.ts -g '@tokencreate' --exit",

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

Lines changed: 0 additions & 1896 deletions
This file was deleted.

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

Lines changed: 902 additions & 0 deletions
Large diffs are not rendered by default.

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

Lines changed: 897 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
/*-
2+
*
3+
* Hedera JSON RPC Relay
4+
*
5+
* Copyright (C) 2022 Hedera Hashgraph, LLC
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*
19+
*/
20+
21+
// external resources
22+
import {expect} from 'chai';
23+
import {ethers} from 'ethers';
24+
import {AliasAccount} from '../clients/servicesClient';
25+
import {Utils} from '../helpers/utils';
26+
27+
// local resources
28+
import reverterContractJson from '../contracts/Reverter.json';
29+
import {EthImpl} from '@hashgraph/json-rpc-relay/src/lib/eth';
30+
31+
describe('@api-batch-3 RPC Server Acceptance Tests', function () {
32+
this.timeout(240 * 1000); // 240 seconds
33+
34+
const accounts: AliasAccount[] = [];
35+
36+
// @ts-ignore
37+
const {servicesNode, mirrorNode, relay, logger} = global;
38+
39+
40+
const CHAIN_ID = process.env.CHAIN_ID || 0;
41+
const ONE_TINYBAR = ethers.utils.parseUnits('1', 10).toHexString();
42+
43+
44+
let reverterContract, reverterEvmAddress, requestId;
45+
const PURE_METHOD_CALL_DATA = '0xb2e0100c';
46+
const VIEW_METHOD_CALL_DATA = '0x90e9b875';
47+
const PAYABLE_METHOD_CALL_DATA = '0xd0efd7ef';
48+
const PURE_METHOD_ERROR_DATA = '0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010526576657274526561736f6e5075726500000000000000000000000000000000';
49+
const VIEW_METHOD_ERROR_DATA = '0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010526576657274526561736f6e5669657700000000000000000000000000000000';
50+
const PAYABLE_METHOD_ERROR_DATA = '0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000013526576657274526561736f6e50617961626c6500000000000000000000000000';
51+
const PURE_METHOD_ERROR_MESSAGE = 'execution reverted: RevertReasonPure';
52+
const VIEW_METHOD_ERROR_MESSAGE = 'execution reverted: RevertReasonView';
53+
54+
beforeEach(async () => {
55+
requestId = Utils.generateRequestId();
56+
});
57+
58+
before(async () => {
59+
60+
requestId = Utils.generateRequestId();
61+
62+
accounts[0] = await servicesNode.createAliasAccount(30, null, requestId);
63+
64+
reverterContract = await servicesNode.deployContract(reverterContractJson);
65+
// Wait for creation to propagate
66+
await mirrorNode.get(`/contracts/${reverterContract.contractId}`, requestId);
67+
reverterEvmAddress = `0x${reverterContract.contractId.toSolidityAddress()}`;
68+
});
69+
70+
describe('Contract call reverts', async () => {
71+
it('Returns revert message for pure methods', async () => {
72+
const callData = {
73+
from: '0x' + accounts[0].address,
74+
to: reverterEvmAddress,
75+
gas: EthImpl.numberTo0x(30000),
76+
data: PURE_METHOD_CALL_DATA
77+
};
78+
79+
await relay.callFailing('eth_call', [callData, 'latest'], {
80+
code: -32008,
81+
message: PURE_METHOD_ERROR_MESSAGE,
82+
data: PURE_METHOD_ERROR_DATA
83+
}, requestId);
84+
});
85+
86+
it('Returns revert message for view methods', async () => {
87+
const callData = {
88+
from: '0x' + accounts[0].address,
89+
to: reverterEvmAddress,
90+
gas: EthImpl.numberTo0x(30000),
91+
data: VIEW_METHOD_CALL_DATA
92+
};
93+
94+
await relay.callFailing('eth_call', [callData, 'latest'], {
95+
code: -32008,
96+
message: VIEW_METHOD_ERROR_MESSAGE,
97+
data: VIEW_METHOD_ERROR_DATA
98+
}, requestId);
99+
});
100+
101+
it('Returns revert reason in receipt for payable methods', async () => {
102+
const transaction = {
103+
value: ONE_TINYBAR,
104+
gasLimit: EthImpl.numberTo0x(30000),
105+
chainId: Number(CHAIN_ID),
106+
to: reverterEvmAddress,
107+
nonce: await relay.getAccountNonce('0x' + accounts[0].address, requestId),
108+
gasPrice: await relay.gasPrice(requestId),
109+
data: PAYABLE_METHOD_CALL_DATA
110+
};
111+
const signedTx = await accounts[0].wallet.signTransaction(transaction);
112+
const transactionHash = await relay.call('eth_sendRawTransaction', [signedTx], requestId);
113+
114+
// Wait until receipt is available in mirror node
115+
await mirrorNode.get(`/contracts/results/${transactionHash}`, requestId);
116+
117+
const receipt = await relay.call('eth_getTransactionReceipt', [transactionHash], requestId);
118+
expect(receipt?.revertReason).to.exist;
119+
expect(receipt.revertReason).to.eq(PAYABLE_METHOD_ERROR_DATA);
120+
});
121+
122+
describe('eth_getTransactionByHash for reverted payable contract calls', async function () {
123+
const payableMethodsData = [
124+
{
125+
data: '0xfe0a3dd7',
126+
method: 'revertWithNothing',
127+
message: '',
128+
errorData: '0x'
129+
},
130+
{
131+
data: '0x0323d234',
132+
method: 'revertWithString',
133+
message: 'Some revert message',
134+
errorData: '0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000013536f6d6520726576657274206d65737361676500000000000000000000000000'
135+
},
136+
{
137+
data: '0x46fc4bb1',
138+
method: 'revertWithCustomError',
139+
message: '',
140+
errorData: '0x0bd3d39c'
141+
},
142+
{
143+
data: '0x33fe3fbd',
144+
method: 'revertWithPanic',
145+
message: '',
146+
errorData: '0x4e487b710000000000000000000000000000000000000000000000000000000000000012'
147+
}
148+
];
149+
const hashes: any = [];
150+
151+
beforeEach(async () => {
152+
requestId = Utils.generateRequestId();
153+
});
154+
155+
before(async function () {
156+
for (let i = 0; i < payableMethodsData.length; i++) {
157+
const transaction = {
158+
// value: ONE_TINYBAR,
159+
gasLimit: EthImpl.numberTo0x(30000),
160+
chainId: Number(CHAIN_ID),
161+
to: reverterEvmAddress,
162+
nonce: await relay.getAccountNonce('0x' + accounts[0].address, requestId),
163+
gasPrice: await relay.gasPrice(requestId),
164+
data: payableMethodsData[i].data
165+
};
166+
const signedTx = await accounts[0].wallet.signTransaction(transaction);
167+
const hash = await relay.call('eth_sendRawTransaction', [signedTx], requestId);
168+
hashes.push(hash);
169+
170+
// Wait until receipt is available in mirror node
171+
await mirrorNode.get(`/contracts/results/${hash}`, requestId);
172+
}
173+
});
174+
175+
for (let i = 0; i < payableMethodsData.length; i++) {
176+
it(`Payable method ${payableMethodsData[i].method} returns tx object`, async function () {
177+
const tx = await relay.call('eth_getTransactionByHash', [hashes[i]], requestId);
178+
expect(tx).to.exist;
179+
expect(tx.hash).to.exist;
180+
expect(tx.hash).to.eq(hashes[i]);
181+
});
182+
}
183+
184+
describe('DEV_MODE = true', async function () {
185+
before(async () => {
186+
process.env.DEV_MODE = 'true';
187+
});
188+
189+
after(async () => {
190+
process.env.DEV_MODE = 'false';
191+
});
192+
193+
for (let i = 0; i < payableMethodsData.length; i++) {
194+
it(`Payable method ${payableMethodsData[i].method} throws an error`, async function () {
195+
await relay.callFailing('eth_getTransactionByHash', [hashes[i]], {
196+
code: -32008,
197+
message: payableMethodsData[i].message,
198+
data: payableMethodsData[i].errorData
199+
}, requestId);
200+
});
201+
}
202+
});
203+
});
204+
205+
describe('eth_call for reverted pure contract calls', async function () {
206+
beforeEach(async () => {
207+
requestId = Utils.generateRequestId();
208+
});
209+
210+
const pureMethodsData = [
211+
{
212+
data: '0x2dac842f',
213+
method: 'revertWithNothingPure',
214+
message: '',
215+
errorData: '0x'
216+
},
217+
{
218+
data: '0x8b153371',
219+
method: 'revertWithStringPure',
220+
message: 'Some revert message',
221+
errorData: '0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000013536f6d6520726576657274206d65737361676500000000000000000000000000'
222+
},
223+
{
224+
data: '0x35314694',
225+
method: 'revertWithCustomErrorPure',
226+
message: '',
227+
errorData: '0x0bd3d39c'
228+
},
229+
{
230+
data: '0x83889056',
231+
method: 'revertWithPanicPure',
232+
message: '',
233+
errorData: '0x4e487b710000000000000000000000000000000000000000000000000000000000000012'
234+
}
235+
];
236+
237+
for (let i = 0; i < pureMethodsData.length; i++) {
238+
it(`Pure method ${pureMethodsData[i].method} returns tx receipt`, async function () {
239+
const callData = {
240+
from: '0x' + accounts[0].address,
241+
to: reverterEvmAddress,
242+
gas: EthImpl.numberTo0x(30000),
243+
data: pureMethodsData[i].data
244+
};
245+
246+
await relay.callFailing('eth_call', [callData, 'latest'], {
247+
code: -32008,
248+
message: pureMethodsData[i].message,
249+
data: pureMethodsData[i].errorData
250+
}, requestId);
251+
});
252+
}
253+
});
254+
});
255+
});

packages/server/tests/clients/servicesClient.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import {
4141
TransactionId,
4242
AccountAllowanceApproveTransaction,
4343
AccountBalance,
44+
FileContentsQuery
4445
} from '@hashgraph/sdk';
4546
import { Logger } from 'pino';
4647
import { ethers } from 'ethers';
@@ -286,6 +287,13 @@ export default class ServicesClient {
286287
return accountBalance.hbars;
287288
}
288289

290+
async getFileContent(fileId: string): Promise<any> {
291+
const query = new FileContentsQuery()
292+
.setFileId(fileId);
293+
294+
return await query.execute(this.client);
295+
}
296+
289297
async updateFileContent(fileId: string, content: string, requestId?: string): Promise<void> {
290298
const requestIdPrefix = Utils.formatRequestIdMessage(requestId);
291299
const response = await new FileUpdateTransaction()

0 commit comments

Comments
 (0)