Skip to content

Commit bed6532

Browse files
committed
Check contract account's nonce directly (#1402)
1 parent b389334 commit bed6532

1 file changed

Lines changed: 28 additions & 9 deletions

File tree

utils/e2e-tests/ts/tests/eth/preserveNonceOnZeroContractBalance.ts

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { describe, it, expect, assert } from "vitest";
22
import { RunNodeState, runNode } from "../../lib/node";
33
import * as eth from "../../lib/ethViem";
4-
import contractsFactory from "../../lib/abis/deposit";
4+
import deposit from "../../lib/abis/deposit";
55
import "../../lib/expect";
66
import { beforeEachWithCleanup } from "../../lib/lifecycle";
77

@@ -18,12 +18,13 @@ describe("contract account's nonce", () => {
1818
devClients = eth.devClientsFromNodeWebSocket(node, cleanup.push);
1919
}, 60 * 1000);
2020

21+
// See also: https://github.com/humanode-network/humanode/issues/1402
2122
it("is being preserved after zeroing the balance", async () => {
2223
const [alice, _] = devClients;
2324

2425
const deployContractTxHash = await alice.deployContract({
25-
abi: contractsFactory.abi,
26-
bytecode: contractsFactory.bytecode,
26+
abi: deposit.abi,
27+
bytecode: deposit.bytecode,
2728
value: 1n, // Even the smallest deposit is enough
2829
gas: 150_274n,
2930
});
@@ -33,20 +34,38 @@ describe("contract account's nonce", () => {
3334
timeout: 18_000,
3435
});
3536
expect(deployContractTxReceipt.status).toBe("success");
36-
const factoryAddress = deployContractTxReceipt.contractAddress;
37-
assert(factoryAddress);
37+
const contract = deployContractTxReceipt.contractAddress;
38+
assert(contract);
3839

39-
// If there's a bug in the EVM, it will clear the contract state after `withdrawAll`.
40+
// The nonce of the contract account immediately after creation.
41+
const INITIAL_NONCE = 1;
42+
43+
// EIP-161 https://eips.ethereum.org/EIPS/eip-161:
44+
//
45+
// > At the end of the transaction, any account touched by ... that transaction which is now *empty*
46+
// > SHALL instead become non-existent (i.e. deleted).
47+
// > Where: ...
48+
// > An account is considered *empty* when it has no code and zero nonce and zero balance.
49+
//
50+
// So once the balance is zeroed below, the account state shouldn't be deleted because
51+
// the account contains the contract code.
4052
const withdrawalTx = await alice.writeContract({
41-
address: factoryAddress,
42-
abi: contractsFactory.abi,
53+
address: contract,
54+
abi: deposit.abi,
4355
functionName: "withdrawAll",
4456
gas: 30_585n,
4557
});
4658
const withdrawalReceipt = await publicClient.waitForTransactionReceipt({
4759
hash: withdrawalTx,
4860
timeout: 18_000,
4961
});
50-
expect(withdrawalReceipt.status).toBe("success");
62+
expect(withdrawalReceipt.status, "status of withdrawal").toBe("success");
63+
64+
// Ethereum RPC returns the account nonce in the `eth_getTransactionCount` RPC call.
65+
// https://github.com/humanode-network/frontier/blob/1afab28e8d5aebe7d44f9043b3ba19e9555123dc/client/rpc/src/eth/state.rs#L116-L169
66+
const nonce = await publicClient.getTransactionCount({
67+
address: contract,
68+
});
69+
expect(nonce).toBe(INITIAL_NONCE);
5170
});
5271
});

0 commit comments

Comments
 (0)