Skip to content

Commit ee7ebde

Browse files
authored
feat: added parameter check on block param for getcode() (#2259)
* feat: added parameter check on block param for getcode() Signed-off-by: Logan Nguyen <[email protected]> * update: updated UNKNOWN_BLOCK to accept param Signed-off-by: Logan Nguyen <[email protected]> * fix: replaced INVALID_PARAMETER rpc error with UNKNOWN_BLOCK in getCode() Signed-off-by: Logan Nguyen <[email protected]> --------- Signed-off-by: Logan Nguyen <[email protected]>
1 parent d596921 commit ee7ebde

File tree

4 files changed

+59
-15
lines changed

4 files changed

+59
-15
lines changed

packages/relay/src/lib/errors/JsonRpcError.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -250,11 +250,12 @@ export const predefined = {
250250
code: -32000,
251251
message: `Exceeded max transactions that can be returned in a block: ${count}`,
252252
}),
253-
UNKNOWN_BLOCK: new JsonRpcError({
254-
name: 'Unknown block',
255-
code: -39012,
256-
message: 'Unknown block',
257-
}),
253+
UNKNOWN_BLOCK: (msg?: string | null) =>
254+
new JsonRpcError({
255+
name: 'Unknown block',
256+
code: -39012,
257+
message: msg || 'Unknown block',
258+
}),
258259
INVALID_BLOCK_RANGE: new JsonRpcError({
259260
name: 'Invalid block range',
260261
code: -39013,

packages/relay/src/lib/eth.ts

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,6 +1014,12 @@ export class EthImpl implements Eth {
10141014
* @param blockNumber
10151015
*/
10161016
async getCode(address: string, blockNumber: string | null, requestIdPrefix?: string) {
1017+
if (!EthImpl.isBlockParamValid(blockNumber)) {
1018+
throw predefined.UNKNOWN_BLOCK(
1019+
`The value passed is not a valid blockHash/blockNumber/blockTag value: ${blockNumber}`,
1020+
);
1021+
}
1022+
10171023
this.logger.trace(`${requestIdPrefix} getCode(address=${address}, blockNumber=${blockNumber})`);
10181024

10191025
// check for static precompile cases first before consulting nodes
@@ -1316,7 +1322,7 @@ export class EthImpl implements Eth {
13161322
nonceCount = await this.getAccountNonceForHistoricBlock(address, blockNumOrTag, requestIdPrefix);
13171323
} else {
13181324
// return a '-39001: Unknown block' error per api-spec
1319-
throw predefined.UNKNOWN_BLOCK;
1325+
throw predefined.UNKNOWN_BLOCK();
13201326
}
13211327
} else {
13221328
// if no block consideration, get latest ethereumNonce from mirror node if account or from consensus node is contract until HIP 729 is implemented
@@ -1943,11 +1949,11 @@ export class EthImpl implements Eth {
19431949
return input.startsWith(EthImpl.emptyHex) ? input.substring(2) : input;
19441950
}
19451951

1946-
private static blockTagIsEarliest = (tag) => {
1952+
private static isBlockTagEarliest = (tag: string) => {
19471953
return tag === EthImpl.blockEarliest;
19481954
};
19491955

1950-
private static blockTagIsFinalized = (tag) => {
1956+
private static isBlockTagFinalized = (tag: string) => {
19511957
return (
19521958
tag === EthImpl.blockFinalized ||
19531959
tag === EthImpl.blockLatest ||
@@ -1956,6 +1962,14 @@ export class EthImpl implements Eth {
19561962
);
19571963
};
19581964

1965+
private static isBlockNumValid = (num: string) => {
1966+
return /^0[xX]([1-9A-Fa-f]+[0-9A-Fa-f]{0,13}|0)$/.test(num) && Number.MAX_SAFE_INTEGER >= Number(num);
1967+
};
1968+
1969+
private static isBlockParamValid = (tag: string | null) => {
1970+
return tag == null || this.isBlockTagEarliest(tag) || this.isBlockTagFinalized(tag) || this.isBlockNumValid(tag);
1971+
};
1972+
19591973
private static isBlockHash = (blockHash) => {
19601974
return new RegExp(constants.BLOCK_HASH_REGEX + '{64}$').test(blockHash);
19611975
};
@@ -2193,7 +2207,7 @@ export class EthImpl implements Eth {
21932207
// get block timestamp for blockNum
21942208
const block = await this.mirrorNodeClient.getBlock(blockNumOrHash, requestIdPrefix); // consider caching error responses
21952209
if (block == null) {
2196-
throw predefined.UNKNOWN_BLOCK;
2210+
throw predefined.UNKNOWN_BLOCK();
21972211
}
21982212

21992213
// get the latest 2 ethereum transactions for the account
@@ -2260,7 +2274,7 @@ export class EthImpl implements Eth {
22602274
const isParamBlockNum = typeof blockNumOrHash === 'number' ? true : false;
22612275

22622276
if (isParamBlockNum && blockNumOrHash < 0) {
2263-
throw predefined.UNKNOWN_BLOCK;
2277+
throw predefined.UNKNOWN_BLOCK();
22642278
}
22652279

22662280
if (!isParamBlockNum) {
@@ -2272,7 +2286,7 @@ export class EthImpl implements Eth {
22722286
// check if on latest block, if so get latest ethereumNonce from mirror node account API
22732287
const blockResponse = await this.mirrorNodeClient.getLatestBlock(requestIdPrefix); // consider caching error responses
22742288
if (blockResponse == null || blockResponse.blocks.length === 0) {
2275-
throw predefined.UNKNOWN_BLOCK;
2289+
throw predefined.UNKNOWN_BLOCK();
22762290
}
22772291

22782292
if (blockResponse.blocks[0].number - blockNum <= this.maxBlockRange) {

packages/relay/tests/lib/eth/eth_getCode.spec.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import {
3737
NO_TRANSACTIONS,
3838
} from './eth-config';
3939
import { generateEthTestEnv } from './eth-helpers';
40+
import { JsonRpcError, predefined } from '../../../src';
4041

4142
dotenv.config({ path: path.resolve(__dirname, '../test.env') });
4243
use(chaiAsPromised);
@@ -48,6 +49,8 @@ let currentMaxBlockRange: number;
4849
describe('@ethGetCode using MirrorNode', async function () {
4950
this.timeout(10000);
5051
let { restMock, hapiServiceInstance, ethImpl, cacheService } = generateEthTestEnv();
52+
let validBlockParam = [null, 'earliest', 'latest', 'pending', 'finalized', 'safe', '0x0', '0x369ABF'];
53+
let invalidBlockParam = ['hedera', 'ethereum', '0xhbar', '0x369ABF369ABF369ABF369ABF'];
5154

5255
this.beforeEach(() => {
5356
// reset cache and restMock
@@ -127,5 +130,31 @@ describe('@ethGetCode using MirrorNode', async function () {
127130
const res = await ethImpl.getCode(EthImpl.iHTSAddress, null);
128131
expect(res).to.equal(EthImpl.invalidEVMInstruction);
129132
});
133+
134+
validBlockParam.forEach((blockParam) => {
135+
it(`should pass the validate param check with blockParam=${blockParam} and return the bytecode`, async () => {
136+
const res = await ethImpl.getCode(CONTRACT_ADDRESS_1, blockParam);
137+
expect(res).to.equal(MIRROR_NODE_DEPLOYED_BYTECODE);
138+
});
139+
});
140+
141+
invalidBlockParam.forEach((blockParam) => {
142+
it(`should throw INVALID_PARAMETER JsonRpcError with invalid blockParam=${blockParam}`, async () => {
143+
try {
144+
await ethImpl.getCode(EthImpl.iHTSAddress, blockParam);
145+
expect(true).to.eq(false);
146+
} catch (error) {
147+
const expectedError = predefined.UNKNOWN_BLOCK(
148+
`The value passed is not a valid blockHash/blockNumber/blockTag value: ${blockParam}`,
149+
);
150+
151+
expect(error).to.exist;
152+
expect(error instanceof JsonRpcError);
153+
expect(error.code).to.eq(expectedError.code);
154+
expect(error.name).to.eq(expectedError.name);
155+
expect(error.message).to.eq(expectedError.message);
156+
}
157+
});
158+
});
130159
});
131160
});

packages/relay/tests/lib/eth/eth_getTransactionCount.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ describe('@ethGetTransactionCount eth_getTransactionCount spec', async function
209209

210210
const args = [MOCK_ACCOUNT_ADDR, blockNumberHex];
211211

212-
await RelayAssertions.assertRejection(predefined.UNKNOWN_BLOCK, ethImpl.getTransactionCount, true, ethImpl, args);
212+
await RelayAssertions.assertRejection(predefined.UNKNOWN_BLOCK(), ethImpl.getTransactionCount, true, ethImpl, args);
213213
});
214214

215215
it('should throw error for account historical numerical block tag with error on latest block', async () => {
@@ -218,7 +218,7 @@ describe('@ethGetTransactionCount eth_getTransactionCount spec', async function
218218

219219
const args = [MOCK_ACCOUNT_ADDR, blockNumberHex];
220220

221-
await RelayAssertions.assertRejection(predefined.UNKNOWN_BLOCK, ethImpl.getTransactionCount, true, ethImpl, args);
221+
await RelayAssertions.assertRejection(predefined.UNKNOWN_BLOCK(), ethImpl.getTransactionCount, true, ethImpl, args);
222222
});
223223

224224
it('should return valid nonce for historical numerical block close to latest', async () => {
@@ -300,13 +300,13 @@ describe('@ethGetTransactionCount eth_getTransactionCount spec', async function
300300
it('should throw for -1 invalid block tag', async () => {
301301
const args = [MOCK_ACCOUNT_ADDR, '-1'];
302302

303-
await RelayAssertions.assertRejection(predefined.UNKNOWN_BLOCK, ethImpl.getTransactionCount, true, ethImpl, args);
303+
await RelayAssertions.assertRejection(predefined.UNKNOWN_BLOCK(), ethImpl.getTransactionCount, true, ethImpl, args);
304304
});
305305

306306
it('should throw for invalid block tag', async () => {
307307
const args = [MOCK_ACCOUNT_ADDR, 'notablock'];
308308

309-
await RelayAssertions.assertRejection(predefined.UNKNOWN_BLOCK, ethImpl.getTransactionCount, true, ethImpl, args);
309+
await RelayAssertions.assertRejection(predefined.UNKNOWN_BLOCK(), ethImpl.getTransactionCount, true, ethImpl, args);
310310
});
311311

312312
it('should return 0x1 for pre-hip-729 contracts with nonce=null', async () => {

0 commit comments

Comments
 (0)