Skip to content

Commit 3c16200

Browse files
authored
feat: implemented eth_newFilter to WS server (#2553)
* feat: implemented eth_newFilter to WS server Signed-off-by: Logan Nguyen <[email protected]> * test: added acceptance tests for eth_newFilter Signed-off-by: Logan Nguyen <[email protected]> * fix: updated validateBlockRangeAndAddTimestampToParams for eth_newFilter Signed-off-by: Logan Nguyen <[email protected]> --------- Signed-off-by: Logan Nguyen <[email protected]>
1 parent 084547f commit 3c16200

File tree

6 files changed

+129
-2
lines changed

6 files changed

+129
-2
lines changed

packages/relay/src/lib/services/ethService/ethCommonService/ICommonService.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export interface ICommonService {
2727
fromBlock: string,
2828
toBlock: string,
2929
requestIdPrefix?: string,
30+
address?: string | string[] | null,
3031
): Promise<boolean>;
3132

3233
getHistoricalBlockResponse(

packages/relay/src/lib/services/ethService/ethFilterService/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,9 @@ export class FilterService implements IFilterService {
127127
try {
128128
FilterService.requireFiltersEnabled();
129129

130-
if (!(await this.common.validateBlockRangeAndAddTimestampToParams({}, fromBlock, toBlock, requestIdPrefix))) {
130+
if (
131+
!(await this.common.validateBlockRangeAndAddTimestampToParams({}, fromBlock, toBlock, requestIdPrefix, address))
132+
) {
131133
throw predefined.INVALID_BLOCK_RANGE;
132134
}
133135

packages/ws-server/src/controllers/index.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,15 @@ const handleSendingRequestsToRelay = async ({
6464

6565
// Call the relay method with the resolved parameters.
6666
// Method will be validated by "verifySupportedMethod" before reaching this point.
67-
const txRes = await relay[service]()[methodName](...resolvedParams, requestIdPrefix);
67+
let txRes: any;
68+
if (method === WS_CONSTANTS.METHODS.ETH_NEWFILTER) {
69+
txRes = await relay
70+
.eth()
71+
.filterService()
72+
[methodName](...resolvedParams, requestIdPrefix);
73+
} else {
74+
txRes = await relay[service]()[methodName](...resolvedParams, requestIdPrefix);
75+
}
6876

6977
if (!txRes) {
7078
logger.trace(

packages/ws-server/src/utils/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ export const WS_CONSTANTS = {
9595
ETH_GETCODE: 'eth_getCode',
9696
ETH_GASPRICE: 'eth_gasPrice',
9797
ETH_SUBSCRIBE: 'eth_subscribe',
98+
ETH_NEWFILTER: 'eth_newFilter',
9899
ETH_GETBALANCE: 'eth_getBalance',
99100
ETH_UNSUBSCRIBE: 'eth_unsubscribe',
100101
ETH_BLOCKNUMBER: 'eth_blockNumber',

packages/ws-server/src/utils/utils.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ export const resolveParams = (method: string, params: any): any[] => {
130130
switch (method) {
131131
case WS_CONSTANTS.METHODS.ETH_GETLOGS:
132132
return [params[0].blockHash, params[0].fromBlock, params[0].toBlock, params[0].address, params[0].topics];
133+
case WS_CONSTANTS.METHODS.ETH_NEWFILTER:
134+
return [params[0].fromBlock, params[0].toBlock, params[0].address, params[0].topics];
133135
default:
134136
return params;
135137
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*-
2+
*
3+
* Hedera JSON RPC Relay
4+
*
5+
* Copyright (C) 2024 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+
import { expect } from 'chai';
22+
import { ethers, WebSocketProvider } from 'ethers';
23+
import { WsTestConstant, WsTestHelper } from '../helper';
24+
import { Utils } from '@hashgraph/json-rpc-server/tests/helpers/utils';
25+
26+
describe('@release @web-socket-batch-2 eth_newFilter', async function () {
27+
let wsFilterObj: any, ethersWsProvider: WebSocketProvider;
28+
const METHOD_NAME = 'eth_newFilter';
29+
const INVALID_PARAMS = [
30+
[],
31+
[
32+
{
33+
address: WsTestConstant.FAKE_TX_HASH,
34+
fromBlock: '0xhedera',
35+
toBlock: 'latest',
36+
},
37+
],
38+
[
39+
{
40+
address: WsTestConstant.FAKE_TX_HASH,
41+
fromBlock: 'latest',
42+
toBlock: '0xhedera',
43+
},
44+
],
45+
];
46+
47+
const SIMPLE_CONTRACT_BYTECODE =
48+
'0x6080604052348015600f57600080fd5b507f4e7df42af9a017b7c655a28ef10cbc8f05b2b088f087ee02416cfa1a96ac3be26007604051603e91906091565b60405180910390a160aa565b6000819050919050565b6000819050919050565b6000819050919050565b6000607d6079607584604a565b605e565b6054565b9050919050565b608b816068565b82525050565b600060208201905060a460008301846084565b92915050565b603f8060b76000396000f3fe6080604052600080fdfea264697066735822122084db7fe76bde5c9c041d61bb40294c56dc6d339bdbc8e0cd285fc4008ccefc2c64736f6c63430008180033';
49+
50+
before(async () => {
51+
// deploy contract
52+
const contract = await Utils.deployContract([], SIMPLE_CONTRACT_BYTECODE, global.accounts[0].wallet);
53+
54+
wsFilterObj = {
55+
address: [contract.target],
56+
fromBlock: '0x0',
57+
toBlock: 'latest',
58+
};
59+
});
60+
61+
beforeEach(async () => {
62+
ethersWsProvider = new ethers.WebSocketProvider(WsTestConstant.WS_RELAY_URL);
63+
});
64+
65+
afterEach(async () => {
66+
if (ethersWsProvider) await ethersWsProvider.destroy();
67+
});
68+
69+
after(async () => {
70+
// expect all the connections to be closed after all
71+
expect(global.socketServer._connections).to.eq(0);
72+
});
73+
74+
describe(WsTestConstant.STANDARD_WEB_SOCKET, () => {
75+
for (const params of INVALID_PARAMS) {
76+
it(`Should fail eth_newFilter on Standard Web Socket and throw predefined.INVALID_PARAMETERS if the request's params variable is invalid. params=[${JSON.stringify(
77+
params,
78+
)}]`, async () => {
79+
await WsTestHelper.assertFailInvalidParamsStandardWebSocket(METHOD_NAME, params);
80+
});
81+
}
82+
83+
it(`Should execute eth_newFilter on Standard Web Socket and handle valid requests correctly`, async () => {
84+
const response = await WsTestHelper.sendRequestToStandardWebSocket(METHOD_NAME, [wsFilterObj]);
85+
WsTestHelper.assertJsonRpcObject(response);
86+
const filterId = response.result;
87+
88+
await new Promise((r) => setTimeout(r, 90000));
89+
90+
expect(filterId).to.exist;
91+
expect(filterId.startsWith('0x')).to.be.true;
92+
expect(filterId.slice(2).length).to.eq(32); // 16 bytes
93+
});
94+
});
95+
96+
describe(WsTestConstant.ETHERS_WS_PROVIDER, () => {
97+
for (const params of INVALID_PARAMS) {
98+
it(`Should fail eth_newFilter on Ethers Web Socket Provider and throw predefined.INVALID_PARAMETERS if the request's params variable is invalid. params=[${JSON.stringify(
99+
params,
100+
)}]`, async () => {
101+
await WsTestHelper.assertFailInvalidParamsEthersWsProvider(ethersWsProvider, METHOD_NAME, params);
102+
});
103+
}
104+
105+
it(`Should execute eth_newFilter on Ethers Web Socket Provider and handle valid requests correctly`, async () => {
106+
const filterId = await ethersWsProvider.send(METHOD_NAME, [wsFilterObj]);
107+
108+
expect(filterId).to.exist;
109+
expect(filterId.startsWith('0x')).to.be.true;
110+
expect(filterId.slice(2).length).to.eq(32); // 16 bytes
111+
});
112+
});
113+
});

0 commit comments

Comments
 (0)