PLT-465: wire key/size/op distributions into StorageRW (rebased on main) - #58
PLT-465: wire key/size/op distributions into StorageRW (rebased on main)#58bdchatham wants to merge 1 commit into
Conversation
…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>
PR SummaryMedium Risk Overview Scenario config gains 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. |
|
Closing — driving this through #54 instead. The rebased content lands there via a merge from main. |
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.Randthreaded per call —SampleIndex(rng, n),GenerateGas(rng).utils/rngis gone from main.This branch adapts to that model rather than restoring the deleted package:
OperationMix.Select(rng)takes the RNG as a parameter, matchingDistribution/GasPicker.pickSlot/pickPad/pickOptake the RNG thatCreateContractTransactionalready receives.What it does (
generator/scenarios/StorageRW.go)Each tx draws slot from
KeyDistributionoverRecordCount, pad length fromSizeDistributionoverSizeBuckets, and method fromOperations. 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 besideValidateFunding.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
gofmtclean ·go vetclean ·golangci-lint run0 issues ·go test -race ./...all packages ok