Developers Forum for XinFin XDC Network

Daniel Liu
Daniel Liu

Posted on

gas2500x test plan

Field test for the Gas2500x tier (625 gwei) shipped by three XDPoSChain
commits on dev-upgrade (baseline 5501a1f1e5, all three included):

  • 7823fc7f (#2516) — Gas2500xBlock fork: the pool floor, the chain default gas price and the EIP-1559 base fee move 12.5 gwei → 625 gwei, and --gasprice can no longer move the floor.
  • 68695806 (#2532) — on a floor rise the pool sweeps every non-special tx below the new floor from pending and queue; swept txs never come back.
  • 06582401 (#2541) — the local tracker holds back below-floor local txs and revives them when the floor drops; below-floor rejects never enter the tracker.

A test result: https://github.com/gzliudan/Local_DPoS_Setup/blob/gas2500x/results/gas2500x-20260905-182603.log

Test environment

  • OS: Ubuntu 24.04.4 LTS (Linux 7.0.0, x86_64)
  • bash: GNU bash 5.2.21
  • jq: jq 1.7
  • cast: foundry cast 1.8.1
  • curl: curl 8.5.0
  • Go: go 1.25.14 (builds the XDC binaries)

Quick start

cd ~/XDPoSChain
git use dev-upgrade
make all                            # once: XDC binaries

cd ~
git clone https://github.com/gzliudan/Local_DPoS_Setup/
cd Local_DPoS_Setup/
git use gas2500x
cp .env.sample .env                 # once: sender/node keys (S1–S5, P3)
# Fill the real keys in `.env`
./gas2500x-run.sh                   # reset → start network → 53 cases → stop
./stop-network.sh                   # only after an interrupted run
Enter fullscreen mode Exit fullscreen mode

Fill the real keys in .env — the three masternode keys
(PRIVATE_KEY_0/1/2) are bound to genesis.json: their addresses are the
masternodes baked into the genesis extraData (and funded in alloc),
so they must stay exactly as shipped; generating fresh keys here yields
a node that can never sign. PRIVATE_KEY_3 (observer pn3) and
TXGEN_KEY_1..5 (senders S1–S5) may be any funded-able raw hex keys.

The runner does the whole lifecycle itself — wipes the datadirs, starts the
network, runs every case, stops the network.

Topology

Node Role RPC Metrics
pn0 masternode, genesis signer 8545 6060
pn1 masternode, genesis signer 8546 6061
pn2 masternode, genesis signer 8547 6062
pn3 observer, non-signer 8548 6063

Masternodes keep sealing the whole run — 2/3 quorum is intact. All pool
cases submit via pn3, so tracker/journal state lands there and the rewind
experiment touches pn3 only.

Key numbers

  • Gas50x floor: 12.5 gwei
  • Gas2500x floor: 625 gwei
  • gas2500xBlock: 120
  • Tracker recheck: 10s after start, then every 60 s (locals.recheckInterval)

Test scripts

Local_DPoS_Setup/
├── gas2500x-run.sh          # the only entry point
├── gas2500x-test.md         # this document
├── results/
│   └── gas2500x-<ts>.log    # runner transcript (start/end tally inside)
└── tests/
    ├── gas2500x-lib.sh      # shared helpers
    ├── t01.sh … t23.sh      # pre-fork
    ├── t24.sh … t34.sh      # fork sweep
    ├── t35.sh … t42.sh      # post-fork probes
    ├── t43.sh … t45.sh      # rewind saga
    └── t46.sh … t53.sh      # creation matrix
Enter fullscreen mode Exit fullscreen mode

Test cases

53 cases, one verifiable result each. The fork (block 120) splits them into
mirrored pairs, one case per side (T02/T27 reject, T09/T29 at-floor seal,
T13/T32 replace, T21 parks / T30 seals the survivor, T15/T42 default price);
observation-only cases add no submissions (T10, T22, T24–T26, T34, T44,
T45); the survivor chain T21→T24→T30 and the rewind saga T43→T44→T45 are
fixed state chains (via /tmp markers); the creation matrix t46–t53 cases
are mutually independent. Missed the pre-fork window? Just re-run the runner
— it resets the chain.

One benign interference: every ~30 s each masternode broadcasts a consensus
signing tx (gasPrice 0) that transiently enters every pool as
executable-special for ~2 s. The pending-side assertions (T11, T12, T34,
T45) therefore count only non-signing txs (shape-based filter).

Out of scope (unit-test covered): TRC21/XDCx tier pricing, concurrent
TrackAll races, Osaka gas-cap discard, Gas2500xBlock == nil, special txs.

Case names are verb-object and paren-free. The table below is generated
from the scripts' begin_case args — regenerate it after renaming a case.

Case Name
T01 fund the senders
T02 reject a tx 1 wei below the pre-fork floor
T03 verify eth_gasPrice on the pre-fork tier
T04 verify eth_maxPriorityFeePerGas on the pre-fork tier
T05 verify the block baseFeePerGas on the pre-fork tier
T06 verify eth_estimateGas on the pre-fork tier
T07 reject a legacy creation below the pre-fork floor
T08 reject a 1559 creation below the pre-fork floor
T09 seal a tx at the pre-fork floor of 12.5 gwei
T10 verify the below-floor reject is not tracked
T11 seed 10 queued txs from S1
T12 seed 8 queued txs from S2
T13 replace a pre-fork queued tx at the same nonce
T14 verify txpool_contentFrom mirrors the pre-fork queue
T15 seal a tx at the pre-fork default gas price
T16 seal a legacy creation at the pre-fork floor
T17 seal a legacy creation above the pre-fork floor
T18 seal a 1559 creation at the pre-fork floor
T19 seal a tip-0 creation at the pre-fork base fee
T20 verify the journal load keeps the pre-fork replacement
T21 park a 700 gwei tx from S4 for the sweep
T22 verify the queued batch is not sealed
T23 verify sealing continuity across the fork
T24 verify the fork sweep empties the queue
T25 verify the sweep meter and drop log on pn3
T26 verify the sweep leaves a hold-back gauge
T27 reject a tx 1 wei below the post-fork floor
T28 reject a swept tx re-entering at the old price
T29 seal a tx at the post-fork floor of 625 gwei
T30 seal the parked 700 gwei tx above the new floor
T31 verify the post-fork reject is not tracked
T32 replace a post-fork queued tx at the same nonce
T33 verify the journal load keeps the new-tier replacement
T34 verify no tracker revival within the recheck
T35 verify effectiveGasPrice matches the block base fee on both tiers
T36 verify the --gasprice 1 knob is inert
T37 verify eth_gasPrice on the post-fork tier
T38 verify eth_maxPriorityFeePerGas on the post-fork tier
T39 verify the block baseFeePerGas on the post-fork tier
T40 verify txpool_contentFrom mirrors the post-fork queue
T41 verify eth_estimateGas on the post-fork tier
T42 seal a tx at the post-fork default gas price
T43 revive the held-back txs when the floor drops
T44 verify the re-cross sweep fires again
T45 verify the hold-back survives a restart
T46 reject a 1559 tx 1 wei below the post-fork floor
T47 reject a legacy creation below the post-fork floor
T48 reject a 1559 creation below the post-fork floor
T49 seal a legacy creation at the post-fork floor
T50 seal a legacy creation above the post-fork floor
T51 seal a 1559 creation at the post-fork floor
T52 seal a tip-0 creation at the post-fork base fee
T53 seal a 1559 tx at the post-fork floor

Discussion (0)