Skip to content

PLT-465: wire key/size/op distributions into StorageRW (rebased on main) - #58

Closed
bdchatham wants to merge 1 commit into
mainfrom
brandon2/plt-465-rebased
Closed

PLT-465: wire key/size/op distributions into StorageRW (rebased on main)#58
bdchatham wants to merge 1 commit into
mainfrom
brandon2/plt-465-rebased

Conversation

@bdchatham

Copy link
Copy Markdown
Contributor

Supersedes #54, which branched before the generator rewrite (890ce1e, #56) and cannot be rebased mechanically. Same feature, adapted to main's RNG model. #54 to be closed on merge.

What changed vs #54

The rewrite replaced named per-axis PRNG sub-streams (utils/rng, SetStream) with a single *mrand.Rand threaded per call — SampleIndex(rng, n), GenerateGas(rng). utils/rng is gone from main.

This branch adapts to that model rather than restoring the deleted package:

  • OperationMix.Select(rng) takes the RNG as a parameter, matching Distribution/GasPicker.
  • pickSlot/pickPad/pickOp take the RNG that CreateContractTransaction already receives.
  • The two axis-independence tests are dropped. They guarded a property main no longer provides; leaving them would assert something untrue. Tracked as PLT-1023 under a later milestone.

What it does (generator/scenarios/StorageRW.go)

Each tx draws slot from KeyDistribution over RecordCount, pad length from SizeDistribution over SizeBuckets, and method from Operations. Draw order is fixed — slot, pad, operation — and documented, since one RNG is shared.

Pad gas is added as intrinsic EIP-2028 cost (4/byte) on top of the 50k base, so an empty pad is exactly the previous 50k and a large pad cannot underprovision.

Additive guarantee

Every axis is optional; every default reproduces prior behavior (fixed slot 0, empty pad, rmw). An unconfigured scenario draws no randomness — asserted by TestStorageRWDefaultPathUnchanged, which checks the RNG is left in lockstep with an untouched one at the same seed. So adding these fields cannot perturb an existing profile's workload.

Validation

Scenario.Validate() / LoadConfig.ValidateScenarios() reject a negative pad length (makeslice panic) or one over a 1 MiB cap (OOM) at load, wired into config load beside ValidateFunding.

Tests

Contention sweep at both ends, size-bucket histogram coverage with gas scaling, op-mix exclusivity and balance, weight-proportion convergence over 100k draws, seeded determinism, zero-randomness default, and omitempty round-trip. Assertions decode calldata through the binding's own ABI rather than byte offsets.

Verify

gofmt clean · go vet clean · golangci-lint run 0 issues · go test -race ./... all packages ok

…rageRW

StorageRW drew a fixed slot with an empty pad and always issued rmw. It now
draws all three per transaction from the scenario config: the slot from
KeyDistribution over a RecordCount keyspace, the pad length from
SizeDistribution over the SizeBuckets histogram, and the method from the
Operations mix. That turns contention into a continuum instead of a binary.

Every axis is optional and every default reproduces the previous behavior:
one fixed slot, empty pad, rmw. An unconfigured scenario draws no randomness,
so a profile that does not use these fields keeps its exact workload — guarded
by a test that asserts the RNG is left untouched.

The pad's intrinsic EIP-2028 calldata cost is added on top of the 50k base
limit, so an empty pad is exactly the previous 50k and a large pad cannot
underprovision the transaction.

Config gains RecordCount, SizeBuckets, and Operations, all omitempty. Scenario
validation rejects a negative or over-cap pad length at load rather than
panicking makeslice or OOMing on the hot path.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@cursor

cursor Bot commented Aug 20, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Changes the hot-path tx generator and load-config schema; defaults are preserved and validated, but misconfigured profiles now fail at load and configured ones change workload shape and gas.

Overview
StorageRW no longer emits a fixed slot-0 empty-pad rmw for every tx. Each transaction now draws a storage slot from KeyDistribution over RecordCount, a calldata pad length from SizeDistribution over SizeBuckets, and read / write / rmw from Operations, using the shared per-call *mrand.Rand in fixed order (slot → pad → operation). Gas is 50k base plus 4 gas per pad byte so large pads cannot underprovision.

Scenario config gains recordCount, sizeBuckets, and operations (with new OperationMix.Select), plus Scenario.Validate / LoadConfig.ValidateScenarios at load time to reject negative or >1 MiB pad lengths. main loadConfig calls validation beside existing funding checks.

Unconfigured scenarios keep the old behavior and consume no RNG on the default path; docs and tests cover contention, size histogram, op mix, determinism, and JSON omitempty.

Reviewed by Cursor Bugbot for commit 8891ac4. Bugbot is set up for automated code reviews on this repo. Configure here.

@bdchatham

Copy link
Copy Markdown
Contributor Author

Closing — driving this through #54 instead. The rebased content lands there via a merge from main.

@bdchatham bdchatham closed this Aug 20, 2026
@bdchatham
bdchatham deleted the brandon2/plt-465-rebased branch August 20, 2026 02:35
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