Skip to content

Commit 270877b

Browse files
Refactor eth_estimateGas (#1280)
* Refactor `eth_estimateGas` Signed-off-by: georgi-l95 <[email protected]> * handling nit suggested by Nana on code review Signed-off-by: Alfredo Gutierrez <[email protected]> --------- Signed-off-by: georgi-l95 <[email protected]> Signed-off-by: Alfredo Gutierrez <[email protected]> Co-authored-by: Alfredo Gutierrez <[email protected]>
1 parent d95500b commit 270877b

File tree

2 files changed

+98
-31
lines changed

2 files changed

+98
-31
lines changed

packages/relay/src/lib/eth.ts

Lines changed: 43 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -436,42 +436,54 @@ export class EthImpl implements Eth {
436436
async estimateGas(transaction: any, _blockParam: string | null, requestId?: string) {
437437
const requestIdPrefix = formatRequestIdMessage(requestId);
438438
this.logger.trace(`${requestIdPrefix} estimateGas(transaction=${JSON.stringify(transaction)}, _blockParam=${_blockParam})`);
439-
// this checks whether this is a transfer transaction and not a contract function execution
440-
if (transaction && transaction.to && (!transaction.data || transaction.data === '0x')) {
441-
const value = Number(transaction.value);
442-
if (value > 0) {
443-
const accountCacheKey = `${constants.CACHE_KEY.ACCOUNT}_${transaction.to}`;
444-
let toAccount: object | null = this.cache.get(accountCacheKey);
445-
if (!toAccount) {
446-
toAccount = await this.mirrorNodeClient.getAccount(transaction.to, requestId);
447-
}
448-
449-
// when account exists return default base gas, otherwise return the minimum amount of gas to create an account entity
450-
if (toAccount) {
451-
this.logger.trace(`${requestIdPrefix} caching ${accountCacheKey}:${JSON.stringify(toAccount)} for ${constants.CACHE_TTL.ONE_HOUR} ms`);
452-
this.cache.set(accountCacheKey, toAccount);
453-
454-
return EthImpl.gasTxBaseCost;
439+
440+
let gas = EthImpl.gasTxBaseCost;
441+
try {
442+
const contractCallResponse = await this.mirrorNodeClient.postContractCall({
443+
...transaction,
444+
estimate: true
445+
}, requestId);
446+
if (contractCallResponse?.result) {
447+
// Workaround until mirror-node bugfix applied, currently mirror-node returns 21k for contract creation, which is wrong
448+
if (!transaction.to && transaction.data !== '0x') {
449+
gas = this.defaultGas;
450+
} else {
451+
gas = EthImpl.prepend0x(contractCallResponse.result);
455452
}
456-
457-
return EthImpl.gasTxHollowAccountCreation;
458453
}
459-
460-
return predefined.INVALID_PARAMETER(0, `Invalid 'value' field in transaction param. Value must be greater than 0`);
461-
} else {
462-
try {
463-
const contractCallResponse = await this.mirrorNodeClient.postContractCall({
464-
...transaction,
465-
estimate: true
466-
}, requestId);
467-
if (contractCallResponse?.result) {
468-
return EthImpl.prepend0x(contractCallResponse.result);
454+
} catch (e: any) {
455+
this.logger.error(`${requestIdPrefix} Error raised while fetching estimateGas from mirror-node: ${JSON.stringify(e)}`);
456+
457+
// Handle Simple Transaction and Hollow account creation
458+
if (transaction && transaction.to && (!transaction.data || transaction.data === '0x')){
459+
const value = Number(transaction.value);
460+
if (value > 0) {
461+
const accountCacheKey = `${constants.CACHE_KEY.ACCOUNT}_${transaction.to}`;
462+
let toAccount: object | null = this.cache.get(accountCacheKey);
463+
if (!toAccount) {
464+
toAccount = await this.mirrorNodeClient.getAccount(transaction.to, requestId);
465+
}
466+
467+
// when account exists return default base gas, otherwise return the minimum amount of gas to create an account entity
468+
if (toAccount) {
469+
this.logger.trace(`${requestIdPrefix} caching ${accountCacheKey}:${JSON.stringify(toAccount)} for ${constants.CACHE_TTL.ONE_HOUR} ms`);
470+
this.cache.set(accountCacheKey, toAccount);
471+
472+
gas = EthImpl.gasTxBaseCost;
473+
} else {
474+
gas = EthImpl.gasTxHollowAccountCreation;
475+
}
476+
} else {
477+
return predefined.INVALID_PARAMETER(0, `Invalid 'value' field in transaction param. Value must be greater than 0`);
469478
}
470-
} catch (e: any) {
471-
this.logger.error(e, `${requestIdPrefix} Error raised during estimateGas with: ${JSON.stringify(e)}`);
479+
} else {
480+
// Handle Contract Call or Contract Create
481+
gas = this.defaultGas;
472482
}
473-
return this.defaultGas;
474483
}
484+
this.logger.error(`${requestIdPrefix} Returning predefined gas: ${gas}`);
485+
486+
return gas;
475487
}
476488

477489
/**

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

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3082,6 +3082,61 @@ describe('Eth calls using MirrorNode', async function () {
30823082

30833083
});
30843084

3085+
it('eth_estimateGas to mirror node for contract call returns 501', async function () {
3086+
const callData = {
3087+
data: "0x608060405234801561001057600080fd5b506040516107893803806107898339818101604052810190610032919061015a565b806000908051906020019061004892919061004f565b50506102f6565b82805461005b90610224565b90600052602060002090601f01602090048101928261007d57600085556100c4565b82601f1061009657805160ff19168380011785556100c4565b828001600101855582156100c4579182015b828111156100c35782518255916020019190600101906100a8565b5b5090506100d191906100d5565b5090565b5b808211156100ee5760008160009055506001016100d6565b5090565b6000610105610100846101c0565b61019b565b90508281526020810184848401111561011d57600080fd5b6101288482856101f1565b509392505050565b600082601f83011261014157600080fd5b81516101518482602086016100f2565b91505092915050565b60006020828403121561016c57600080fd5b600082015167ffffffffffffffff81111561018657600080fd5b61019284828501610130565b91505092915050565b60006101a56101b6565b90506101b18282610256565b919050565b6000604051905090565b600067ffffffffffffffff8211156101db576101da6102b6565b5b6101e4826102e5565b9050602081019050919050565b60005b8381101561020f5780820151818401526020810190506101f4565b8381111561021e576000848401525b50505050565b6000600282049050600182168061023c57607f821691505b602082108114156102505761024f610287565b5b50919050565b61025f826102e5565b810181811067ffffffffffffffff8211171561027e5761027d6102b6565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000601f19601f8301169050919050565b610484806103056000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063a41368621461003b578063cfae321714610057575b600080fd5b6100556004803603810190610050919061022c565b610075565b005b61005f61008f565b60405161006c91906102a6565b60405180910390f35b806000908051906020019061008b929190610121565b5050565b60606000805461009e9061037c565b80601f01602080910402602001604051908101604052809291908181526020018280546100ca9061037c565b80156101175780601f106100ec57610100808354040283529160200191610117565b820191906000526020600020905b8154815290600101906020018083116100fa57829003601f168201915b5050505050905090565b82805461012d9061037c565b90600052602060002090601f01602090048101928261014f5760008555610196565b82601f1061016857805160ff1916838001178555610196565b82800160010185558215610196579182015b8281111561019557825182559160200191906001019061017a565b5b5090506101a391906101a7565b5090565b5b808211156101c05760008160009055506001016101a8565b5090565b60006101d76101d2846102ed565b6102c8565b9050828152602081018484840111156101ef57600080fd5b6101fa84828561033a565b509392505050565b600082601f83011261021357600080fd5b81356102238482602086016101c4565b91505092915050565b60006020828403121561023e57600080fd5b600082013567ffffffffffffffff81111561025857600080fd5b61026484828501610202565b91505092915050565b60006102788261031e565b6102828185610329565b9350610292818560208601610349565b61029b8161043d565b840191505092915050565b600060208201905081810360008301526102c0818461026d565b905092915050565b60006102d26102e3565b90506102de82826103ae565b919050565b6000604051905090565b600067ffffffffffffffff8211156103085761030761040e565b5b6103118261043d565b9050602081019050919050565b600081519050919050565b600082825260208201905092915050565b82818337600083830152505050565b60005b8381101561036757808201518184015260208101905061034c565b83811115610376576000848401525b50505050565b6000600282049050600182168061039457607f821691505b602082108114156103a8576103a76103df565b5b50919050565b6103b78261043d565b810181811067ffffffffffffffff821117156103d6576103d561040e565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000601f19601f830116905091905056fea264697066735822122070d157c4efbb3fba4a1bde43cbba5b92b69f2fc455a650c0dfb61e9ed3d4bd6364736f6c634300080400330000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b696e697469616c5f6d7367000000000000000000000000000000000000000000",
3088+
from: "0x81cb089c285e5ee3a7353704fb114955037443af",
3089+
}
3090+
web3Mock.onPost('contracts/call', {...callData, estimate: true}).reply(501, {"errorMessage":"","statusCode":501});
3091+
3092+
const gas = await ethImpl.estimateGas(callData, null);
3093+
expect(gas).to.equal(EthImpl.numberTo0x(constants.TX_DEFAULT_GAS_DEFAULT));
3094+
});
3095+
3096+
it('eth_estimateGas to mirror node for transfer returns 501', async function () {
3097+
const callData = {
3098+
data: "0x",
3099+
from: "0x81cb089c285e5ee3a7353704fb114955037443af",
3100+
to: "0x5b98Ce3a4D1e1AC55F15Da174D5CeFcc5b8FB994",
3101+
value: "0x1"
3102+
}
3103+
web3Mock.onPost('contracts/call', {...callData, estimate: true}).reply(501, {"errorMessage":"","statusCode":501});
3104+
3105+
const receiverAddress = '0x5b98Ce3a4D1e1AC55F15Da174D5CeFcc5b8FB994';
3106+
restMock.onGet(`accounts/${receiverAddress}`).reply(200, { address: receiverAddress });
3107+
3108+
const gas = await ethImpl.estimateGas(callData, null);
3109+
expect(gas).to.equal(EthImpl.numberTo0x(constants.TX_BASE_COST));
3110+
});
3111+
3112+
it('eth_estimateGas to mirror node for transfer without value returns 501', async function () {
3113+
const callData = {
3114+
data: "0x",
3115+
from: "0x81cb089c285e5ee3a7353704fb114955037443af",
3116+
to: "0x5b98Ce3a4D1e1AC55F15Da174D5CeFcc5b8FB994"
3117+
}
3118+
web3Mock.onPost('contracts/call', {...callData, estimate: true}).reply(501, {"errorMessage":"","statusCode":501});
3119+
3120+
const receiverAddress = '0x5b98Ce3a4D1e1AC55F15Da174D5CeFcc5b8FB994';
3121+
restMock.onGet(`accounts/${receiverAddress}`).reply(200, { address: receiverAddress });
3122+
3123+
const result = await ethImpl.estimateGas(callData, null);
3124+
expect(result).to.not.be.null;
3125+
expect(result.code).to.eq(-32602);
3126+
expect(result.name).to.eq("Invalid parameter");
3127+
});
3128+
3129+
it('eth_estimateGas contract call returns workaround response from mirror-node', async function () {
3130+
const callData = {
3131+
data: "0x608060405234801561001057600080fd5b506040516107893803806107898339818101604052810190610032919061015a565b806000908051906020019061004892919061004f565b50506102f6565b82805461005b90610224565b90600052602060002090601f01602090048101928261007d57600085556100c4565b82601f1061009657805160ff19168380011785556100c4565b828001600101855582156100c4579182015b828111156100c35782518255916020019190600101906100a8565b5b5090506100d191906100d5565b5090565b5b808211156100ee5760008160009055506001016100d6565b5090565b6000610105610100846101c0565b61019b565b90508281526020810184848401111561011d57600080fd5b6101288482856101f1565b509392505050565b600082601f83011261014157600080fd5b81516101518482602086016100f2565b91505092915050565b60006020828403121561016c57600080fd5b600082015167ffffffffffffffff81111561018657600080fd5b61019284828501610130565b91505092915050565b60006101a56101b6565b90506101b18282610256565b919050565b6000604051905090565b600067ffffffffffffffff8211156101db576101da6102b6565b5b6101e4826102e5565b9050602081019050919050565b60005b8381101561020f5780820151818401526020810190506101f4565b8381111561021e576000848401525b50505050565b6000600282049050600182168061023c57607f821691505b602082108114156102505761024f610287565b5b50919050565b61025f826102e5565b810181811067ffffffffffffffff8211171561027e5761027d6102b6565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000601f19601f8301169050919050565b610484806103056000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063a41368621461003b578063cfae321714610057575b600080fd5b6100556004803603810190610050919061022c565b610075565b005b61005f61008f565b60405161006c91906102a6565b60405180910390f35b806000908051906020019061008b929190610121565b5050565b60606000805461009e9061037c565b80601f01602080910402602001604051908101604052809291908181526020018280546100ca9061037c565b80156101175780601f106100ec57610100808354040283529160200191610117565b820191906000526020600020905b8154815290600101906020018083116100fa57829003601f168201915b5050505050905090565b82805461012d9061037c565b90600052602060002090601f01602090048101928261014f5760008555610196565b82601f1061016857805160ff1916838001178555610196565b82800160010185558215610196579182015b8281111561019557825182559160200191906001019061017a565b5b5090506101a391906101a7565b5090565b5b808211156101c05760008160009055506001016101a8565b5090565b60006101d76101d2846102ed565b6102c8565b9050828152602081018484840111156101ef57600080fd5b6101fa84828561033a565b509392505050565b600082601f83011261021357600080fd5b81356102238482602086016101c4565b91505092915050565b60006020828403121561023e57600080fd5b600082013567ffffffffffffffff81111561025857600080fd5b61026484828501610202565b91505092915050565b60006102788261031e565b6102828185610329565b9350610292818560208601610349565b61029b8161043d565b840191505092915050565b600060208201905081810360008301526102c0818461026d565b905092915050565b60006102d26102e3565b90506102de82826103ae565b919050565b6000604051905090565b600067ffffffffffffffff8211156103085761030761040e565b5b6103118261043d565b9050602081019050919050565b600081519050919050565b600082825260208201905092915050565b82818337600083830152505050565b60005b8381101561036757808201518184015260208101905061034c565b83811115610376576000848401525b50505050565b6000600282049050600182168061039457607f821691505b602082108114156103a8576103a76103df565b5b50919050565b6103b78261043d565b810181811067ffffffffffffffff821117156103d6576103d561040e565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000601f19601f830116905091905056fea264697066735822122070d157c4efbb3fba4a1bde43cbba5b92b69f2fc455a650c0dfb61e9ed3d4bd6364736f6c634300080400330000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b696e697469616c5f6d7367000000000000000000000000000000000000000000",
3132+
from: "0x81cb089c285e5ee3a7353704fb114955037443af",
3133+
}
3134+
web3Mock.onPost('contracts/call', {...callData, estimate: true}).reply(200, {result: `0x61A80`});
3135+
3136+
const gas = await ethImpl.estimateGas(callData, null);
3137+
expect(gas).to.equal(EthImpl.numberTo0x(constants.TX_DEFAULT_GAS_DEFAULT));
3138+
});
3139+
30853140
it('eth_estimateGas contract call returns default', async function () {
30863141
const gas = await ethImpl.estimateGas({ data: "0x01" }, null);
30873142
expect(gas).to.equal(EthImpl.numberTo0x(constants.TX_DEFAULT_GAS_DEFAULT));

0 commit comments

Comments
 (0)