Skip to content

test(postage): prove chain-state buffering equivalence (#5343)#5481

Draft
martinconic wants to merge 1 commit into
masterfrom
test-chainstate-buffering-equivalence-5343
Draft

test(postage): prove chain-state buffering equivalence (#5343)#5481
martinconic wants to merge 1 commit into
masterfrom
test-chainstate-buffering-equivalence-5343

Conversation

@martinconic
Copy link
Copy Markdown
Contributor

@martinconic martinconic commented May 29, 2026

Checklist

  • I have read the coding guide.
  • My change requires a documentation update, and I have done it.
  • I have added tests to cover my changes.
  • I have filled out the description and linked the related issues.

Summary

Test-only PR. Adds regression coverage for #5343 (postage batch snapshot optimization), which is already merged and on production.

#5343 changed batchservice so that UpdatePrice / UpdateBlockNumber no longer call storer.PutChainStateper event. Instead the chain state is buffered inpendingChainState(set inTransactionStart) and flushed once per page at TransactionEnd. PutChainStateis what runscleanup(evict expired batches) andcomputeRadius`.

A concern was raised: can the price fluctuate up/down within a window such that we skip PutChainState, and therefore skip cleanup / radius change?

These tests demonstrate the deferral is safe. PutChainState is not skipped — it is batched to once per page — and the final result is identical to the old per-event behaviour because:

  • TotalAmount is monotonically non-decreasing, so a single cleanup at the end of a window evicts the same superset;
  • computeRadius is a pure function of the final batch set and depths (Create/TopUp/UpdateDepth recompute it immediately, never deferred);
  • pendingChainState aliases the batchstore's in-memory chain state, so mid-window batch operations still observe the accrued amount.

What the tests do

Each test replays one identical event stream three ways against three independent real batchstores and asserts the final batch set, radius and chain state are byte-for-byte identical:

  • per-event — no transaction; every update persists immediately (pre-feat: optimize postage batch snapshot #5343 behaviour, the reference)

  • single-tx — whole stream buffered, a single flush at the end

  • per-page — one flush per page at TransactionEnd (feat: optimize postage batch snapshot #5343 behaviour)

  • TestChainStateBufferingEquivalence — deterministic; exercises Create, TopUp, UpdateDepth and UpdatePrice (price up 1→10 then down 10→2), evicting two batches while a third (topped up and diluted) survives and drives the final radius. Includes guards so the scenario can't silently become vacuous.

  • TestChainStateBufferingEquivalenceRandomized — seeded fuzz (40 iterations) over random prices, top-ups, depth changes and random page boundaries. Top-ups/depth changes target only "permanent" batches whose value exceeds any reachable TotalAmount, so they're valid in all modes regardless of how flush timing shifts ephemeral evictions.

The tests use the real batchstore on an in-memory leveldb state store. The map-backed mock state store can't be used: it iterates in random order, which breaks cleanup's value-ordered early-stop and yields non-deterministic evictions.

Validation

  • Deterministic test + all 40 randomized iterations pass
  • go test ./pkg/postage/batchservice/... passes, including under -race
  • go vet clean, gofumpt-formatted
  • Confirmed load-bearing: temporarily making TransactionEnd skip the flush made the buffered modes diverge (3 surviving batches / radius 5 vs. the correct 1 / radius 3), and the tests caught it

AI Disclosure

  • This PR contains code that has been generated by an LLM.
  • I have reviewed the AI generated code thoroughly.
  • I possess the technical expertise to responsibly review the code generated in this PR.

@martinconic martinconic marked this pull request as draft May 29, 2026 12:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant