Skip to content

Commit

Permalink
Fix eth_estimateGas for hollow account creation (#844) (#860)
Browse files Browse the repository at this point in the history
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 <n.atanasow94@gmail.com>
Signed-off-by: georgi-l95 <glazarov95@gmail.com>
Signed-off-by: Nana Essilfie-Conduah <nana@swirldslabs.com>
Co-authored-by: Nikolay Atanasow <n.atanasow94@gmail.com>
Co-authored-by: georgi-l95 <glazarov95@gmail.com>
  • Loading branch information
3 people authored Jan 30, 2023
1 parent 3616571 commit 6d14f05
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 4 deletions.
1 change: 1 addition & 0 deletions packages/relay/src/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export default {
BLOCK_GAS_LIMIT: 15_000_000,
ISTANBUL_TX_DATA_NON_ZERO_COST: 16,
TX_BASE_COST: 21_000,
TX_HOLLOW_ACCOUNT_CREATION_GAS: 587_000,
TX_DEFAULT_GAS: 400_000,
TX_CREATE_EXTRA: 32_000,
TX_DATA_ZERO_COST: 4,
Expand Down
6 changes: 5 additions & 1 deletion packages/relay/src/lib/eth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export class EthImpl implements Eth {
static emptyBloom = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
static defaultGas = EthImpl.numberTo0x(constants.TX_DEFAULT_GAS);
static gasTxBaseCost = EthImpl.numberTo0x(constants.TX_BASE_COST);
static gasTxHollowAccountCreation = EthImpl.numberTo0x(constants.TX_HOLLOW_ACCOUNT_CREATION_GAS);
static ethTxType = 'EthereumTransaction';
static ethEmptyTrie = '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421';
static defaultGasUsedRatio = 0.5;
Expand Down Expand Up @@ -325,8 +326,11 @@ export class EthImpl implements Eth {
async estimateGas(transaction: any, _blockParam: string | null, requestId?: string) {
const requestIdPrefix = formatRequestIdMessage(requestId);
this.logger.trace(`${requestIdPrefix} estimateGas(transaction=${JSON.stringify(transaction)}, _blockParam=${_blockParam})`);
//this checks whether this is a transfer transaction and not a contract function execution
if (!transaction || !transaction.data || transaction.data === '0x') {
return EthImpl.gasTxBaseCost;
const toAccount = await this.mirrorNodeClient.getAccount(transaction.to);
// when account exists return default base gas, otherwise return the minimum amount of gas to create an account entity
return toAccount ? EthImpl.gasTxBaseCost : EthImpl.gasTxHollowAccountCreation;
} else {
return EthImpl.defaultGas;
}
Expand Down
20 changes: 17 additions & 3 deletions packages/relay/tests/lib/eth.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2218,19 +2218,33 @@ describe('Eth calls using MirrorNode', async function () {
expect(gas).to.equal(EthImpl.defaultGas);
});

it('eth_estimateGas transfer to existing account', async function() {
const receiverAddress = '0x5b98Ce3a4D1e1AC55F15Da174D5CeFcc5b8FB994';
mock.onGet(`accounts/${receiverAddress}`).reply(200, { address: receiverAddress });

const gas = await ethImpl.estimateGas({
to: receiverAddress,
value: 100_000_000_000
}, null);
expect(gas).to.equal(EthImpl.gasTxBaseCost);
});

it('eth_estimateGas empty call returns transfer cost', async function () {
mock.onGet(`accounts/undefined`).reply(404);
const gas = await ethImpl.estimateGas({}, null);
expect(gas).to.equal(EthImpl.gasTxBaseCost);
expect(gas).to.equal(EthImpl.gasTxHollowAccountCreation);
});

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

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

it('eth_gasPrice', async function () {
Expand Down
1 change: 1 addition & 0 deletions packages/relay/tests/lib/openrpc.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ describe("Open RPC Specification", function () {
});

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

validateResponseSchema(methodsResponseSchema.eth_estimateGas, response);
Expand Down
28 changes: 28 additions & 0 deletions packages/server/tests/acceptance/rpc_batch2.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ describe('@api-batch-2 RPC Server Acceptance Tests', function () {
let contractExecuteTimestamp;
let mirrorContract;
let mirrorContractDetails;
let mirrorSecondaryAccount;
let requestId;

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

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

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

it('@release should execute "eth_estimateGas" for contract call', async function() {
const res = await relay.call('eth_estimateGas', [{
to: mirrorContract.evm_address,
data: BASIC_CONTRACT_PING_CALL_DATA
}], requestId);
expect(res).to.contain('0x');
expect(res).to.equal(EthImpl.defaultGas);
});

it('@release should execute "eth_estimateGas" for existing account', async function() {
const res = await relay.call('eth_estimateGas', [{
to: mirrorSecondaryAccount.evm_address
}], requestId);
expect(res).to.contain('0x');
expect(res).to.equal(EthImpl.gasTxBaseCost);
});

it('@release should execute "eth_estimateGas" hollow account creation', async function() {
const hollowAccount = ethers.Wallet.createRandom();
const res = await relay.call('eth_estimateGas', [{
to: hollowAccount.address
}], requestId);
expect(res).to.contain('0x');
expect(res).to.equal(EthImpl.gasTxHollowAccountCreation);
});

it('should execute "eth_estimateGas" with to, from, value and gas filed', async function () {
const res = await relay.call('eth_estimateGas', [{
from: '0x114f60009ee6b84861c0cdae8829751e517bc4d7',
Expand Down

0 comments on commit 6d14f05

Please sign in to comment.