Skip to content

Commit d685c26

Browse files
authored
chore: cherry pick 2521 (#2525)
feat: added constructValidLogSubscriptionFilter() to discard any unexpected parameters for logs subcription filter object (#2521) * fix: removed param validator for eth_subscribe:logs * fix: added unexpectedParams validator back * feat: added constructValidLogSubscriptionFilter() to strip off unexpected params * fix: fixed multiple address check --------- Signed-off-by: Logan Nguyen <[email protected]>
1 parent 3677110 commit d685c26

File tree

4 files changed

+108
-5
lines changed

4 files changed

+108
-5
lines changed

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

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@
1818
*
1919
*/
2020

21-
import { getMultipleAddressesEnabled } from '../utils/utils';
2221
import { predefined, Relay } from '@hashgraph/json-rpc-relay';
2322
import { validateSubscribeEthLogsParams } from '../utils/validators';
2423
import constants from '@hashgraph/json-rpc-relay/dist/lib/constants';
25-
import jsonResp from '@hashgraph/json-rpc-server/dist/koaJsonRpc/lib/RpcResponse';
2624
import { MirrorNodeClient } from '@hashgraph/json-rpc-relay/dist/lib/clients';
25+
import jsonResp from '@hashgraph/json-rpc-server/dist/koaJsonRpc/lib/RpcResponse';
26+
import { constructValidLogSubscriptionFilter, getMultipleAddressesEnabled } from '../utils/utils';
2727

2828
/**
2929
* Subscribes to new block headers (newHeads) events and returns the response and subscription ID.
@@ -115,15 +115,21 @@ const handleEthSubscribeLogs = async (
115115
relay: Relay,
116116
mirrorNodeClient: MirrorNodeClient,
117117
): Promise<{ response: any; subscriptionId: any }> => {
118-
await validateSubscribeEthLogsParams(filters, requestIdPrefix, mirrorNodeClient);
119-
if (!getMultipleAddressesEnabled() && Array.isArray(filters.address) && filters.address.length > 1) {
118+
const validFiltersObject = constructValidLogSubscriptionFilter(filters);
119+
120+
await validateSubscribeEthLogsParams(validFiltersObject, requestIdPrefix, mirrorNodeClient);
121+
if (
122+
!getMultipleAddressesEnabled() &&
123+
Array.isArray(validFiltersObject['address']) &&
124+
validFiltersObject['address'].length > 1
125+
) {
120126
response = jsonResp(
121127
request.id,
122128
predefined.INVALID_PARAMETER('filters.address', 'Only one contract address is allowed'),
123129
undefined,
124130
);
125131
} else {
126-
subscriptionId = relay.subs()?.subscribe(ctx.websocket, event, filters);
132+
subscriptionId = relay.subs()?.subscribe(ctx.websocket, event, validFiltersObject);
127133
}
128134
return { response, subscriptionId };
129135
};

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,3 +195,14 @@ const hasInvalidReqestId = (
195195

196196
return !hasId;
197197
};
198+
199+
/**
200+
* Constructs a valid log subscription filter from the provided filters, retaining only the 'address' and 'topics' fields while discarding any unexpected parameters.
201+
* @param {any} filters - The filters to construct the subscription filter from.
202+
* @returns {Object} A valid log subscription filter object.
203+
*/
204+
export const constructValidLogSubscriptionFilter = (filters: any): object => {
205+
return Object.fromEntries(
206+
Object.entries(filters).filter(([key, value]) => value !== undefined && ['address', 'topics'].includes(key)),
207+
);
208+
};

packages/ws-server/tests/acceptance/subscribe.spec.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import WebSocket from 'ws';
2323
import { ethers } from 'ethers';
2424
import chai, { expect } from 'chai';
25+
import { WsTestHelper } from '../helper';
2526
import { solidity } from 'ethereum-waffle';
2627
import { Utils } from '@hashgraph/json-rpc-server/tests/helpers/utils';
2728
import Constants from '@hashgraph/json-rpc-server/tests/helpers/constants';
@@ -889,6 +890,21 @@ describe('@release @web-socket-batch-3 eth_subscribe', async function () {
889890
['logs', { address: logContractSigner.target, topics: ['0x000'] }],
890891
]);
891892
});
893+
894+
it('Should ignore invalid params in filter object and still successfully call eth_subscribe Logs ', async function () {
895+
const randomTopic = '0x1d29d0f04057864b829c60f025fdba344f1623eb30b90820f5a6c39ffbd1c512';
896+
897+
// @notice: the only two valid params a filter object can have is `address` and `topics`.
898+
// However, WS server should ignore any invalid params passed in the request.
899+
const response = await WsTestHelper.sendRequestToStandardWebSocket(
900+
'eth_subscribe',
901+
['logs', { address: logContractSigner.target, topics: [randomTopic], fromBlock: '0x0', toBlock: 'latest' }],
902+
1000,
903+
);
904+
WsTestHelper.assertJsonRpcObject(response);
905+
expect(response.result).to.exist;
906+
expect(ethers.isHexString(response.result)).to.be.true;
907+
});
892908
});
893909

