Summary
FEE_VERSION2 (packages/rs-platform-version/src/version/fee/v2.rs) declares fee_version_number: 1, the same number as FEE_VERSION1, and is absent from FEE_VERSIONS (fee/mod.rs). FeeVersion::get(1) therefore always returns FEE_VERSION1, even for epochs that ran on FEE_VERSION2 (protocol v9 and later).
Why it matters
Only the fee version number is persisted for previous epochs:
Both round trips silently substitute FEE_VERSION1 for FEE_VERSION2. It is latent today only because the two schedules have identical storage fees, and previous_fee_versions is consulted solely to price storage refunds (rs-drive/src/fees/op.rs). The first FeeVersion that changes a storage or processing fee without taking a distinct number turns this into a consensus fork between nodes that restarted (or state-synced) and nodes that did not.
Fix
Give FEE_VERSION2 its own number (2) and add it to FEE_VERSIONS at index 1. That changes what a restarted or state-synced node computes for old epochs, so it is protocol-visible and needs a versioned migration rather than an in-place edit.
The #[ignore]d test fee_version_numbers_are_unique_and_resolvable in fee/mod.rs pins the defect; un-ignore it with the fix.
Rule going forward
Every FeeVersion constant needs a unique fee_version_number and an entry in FEE_VERSIONS at the index that number implies.
Summary
FEE_VERSION2(packages/rs-platform-version/src/version/fee/v2.rs) declaresfee_version_number: 1, the same number asFEE_VERSION1, and is absent fromFEE_VERSIONS(fee/mod.rs).FeeVersion::get(1)therefore always returnsFEE_VERSION1, even for epochs that ran onFEE_VERSION2(protocol v9 and later).Why it matters
Only the fee version number is persisted for previous epochs:
PlatformStateForSavingV1storesprevious_fee_versionsasepoch index -> fee_version_number(aux storage, rehydrated on every restart).ReducedPlatformStateV0(state sync, feat(drive-abci): state sync via ABCI snapshots with reduced platform state (protocol v15) #4520) stores the same map in the replicated Misc tree and rehydrates it on a state-synced node.Both round trips silently substitute
FEE_VERSION1forFEE_VERSION2. It is latent today only because the two schedules have identicalstoragefees, andprevious_fee_versionsis consulted solely to price storage refunds (rs-drive/src/fees/op.rs). The firstFeeVersionthat changes a storage or processing fee without taking a distinct number turns this into a consensus fork between nodes that restarted (or state-synced) and nodes that did not.Fix
Give
FEE_VERSION2its own number (2) and add it toFEE_VERSIONSat index 1. That changes what a restarted or state-synced node computes for old epochs, so it is protocol-visible and needs a versioned migration rather than an in-place edit.The
#[ignore]d testfee_version_numbers_are_unique_and_resolvableinfee/mod.rspins the defect; un-ignore it with the fix.Rule going forward
Every
FeeVersionconstant needs a uniquefee_version_numberand an entry inFEE_VERSIONSat the index that number implies.