Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

fix: don't alter metadata state during eth_estimateGas #1732

Merged
merged 3 commits into from
Dec 3, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
5 changes: 4 additions & 1 deletion src/chains/ethereum/ethereum/src/helpers/gas-estimator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,9 @@ const binSearch = async (generateVM, runArgs, result, callback) => {
const isEnoughGas = async gas => {
const vm = generateVM(); // Generate fresh VM
runArgs.tx.gasLimit = new BN(gas.toArrayLike(Buffer));
await vm.stateManager.checkpoint();
const result = await vm.runTx(runArgs).catch(vmerr => ({ vmerr }));
await vm.stateManager.revert();
return !result.vmerr && !result.execResult.exceptionError;
};

Expand Down Expand Up @@ -245,8 +247,9 @@ const exactimate = async (vm, runArgs, callback) => {
const gas = context.getCost();
return gas.cost.add(gas.sixtyFloorths);
};

await vm.stateManager.checkpoint();
const result = await vm.runTx(runArgs).catch(vmerr => ({ vmerr }));
await vm.stateManager.revert();
const vmerr = result.vmerr;
if (vmerr) {
return callback(vmerr);
Expand Down
77 changes: 58 additions & 19 deletions src/chains/ethereum/ethereum/tests/forking/forking.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -504,25 +504,27 @@ describe("forking", function () {
}

function set(provider: EthereumProvider, key: number, value: number) {
const encodedKey = Quantity.from(key)
.toBuffer()
.toString("hex")
.padStart(64, "0");
const encodedValue = Quantity.from(value)
.toBuffer()
.toString("hex")
.padStart(64, "0");

return provider.send("eth_sendTransaction", [
{
from: remoteAccounts[0],
to: contractAddress,
data: `0x${
methods[`setValueFor(uint8,uint256)`]
}${encodedKey}${encodedValue}`,
gas: `0x${(3141592).toString(16)}`
}
]);
const tx = makeTxForSet(key, value) as any;
tx.gas = `0x${(3141592).toString(16)}`;

return provider.send("eth_sendTransaction", [tx]);
}

function encodeValue(val: number) {
return Quantity.from(val).toBuffer().toString("hex").padStart(64, "0");
}

function makeTxForSet(key: number, value: number) {
const encodedKey = encodeValue(key);
const encodedValue = encodeValue(value);

return {
from: remoteAccounts[0],
to: contractAddress,
data: `0x${
methods[`setValueFor(uint8,uint256)`]
}${encodedKey}${encodedValue}`
};
}

async function getBlockNumber(provider: EthereumProvider) {
Expand Down Expand Up @@ -930,6 +932,43 @@ describe("forking", function () {
}
}
});

describe("gas estimation", () => {
it("should not affect live state", async () => {
const { localProvider } = await startLocalChain(PORT, {
disableCache: true
});
const blockNum = await getBlockNumber(localProvider);

// calling eth_estimateGas shouldn't change actual state, which is `2`
const expectedValue = 2;
const testValue = 0;
assert.strictEqual(
testValue,
0,
"the test value must be 0 in order to make sure the change doesn't get stuck in the delete cache"
);
const actualValueBefore = parseInt(
await get(localProvider, "value1", blockNum)
);
assert.strictEqual(actualValueBefore, expectedValue);

// make a tx that sets a value 1 to 0, we'll only use this for gas
// estimation
const tx = makeTxForSet(1, testValue);
const est = await localProvider.request({
method: "eth_estimateGas",
params: [tx]
});
assert.notStrictEqual(est, "0x");

// make sure the call to eth_estimateGas didn't change anything!
const actualValueAfter = parseInt(
await get(localProvider, "value1", blockNum)
);
assert.strictEqual(actualValueAfter, expectedValue);
});
});
});

describe("blocks", () => {
Expand Down