Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Limit the ethCall gas to 15_000_000, otherwise the call will fail #513

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions packages/relay/src/lib/eth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ export class EthImpl implements Eth {

return result;
}

/**
* Gets the balance of an account as of the given block.
*
Expand Down Expand Up @@ -704,11 +704,11 @@ export class EthImpl implements Eth {
const result = await this.mirrorNodeClient.resolveEntityType(address, requestId);
if (result?.type === constants.TYPE_ACCOUNT) {
const accountInfo = await this.sdkClient.getAccountInfo(result?.entity.account, EthImpl.ethGetTransactionCount, requestId);
return EthImpl.numberTo0x(Number(accountInfo.ethereumNonce));
return EthImpl.numberTo0x(Number(accountInfo.ethereumNonce));
}
else if (result?.type === constants.TYPE_CONTRACT) {
return EthImpl.numberTo0x(1);
}
}
} catch (e: any) {
this.logger.error(e, `${requestIdPrefix} Error raised during getTransactionCount for address ${address}, block number or tag ${blockNumOrTag}`);
return predefined.INTERNAL_ERROR;
Expand Down Expand Up @@ -792,7 +792,14 @@ export class EthImpl implements Eth {
gas = call.gas;
}
}


// Gas limit for `eth_call` is 50_000_000, but the Hedera network limit is 15_000_000
// With values over 15_000_000 the call will fail with BUSY error
if (gas > 15_000_000) {
this.logger.trace(`${requestIdPrefix} eth_call gas amount (${gas}) exceeds network limit, capping gas to 15_000_000`);
gas = 15_000_000;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: could have made 15_000_000 a const
Can make this change in a future PR, no biggie

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll still probably have to merge main at some point to fix the dapp tests, I can push that change too

}

// Execute the call and get the response
this.logger.debug(`${requestIdPrefix} Making eth_call on contract ${call.to} with gas ${gas} and call data "${call.data}" from "${call.from}"`, call.to, gas, call.data, call.from);
const contractCallResponse = await this.sdkClient.submitContractCallQuery(call.to, call.data, gas, call.from, EthImpl.ethCall, requestId);
Expand Down
66 changes: 44 additions & 22 deletions packages/relay/tests/lib/eth.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import { Block, Transaction } from '../../src/lib/model';
import constants from '../../src/lib/constants';
import { SDKClient } from '../../src/lib/clients';
import { SDKClientError } from '../../src/lib/errors/SDKClientError';
import { isTypedArray } from 'util/types';

const logger = pino();
const registry = new Registry();
Expand Down Expand Up @@ -1204,7 +1205,7 @@ describe('Eth calls using MirrorNode', async function () {
const latestBlock = {...defaultBlock, number: blockNumber3};
const previousFees = JSON.parse(JSON.stringify(defaultNetworkFees));
const latestFees = JSON.parse(JSON.stringify(defaultNetworkFees));

previousFees.fees[2].gas += 1;

mock.onGet('blocks?limit=1&order=desc').reply(200, {blocks: [latestBlock]});
Expand Down Expand Up @@ -1247,7 +1248,7 @@ describe('Eth calls using MirrorNode', async function () {
it('eth_feeHistory verify cached value', async function () {
const latestBlock = {...defaultBlock, number: blockNumber3};
const latestFees = defaultNetworkFees;

mock.onGet('blocks?limit=1&order=desc').reply(200, {blocks: [latestBlock]});
mock.onGet(`blocks/${latestBlock.number}`).reply(200, latestBlock);
mock.onGet(`network/fees?timestamp=lte:${latestBlock.timestamp.to}`).reply(200, latestFees);
Expand All @@ -1265,7 +1266,7 @@ describe('Eth calls using MirrorNode', async function () {

it('eth_feeHistory on mirror 404', async function () {
const latestBlock = {...defaultBlock, number: blockNumber3};

mock.onGet('blocks?limit=1&order=desc').reply(200, {blocks: [latestBlock]});
mock.onGet(`blocks/${latestBlock.number}`).reply(200, latestBlock);
mock.onGet(`network/fees?timestamp=lte:${latestBlock.timestamp.to}`).reply(404, {
Expand All @@ -1291,7 +1292,7 @@ describe('Eth calls using MirrorNode', async function () {

it('eth_feeHistory on mirror 500', async function () {
const latestBlock = {...defaultBlock, number: blockNumber3};

mock.onGet('blocks?limit=1&order=desc').reply(200, {blocks: [latestBlock]});
mock.onGet(`blocks/${latestBlock.number}`).reply(200, latestBlock);
mock.onGet(`network/fees?timestamp=lte:${latestBlock.timestamp.to}`).reply(404, {
Expand Down Expand Up @@ -1408,7 +1409,7 @@ describe('Eth calls using MirrorNode', async function () {
it('eth_call with no gas', async function () {
sdkClientStub.submitContractCallQuery.returns({
asBytes: function () {
return Uint8Array.of(0)
return Uint8Array.of(0);
}
}
);
Expand All @@ -1417,34 +1418,34 @@ describe('Eth calls using MirrorNode', async function () {
"from": contractAddress1,
"to": contractAddress2,
"data": contractCallData,
}, 'latest')
}, 'latest');

sinon.assert.calledWith(sdkClientStub.submitContractCallQuery, contractAddress2, contractCallData, 400_000, contractAddress1, 'eth_call');
expect(result).to.equal("0x00")
expect(result).to.equal("0x00");
});

it('eth_call with no data', async function () {
sdkClientStub.submitContractCallQuery.returns({
asBytes: function () {
return Uint8Array.of(0)
return Uint8Array.of(0);
}
}
);

var result = await ethImpl.call({
const result = await ethImpl.call({
"from": contractAddress1,
"to": contractAddress2,
"gas": maxGasLimitHex
}, 'latest')
}, 'latest');

sinon.assert.calledWith(sdkClientStub.submitContractCallQuery, contractAddress2, undefined, maxGasLimit, contractAddress1, 'eth_call');
expect(result).to.equal("0x00")
expect(result).to.equal("0x00");
});

it('eth_call with no from address', async function () {
sdkClientStub.submitContractCallQuery.returns({
asBytes: function () {
return Uint8Array.of(0)
return Uint8Array.of(0);
}
}
);
Expand All @@ -1453,16 +1454,16 @@ describe('Eth calls using MirrorNode', async function () {
"to": contractAddress2,
"data": contractCallData,
"gas": maxGasLimitHex
}, 'latest')
}, 'latest');

sinon.assert.calledWith(sdkClientStub.submitContractCallQuery, contractAddress2, contractCallData, maxGasLimit, undefined, 'eth_call');
expect(result).to.equal("0x00")
expect(result).to.equal("0x00");
});

it('eth_call with all fields', async function () {
sdkClientStub.submitContractCallQuery.returns({
asBytes: function () {
return Uint8Array.of(0)
return Uint8Array.of(0);
}
}
);
Expand All @@ -1472,10 +1473,31 @@ describe('Eth calls using MirrorNode', async function () {
"to": contractAddress2,
"data": contractCallData,
"gas": maxGasLimitHex
}, 'latest')
}, 'latest');

sinon.assert.calledWith(sdkClientStub.submitContractCallQuery, contractAddress2, contractCallData, maxGasLimit, contractAddress1, 'eth_call');
expect(result).to.equal("0x00")
expect(result).to.equal("0x00");
});

describe('with gas > 15_000_000', async function() {
it('caps gas at 15_000_000', async function () {
sdkClientStub.submitContractCallQuery.returns({
asBytes: function () {
return Uint8Array.of(0);
}
}
);

const result = await ethImpl.call({
"from": contractAddress1,
"to": contractAddress2,
"data": contractCallData,
"gas": 50_000_000
}, 'latest');

sinon.assert.calledWith(sdkClientStub.submitContractCallQuery, contractAddress2, contractCallData, 15_000_000, contractAddress1, 'eth_call');
expect(result).to.equal("0x00");
});
});
});

Expand Down Expand Up @@ -1507,7 +1529,7 @@ describe('Eth calls using MirrorNode', async function () {
const result = await ethImpl.getStorageAt(contractAddress1, defaultDetailedContractResults.state_changes[0].slot, EthImpl.numberTo0x(blockNumber));
expect(result).to.exist;
if (result == null) return;

// verify slot value
expect(result).equal(defaultDetailedContractResults.state_changes[0].value_written);
});
Expand All @@ -1520,7 +1542,7 @@ describe('Eth calls using MirrorNode', async function () {
const result = await ethImpl.getStorageAt(contractAddress1, defaultDetailedContractResults.state_changes[0].slot, "latest");
expect(result).to.exist;
if (result == null) return;

// verify slot value
expect(result).equal(defaultDetailedContractResults.state_changes[0].value_written);
});
Expand All @@ -1533,7 +1555,7 @@ describe('Eth calls using MirrorNode', async function () {
const result = await ethImpl.getStorageAt(contractAddress1, defaultDetailedContractResults.state_changes[0].slot);
expect(result).to.exist;
if (result == null) return;

// verify slot value
expect(result).equal(defaultDetailedContractResults.state_changes[0].value_written);
});
Expand All @@ -1543,7 +1565,7 @@ describe('Eth calls using MirrorNode', async function () {
let hasError = false;
try {
mock.onGet(`blocks/${blockNumber}`).reply(200, null);
const result = await ethImpl.getStorageAt(contractAddress1, defaultDetailedContractResults.state_changes[0].slot, EthImpl.numberTo0x(blockNumber));
const result = await ethImpl.getStorageAt(contractAddress1, defaultDetailedContractResults.state_changes[0].slot, EthImpl.numberTo0x(blockNumber));
} catch (e: any) {
hasError = true;
expect(e.code).to.equal(-32001);
Expand All @@ -1565,7 +1587,7 @@ describe('Eth calls using MirrorNode', async function () {
hasError = true;
expect(e.statusCode).to.equal(404);
expect(e.message).to.equal("Request failed with status code 404");
}
}
expect(hasError).to.be.true;
});
});
Expand Down