DEV Community

Cover image for Forklift: rehearse a Portaldot transaction on a fork, then send the same bytes
Edy Cu
Edy Cu

Posted on Edited on

Forklift: rehearse a Portaldot transaction on a fork, then send the same bytes

Your transaction runs twice. The first time is a rehearsal.

Forklift pins a Portaldot block, lifts the chain's real state at that block, forks it on your machine and checks the fork against the live chain key by key. Then forklift rehearse signs a transaction once, applies those exact bytes on the fork as the prediction, and with --send sends the same bytes to the V3 testnet and lists every field that differs.

Forklift architecture

What is measured on the V3 testnet

  • Lift at #118,061: 5,508 keys. verify --sample 200 exits 0: 200/200 draws identical, key set 5,508 = 5,508.
  • Rehearse: three real V3 transactions, each predicted on a fork first, then sent: 118555-1 System.remark, 118621-1 Balances.transfer_keep_alive, 118669-1 Utility.batch. Each had the same tx hash, success and event sequence as predicted, and the same recipient delta where there is one.
  • What differed: the fee-bearing event amounts, the fee (3,660 to 8,269 planck), the signer delta and the inclusion height. Forklift lists every one and exits 7, never a quiet fix.
  • Replay re-runs a V3 extrinsic on a fork of its parent block: 118555-1 10/10, 118621-1 14/14, 118669-1 16/16 fields equal.
  • Fork Receipt v2, a Revive contract on V3 at 0x52f0edd92af9ff410ca63ccc83735552e1b2abc7 (84 bytes): the emitted event and the stored receipt() equal the #118,061 manifest.

Mainnet, too

Three mainnet extrinsics replayed field-equal on a fork of their parent block (24/24, 25/25, 24/24). runtime-diff and migrate-report compare mainnet spec 1002 with V3: of a 16,324-key lift, 10,499 keys carry over, 5,443 re-encode and 382 have no home on V3.

Things I learned

  • A fee difference is not a bug, but it must be said. Each transaction landed a few blocks after its prediction, so the fee moved. Listing it, with an exit code, is more useful than hiding it.
  • Sampling is honest only if you say it is a sample. verify checks 200 random keys, not every key, and Forklift says so.

Honest limits

A V3 fork is Chopsticks, not a V3 node (no public V3 node binary exists). Forklift reads mainnet and V3; the only writes to a real chain are rehearse --send and receipt --target v3, and only to V3. The PyPI package is not published yet.

Links

324 offline tests and 10 live tests. Built for the Portaldot Hacker House 2026.

Top comments (0)