Skip to content

Commit daf1742

Browse files
committed
test: added new sendRawTransactionExtension acceptance test
Signed-off-by: Logan Nguyen <[email protected]>
1 parent c19526d commit daf1742

File tree

2 files changed

+223
-0
lines changed

2 files changed

+223
-0
lines changed

.github/workflows/acceptance.yml

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ jobs:
3636
- { name: 'Websocket Batch 3', testfilter: 'ws_batch3', test_ws_server: true }
3737
- { name: 'Cache Service', testfilter: 'cache-service' }
3838
- { name: 'Server Config', testfilter: 'serverconfig' }
39+
- { name: 'sendRawTransaction Extension', testfilter: 'sendRawTransactionExtension' }
3940
uses: ./.github/workflows/acceptance-workflow.yml
4041
with:
4142
testfilter: ${{ matrix.test.testfilter }}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
// External resources
4+
import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services';
5+
// Other imports
6+
import { numberTo0x } from '@hashgraph/json-rpc-relay/dist/formatters';
7+
import Constants from '@hashgraph/json-rpc-relay/dist/lib/constants';
8+
// Errors and constants from local resources
9+
import { predefined } from '@hashgraph/json-rpc-relay/dist/lib/errors/JsonRpcError';
10+
import { RequestDetails } from '@hashgraph/json-rpc-relay/dist/lib/types';
11+
import { expect } from 'chai';
12+
13+
import MirrorClient from '../clients/mirrorClient';
14+
import RelayClient from '../clients/relayClient';
15+
import ServicesClient from '../clients/servicesClient';
16+
// Assertions from local resources
17+
import Assertions from '../helpers/assertions';
18+
import { Utils } from '../helpers/utils';
19+
import { AliasAccount } from '../types/AliasAccount';
20+
21+
describe('@sendRawTransactionExtension Acceptance Tests', function () {
22+
this.timeout(240 * 1000); // 240 seconds
23+
24+
const accounts: AliasAccount[] = [];
25+
26+
// @ts-ignore
27+
const {
28+
mirrorNode,
29+
relay,
30+
initialBalance,
31+
}: { servicesNode: ServicesClient; mirrorNode: MirrorClient; relay: RelayClient; initialBalance: string } = global;
32+
33+
const CHAIN_ID = ConfigService.get('CHAIN_ID');
34+
const requestId = 'sendRawTransactionPrecheck';
35+
const requestDetails = new RequestDetails({ requestId: 'sendRawTransactionPrecheck', ipAddress: '0.0.0.0' });
36+
const sendRawTransaction = relay.sendRawTransaction;
37+
38+
// describe('@sendRawTransactionPrecheck Acceptance Tests', function () {
39+
this.timeout(240 * 1000); // 240 seconds
40+
const defaultGasLimit = numberTo0x(3_000_000);
41+
42+
this.beforeAll(async () => {
43+
const initialAccount: AliasAccount = global.accounts[0];
44+
const neededAccounts: number = 2;
45+
accounts.push(
46+
...(await Utils.createMultipleAliasAccounts(
47+
mirrorNode,
48+
initialAccount,
49+
neededAccounts,
50+
initialBalance,
51+
requestDetails,
52+
)),
53+
);
54+
global.accounts.push(...accounts);
55+
});
56+
57+
describe('Prechecks', function () {
58+
describe('transactionSize', function () {
59+
it('@release should execute "eth_sendRawTransaction" with regular transaction size within the limit', async function () {
60+
const gasPrice = await relay.gasPrice(requestId);
61+
const transaction = {
62+
type: 2,
63+
chainId: Number(CHAIN_ID),
64+
nonce: await relay.getAccountNonce(accounts[1].address, requestId),
65+
maxPriorityFeePerGas: gasPrice,
66+
maxFeePerGas: gasPrice,
67+
gasLimit: defaultGasLimit,
68+
to: accounts[0].address,
69+
};
70+
71+
const signedTx = await accounts[1].wallet.signTransaction(transaction);
72+
expect(signedTx.length).to.be.lt(Constants.SEND_RAW_TRANSACTION_SIZE_LIMIT);
73+
74+
const transactionHash = await relay.sendRawTransaction(signedTx, requestId);
75+
await relay.pollForValidTransactionReceipt(transactionHash);
76+
77+
const info = await mirrorNode.get(`/contracts/results/${transactionHash}`, requestId);
78+
expect(info).to.exist;
79+
expect(info.result).to.equal('SUCCESS');
80+
});
81+
82+
it('@release should fail "eth_sendRawTransaction" when transaction size exceeds the limit', async function () {
83+
const gasPrice = await relay.gasPrice(requestId);
84+
const transaction = {
85+
type: 2,
86+
chainId: Number(CHAIN_ID),
87+
nonce: await relay.getAccountNonce(accounts[1].address, requestId),
88+
maxPriorityFeePerGas: gasPrice,
89+
maxFeePerGas: gasPrice,
90+
gasLimit: defaultGasLimit,
91+
to: accounts[0].address,
92+
data: '0x' + '00'.repeat(Constants.SEND_RAW_TRANSACTION_SIZE_LIMIT + 1024), // exceeds the limit by 1KB
93+
};
94+
95+
const signedTx = await accounts[1].wallet.signTransaction(transaction);
96+
const totalRawTransactionSizeInBytes = signedTx.replace('0x', '').length / 2;
97+
const error = predefined.TRANSACTION_SIZE_LIMIT_EXCEEDED(
98+
totalRawTransactionSizeInBytes,
99+
Constants.SEND_RAW_TRANSACTION_SIZE_LIMIT,
100+
);
101+
102+
await Assertions.assertPredefinedRpcError(error, sendRawTransaction, false, relay, [signedTx, requestDetails]);
103+
});
104+
});
105+
106+
describe('callDataSize', function () {
107+
it('@release should execute "eth_sendRawTransaction" with regular transaction size within the limit', async function () {
108+
const gasPrice = await relay.gasPrice(requestId);
109+
const transaction = {
110+
type: 2,
111+
chainId: Number(CHAIN_ID),
112+
nonce: await relay.getAccountNonce(accounts[1].address, requestId),
113+
maxPriorityFeePerGas: gasPrice,
114+
maxFeePerGas: gasPrice,
115+
gasLimit: defaultGasLimit,
116+
to: accounts[0].address,
117+
};
118+
119+
const signedTx = await accounts[1].wallet.signTransaction(transaction);
120+
expect(signedTx.length).to.be.lt(Constants.CALL_DATA_SIZE_LIMIT);
121+
122+
const transactionHash = await relay.sendRawTransaction(signedTx, requestId);
123+
await relay.pollForValidTransactionReceipt(transactionHash);
124+
125+
const info = await mirrorNode.get(`/contracts/results/${transactionHash}`, requestId);
126+
expect(info).to.exist;
127+
expect(info.result).to.equal('SUCCESS');
128+
});
129+
130+
it('@release should fail "eth_sendRawTransaction" when transaction size exceeds the limit', async function () {
131+
const gasPrice = await relay.gasPrice(requestId);
132+
const transaction = {
133+
type: 2,
134+
chainId: Number(CHAIN_ID),
135+
nonce: await relay.getAccountNonce(accounts[1].address, requestId),
136+
maxPriorityFeePerGas: gasPrice,
137+
maxFeePerGas: gasPrice,
138+
gasLimit: defaultGasLimit,
139+
to: accounts[0].address,
140+
data: '0x' + '00'.repeat(Constants.CALL_DATA_SIZE_LIMIT + 1024), // exceeds the limit by 1KB
141+
};
142+
143+
const signedTx = await accounts[1].wallet.signTransaction(transaction);
144+
const totalRawTransactionSizeInBytes = transaction.data.replace('0x', '').length / 2;
145+
const error = predefined.CALL_DATA_SIZE_LIMIT_EXCEEDED(
146+
totalRawTransactionSizeInBytes,
147+
Constants.CALL_DATA_SIZE_LIMIT,
148+
);
149+
150+
await Assertions.assertPredefinedRpcError(error, sendRawTransaction, false, relay, [signedTx, requestDetails]);
151+
});
152+
});
153+
154+
describe('contractCodeSize', function () {
155+
it('@release should execute "eth_sendRawTransaction" and deploy a contract with code size within the limit', async function () {
156+
const gasPrice = await relay.gasPrice(requestId);
157+
const transaction = {
158+
type: 2,
159+
chainId: Number(CHAIN_ID),
160+
nonce: await relay.getAccountNonce(accounts[1].address, requestId),
161+
maxPriorityFeePerGas: gasPrice,
162+
maxFeePerGas: gasPrice,
163+
gasLimit: defaultGasLimit,
164+
data: '0x' + '00'.repeat(Constants.CONTRACT_CODE_SIZE_LIMIT), // Within the CONTRACT_CODE_SIZE_LIMIT limit
165+
};
166+
167+
const signedTx = await accounts[1].wallet.signTransaction(transaction);
168+
const transactionHash = await relay.sendRawTransaction(signedTx, requestId);
169+
await relay.pollForValidTransactionReceipt(transactionHash);
170+
171+
const info = await mirrorNode.get(`/contracts/results/${transactionHash}`, requestId);
172+
expect(info).to.have.property('contract_id');
173+
expect(info.contract_id).to.not.be.null;
174+
expect(info).to.have.property('created_contract_ids');
175+
expect(info.created_contract_ids.length).to.be.equal(1);
176+
});
177+
178+
it('@release should fail "eth_sendRawTransaction" for contract with code size exceeding the limit', async function () {
179+
const gasPrice = await relay.gasPrice(requestId);
180+
// Create a transaction with contract code size exceeding CONTRACT_CODE_SIZE_LIMIT
181+
const transaction = {
182+
type: 2,
183+
chainId: Number(CHAIN_ID),
184+
nonce: await relay.getAccountNonce(accounts[1].address, requestId),
185+
maxPriorityFeePerGas: gasPrice,
186+
maxFeePerGas: gasPrice,
187+
gasLimit: defaultGasLimit,
188+
data: '0x' + '00'.repeat(Constants.CONTRACT_CODE_SIZE_LIMIT + 1),
189+
};
190+
191+
const signedTx = await accounts[1].wallet.signTransaction(transaction);
192+
const contractCodeSize = (transaction.data.length - 2) / 2;
193+
const error = predefined.CONTRACT_CODE_SIZE_LIMIT_EXCEEDED(
194+
contractCodeSize,
195+
Constants.CONTRACT_CODE_SIZE_LIMIT,
196+
);
197+
198+
await Assertions.assertPredefinedRpcError(error, sendRawTransaction, false, relay, [signedTx, requestDetails]);
199+
});
200+
201+
it('@release should pass precheck and execute "eth_sendRawTransaction" for a regular transaction i.e. non contract deployment transaction with data exceeding the limit', async function () {
202+
const gasPrice = await relay.gasPrice(requestId);
203+
// Create a transaction with large data but sent to an existing address (not contract creation)
204+
const transaction = {
205+
type: 2,
206+
chainId: Number(CHAIN_ID),
207+
nonce: await relay.getAccountNonce(accounts[1].address, requestId),
208+
maxPriorityFeePerGas: gasPrice,
209+
maxFeePerGas: gasPrice,
210+
gasLimit: defaultGasLimit,
211+
to: accounts[0].address, // Sending to existing address, so code size check doesn't apply
212+
data: '0x' + '00'.repeat(Constants.CONTRACT_CODE_SIZE_LIMIT + 1024), // exceeds the limit by 1KB
213+
};
214+
215+
const signedTx = await accounts[1].wallet.signTransaction(transaction);
216+
const transactionHash = await relay.sendRawTransaction(signedTx, requestId);
217+
const info = await mirrorNode.get(`/contracts/results/${transactionHash}`, requestId);
218+
expect(info).to.exist;
219+
});
220+
});
221+
});
222+
});

0 commit comments

Comments
 (0)