894910
// skip this test if using a remote relay since updating the env vars would not affect it
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
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 { constructValidLogSubscriptionFilter } from '../../src/utils/utils';
23+
24+
describe('Utilities unit tests', async function () {
25+
describe('constructValidLogSubscriptionFilter tests', () => {
26+
it('Should ignore all the unexpected params and return a new filter object with valid params (address, topics)', () => {
27+
const originalFilter = {
28+
address: '0x23f5e49569A835d7bf9AefD30e4f60CdD570f225',
29+
topics: ['0x1d29d0f04057864b829c60f025fdba344f1623eb30b90820f5a6c39ffbd1c512'],
30+
fromBlock: '0x0',
31+
toBlock: 'latest',
32+
hedera: '0xhbar',
33+
};
34+
const originalFilterKeys = Object.keys(originalFilter);
35+
36+
const validFilter = constructValidLogSubscriptionFilter(originalFilter);
37+
const validFilterKeys = Object.keys(validFilter);
38+
39+
expect(validFilterKeys).to.not.deep.eq(originalFilterKeys);
40+
expect(validFilterKeys.length).to.eq(2); // address & topics
41+
expect(validFilter['address']).to.eq(originalFilter.address);
42+
expect(validFilter['topics']).to.eq(originalFilter.topics);
43+
expect(validFilter['fromBlock']).to.not.exist;
44+
expect(validFilter['toBlock']).to.not.exist;
45+
expect(validFilter['hedera']).to.not.exist;
46+
});
47+
48+
it('Should only add valid params if presented in original filter object', () => {
49+
// original missing `address` param
50+
const originalFilter1 = {
51+
topics: ['0x1d29d0f04057864b829c60f025fdba344f1623eb30b90820f5a6c39ffbd1c512'],
52+
};
53+
const validFilter1 = constructValidLogSubscriptionFilter(originalFilter1);
54+
const validFilter1Keys = Object.keys(validFilter1);
55+
expect(validFilter1Keys.length).to.eq(1);
56+
expect(validFilter1['address']).to.not.exist;
57+
expect(validFilter1['topics']).to.eq(originalFilter1.topics);
58+
59+
// original missing `topics` param
60+
const originalFilter2 = {
61+
address: '0x23f5e49569A835d7bf9AefD30e4f60CdD570f225',
62+
};
63+
const validFilter2 = constructValidLogSubscriptionFilter(originalFilter2);
64+
const validFilter2Keys = Object.keys(validFilter2);
65+
expect(validFilter2Keys.length).to.eq(1);
66+
expect(validFilter2['topics']).to.not.exist;
67+
expect(validFilter2['address']).to.eq(originalFilter2.address);
68+
});
69+
});
70+
});

0 commit comments

Comments
 (0)