`doVoting` built the three gas votes unconditionally. Before the amendment,
the ledger reports zero for all three while the config targets are non-zero by
default, and the loop that collects validator votes is itself gated on the
amendment — so the vote map held only our own target and every one of the
three reported a change.
The result was a `SetFee` pseudo-transaction on every flag ledger, from every
node running this build, for as long as the amendment stayed disabled. The
transaction carried no gas fields, since that part was gated correctly, so it
proposed no change at all.
Gate the three flags on the amendment, matching `doValidation`, which already
had its gas votes inside the same check.
Reported by xrplf-ai-reviewer on #8214.
`FeeSetup::toFees()` returned the three-argument `Fees`, leaving `gasLimit`,
`bytecodeSizeLimit` and `gasPrice` at zero. `startGenesisLedger` passes that
straight into the genesis `Ledger`, which is where those three are written to
the `FeeSettings` entry — so a network started fresh with `featureSmartEscrow`
in its initial amendment set got a gas limit of zero, i.e. Smart Escrow
switched off no matter what the operator configured.
Carrying them through `toFees()` alone is not enough. Every `Ledger` built
from stored data is seeded with the same `Fees`, and `Ledger::setup()` only
overwrites the fields the `FeeSettings` entry actually carries. A ledger from
before the amendment carries none, so the seed would survive and the node
would read its own configuration back as though the network had agreed to it —
and then never vote for the values it wants, because `doValidation` only votes
when the current setting differs from the target.
So the genesis constructor now clears the three whenever it does not write
them. A ledger reports what its `FeeSettings` entry holds, and nothing more.
Reported by depthfirst-app and Copilot on #8214.
Add `GasLimit`, `BytecodeSizeLimit`, and `GasPrice` to the network's votable
fee settings, gated on `featureSmartEscrow`.
The `.macro` and autogen plumbing for these fields landed in #8157; this adds
the behavior behind them: config parsing, fee voting, the `SetFee` pseudo-
transaction, `FeeSettings` genesis and load, and the RPC surfaces that report
fee settings.
`detail::VotableValue` in FeeVoteImpl.cpp becomes a template, since the three
new settings are `std::uint32_t` rather than `XRPAmount`.
`ServiceRegistry::getFees()` exposes the configured settings to code that has
no `ReadView`. It has no production caller yet; the Smart Escrow transactors
call it from `preflight`.