Skip to content

Commit d0a5d29

Browse files
natanasowgeorgi-l95
authored andcommitted
Fix eth_estimateGas for hollow account creation (#844)
Hollow account creation requires an accurate gas amount response - add a `TX_HOLLOW_ACCOUNT_CREATION_GAS` to capture the necessary gas amount - Update `eth_estimateGas` to check in the case of a transfer transaction if the recipient exists or not. If so return update gas, if not default to current flow - Update unit and acceptance tests Signed-off-by: nikolay <[email protected]> Signed-off-by: georgi-l95 <[email protected]> Co-authored-by: georgi-l95 <[email protected]> Signed-off-by: Nana Essilfie-Conduah <[email protected]>
1 parent 3616571 commit d0a5d29

File tree

5 files changed

+52
-4
lines changed

5 files changed

+52
-4
lines changed

packages/relay/src/lib/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export default {
5555
BLOCK_GAS_LIMIT: 15_000_000,
5656
ISTANBUL_TX_DATA_NON_ZERO_COST: 16,
5757
TX_BASE_COST: 21_000,
58+
TX_HOLLOW_ACCOUNT_CREATION_GAS: 587_000,
5859
TX_DEFAULT_GAS: 400_000,
5960
TX_CREATE_EXTRA: 32_000,
6061
TX_DATA_ZERO_COST: 4,

packages/relay/src/lib/eth.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export class EthImpl implements Eth {
5353
static emptyBloom = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
5454
static defaultGas = EthImpl.numberTo0x(constants.TX_DEFAULT_GAS);
5555
static gasTxBaseCost = EthImpl.numberTo0x(constants.TX_BASE_COST);
56+
static gasTxHollowAccountCreation = EthImpl.numberTo0x(constants.TX_HOLLOW_ACCOUNT_CREATION_GAS);
5657
static ethTxType = 'EthereumTransaction';
5758
static ethEmptyTrie = '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421';
5859
static defaultGasUsedRatio = 0.5;
@@ -325,8 +326,11 @@ export class EthImpl implements Eth {
325326
async estimateGas(transaction: any, _blockParam: string | null, requestId?: string) {
326327
const requestIdPrefix = formatRequestIdMessage(requestId);
327328
this.logger.trace(`${requestIdPrefix} estimateGas(transaction=${JSON.stringify(transaction)}, _blockParam=${_blockParam})`);
329+
//this checks whether this is a transfer transaction and not a contract function execution
328330
if (!transaction || !transaction.data || transaction.data === '0x') {
329-
return EthImpl.gasTxBaseCost;
331+
const toAccount = await this.mirrorNodeClient.getAccount(transaction.to);
332+
// when account exists return default base gas, otherwise return the minimum amount of gas to create an account entity
333+
return toAccount ? EthImpl.gasTxBaseCost : EthImpl.gasTxHollowAccountCreation;
330334
} else {
331335
return EthImpl.defaultGas;
332336
}

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

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2218,19 +2218,33 @@ describe('Eth calls using MirrorNode', async function () {
22182218
expect(gas).to.equal(EthImpl.defaultGas);
22192219
});
22202220

2221+
it('eth_estimateGas transfer to existing account', async function() {
2222+
const receiverAddress = '0x5b98Ce3a4D1e1AC55F15Da174D5CeFcc5b8FB994';
2223+
mock.onGet(`accounts/${receiverAddress}`).reply(200, { address: receiverAddress });
2224+
2225+
const gas = await ethImpl.estimateGas({
2226+
to: receiverAddress,
2227+
value: 100_000_000_000
2228+
}, null);
2229+
expect(gas).to.equal(EthImpl.gasTxBaseCost);
2230+
});
2231+
22212232
it('eth_estimateGas empty call returns transfer cost', async function () {
2233+
mock.onGet(`accounts/undefined`).reply(404);
22222234
const gas = await ethImpl.estimateGas({}, null);
2223-
expect(gas).to.equal(EthImpl.gasTxBaseCost);
2235+
expect(gas).to.equal(EthImpl.gasTxHollowAccountCreation);
22242236
});
22252237

22262238
it('eth_estimateGas empty input transfer cost', async function () {
2239+
mock.onGet(`accounts/undefined`).reply(404);
22272240
const gas = await ethImpl.estimateGas({ data: "" }, null);
2228-
expect(gas).to.equal(EthImpl.gasTxBaseCost);
2241+
expect(gas).to.equal(EthImpl.gasTxHollowAccountCreation);
22292242
});
22302243

22312244
it('eth_estimateGas zero input returns transfer cost', async function () {
2245+
mock.onGet(`accounts/undefined`).reply(404);
22322246
const gas = await ethImpl.estimateGas({ data: "0x" }, null);
2233-
expect(gas).to.equal(EthImpl.gasTxBaseCost);
2247+
expect(gas).to.equal(EthImpl.gasTxHollowAccountCreation);
22342248
});
22352249

22362250
it('eth_gasPrice', async function () {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ describe("Open RPC Specification", function () {
196196
});
197197

198198
it('should execute "eth_estimateGas"', async function () {
199+
mock.onGet(`accounts/undefined`).reply(404);
199200
const response = await ethImpl.estimateGas({}, null);
200201

201202
validateResponseSchema(methodsResponseSchema.eth_estimateGas, response);

packages/server/tests/acceptance/rpc_batch2.spec.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ describe('@api-batch-2 RPC Server Acceptance Tests', function () {
4949
let contractExecuteTimestamp;
5050
let mirrorContract;
5151
let mirrorContractDetails;
52+
let mirrorSecondaryAccount;
5253
let requestId;
5354

5455
const CHAIN_ID = process.env.CHAIN_ID || 0;
@@ -99,6 +100,7 @@ describe('@api-batch-2 RPC Server Acceptance Tests', function () {
99100

100101
// get contract result details
101102
mirrorContractDetails = await mirrorNode.get(`/contracts/${contractId}/results/${contractExecuteTimestamp}`, requestId);
103+
mirrorSecondaryAccount = (await mirrorNode.get(`accounts?account.id=${accounts[1].accountId}`, requestId)).accounts[0];
102104

103105
const latestBlock = (await mirrorNode.get(`/blocks?limit=1&order=desc`, requestId)).blocks[0];
104106
blockNumberAtStartOfTests = latestBlock.number;
@@ -117,6 +119,32 @@ describe('@api-batch-2 RPC Server Acceptance Tests', function () {
117119
expect(res).to.not.be.equal('0x0');
118120
});
119121

122+
it('@release should execute "eth_estimateGas" for contract call', async function() {
123+
const res = await relay.call('eth_estimateGas', [{
124+
to: mirrorContract.evm_address,
125+
data: BASIC_CONTRACT_PING_CALL_DATA
126+
}], requestId);
127+
expect(res).to.contain('0x');
128+
expect(res).to.equal(EthImpl.defaultGas);
129+
});
130+
131+
it('@release should execute "eth_estimateGas" for existing account', async function() {
132+
const res = await relay.call('eth_estimateGas', [{
133+
to: mirrorSecondaryAccount.evm_address
134+
}], requestId);
135+
expect(res).to.contain('0x');
136+
expect(res).to.equal(EthImpl.gasTxBaseCost);
137+
});
138+
139+
it('@release should execute "eth_estimateGas" hollow account creation', async function() {
140+
const hollowAccount = ethers.Wallet.createRandom();
141+
const res = await relay.call('eth_estimateGas', [{
142+
to: hollowAccount.address
143+
}], requestId);
144+
expect(res).to.contain('0x');
145+
expect(res).to.equal(EthImpl.gasTxHollowAccountCreation);
146+
});
147+
120148
it('should execute "eth_estimateGas" with to, from, value and gas filed', async function () {
121149
const res = await relay.call('eth_estimateGas', [{
122150
from: '0x114f60009ee6b84861c0cdae8829751e517bc4d7',

0 commit comments

Comments
 (0)