Field test for the Gas2500x tier (625 gwei) shipped by three XDPoSChain
commits on dev-upgrade (baseline 5501a1f1e5, all three included):
-
7823fc7f(#2516) —Gas2500xBlockfork: the pool floor, the chain default gas price and the EIP-1559 base fee move 12.5 gwei → 625 gwei, and--gaspricecan 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
cast1.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
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
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)