Browse Source

doc: describe the FeeV1 mandatory burn model

brid 9 hours ago
parent
commit
e2c29f3308
1 changed files with 106 additions and 7 deletions
  1. 106 7
      doc/src/arch/fees.md

+ 106 - 7
doc/src/arch/fees.md

@@ -13,7 +13,8 @@ pub struct GasData {
 }
 ```
 
-Total gas is their saturating sum, and the fee is `gas / 100`:
+Total gas is their saturating sum. The minimum fee for a transaction is
+`total_gas * FEE_PER_GAS`, and a mandatory fraction of it is burned:
 
 ```rust
 pub fn total_gas_used(&self) -> u64 {
@@ -23,11 +24,106 @@ pub fn total_gas_used(&self) -> u64 {
         .saturating_add(self.deployments)
 }
 
-pub fn compute_fee(gas: &u64) -> u64 {
-    gas / 100
+pub fn minimum_fee(gas: u64) -> FeeResult<u64> {
+    gas.checked_mul(FEE_PER_GAS).ok_or(FeeError::ArithmeticOverflow)
 }
+
+pub fn burn_fee(minimum_fee: u64) -> FeeResult<u64> {
+    let burned =
+        (minimum_fee as u128).checked_mul(BURN_NUM as u128).ok_or(FeeError::ArithmeticOverflow)?
+            / BURN_DEN as u128;
+
+    u64::try_from(burned).map_err(|_| FeeError::ArithmeticOverflow)
+}
+```
+
+# Fee burning
+
+Fee pricing uses one fixed set of consensus constants. For a fee-paying
+transaction with final measured gas `g`, paid fee `paid`, and declared
+burned fee `burned`:
+
+```
+base_fee(g)      = g * FEE_PER_GAS
+burn_fee(g)      = floor(base_fee(g) * BURN_NUM / BURN_DEN)
+inclusion_fee(g) = base_fee(g) - burn_fee(g)
+tip_fee          = paid - base_fee(g)
+```
+
+| Constant     | Value | Description                       |
+|--------------|-------|-----------------------------------|
+| `FEE_PER_GAS`| 5     | Fee per gas unit                  |
+| `BURN_NUM`   | 3     | Mandatory burn ratio numerator    |
+| `BURN_DEN`   | 4     | Mandatory burn ratio denominator  |
+
+This sets the minimum fee to `5 * gas`, burns 75% of it before
+per-transaction rounding, and pays the remainder to the miner. Any
+payment above the minimum is an implicit miner tip; there is no
+separate priority-tip field.
+
+`paid` and `burned` are public values in the `Money::FeeV1` calldata:
+
+```
+[function_id][paid_fee][burned_fee][params]
+```
+
+The transaction is valid only if:
+
+```
+paid   >= base_fee(g)
+burned >= burn_fee(base_fee(g))
+burned <= paid
 ```
 
+The burn is enforced as a mandatory floor rather than an exact value.
+Builders cannot predict final gas exactly, since the fee call's own gas
+usage depends on chain state (tree depths) and varies slightly between
+builds of the same transaction, so they estimate conservatively with
+`FEE_CALL_GAS` as an upper bound. Under-declaring the burn below the
+mandatory amount is invalid. Over-declaring is valid and only burns
+more of the builder's own value, reducing the miner-claimable amount;
+no value can be forged.
+
+Overpayment is settled against the fee values the transaction declares,
+not against what the chain actually required. The miner always receives
+`paid - burned`:
+
+* A deliberate tip above the builder's own estimated minimum raises
+  `paid` only, so it goes entirely to the miner.
+* Estimation error raises `paid` and the declared `burned` together,
+  since the burn is declared from the estimate while the floor is
+  enforced from the actual requirement. Over-estimated gas therefore
+  splits the slack: 75% is burned and 25% accrues to the miner's
+  inclusion fee. Under-estimation makes the transaction invalid.
+
+| Extra payment from…                | Burned | Miner |
+|------------------------------------|--------|-------|
+| a deliberate tip over the estimate | 0%     | 100%  |
+| estimation slack over actual gas   | 75%    | 25%   |
+
+Fee interpretation is split between the contract and the validator:
+the contract handles public numbers and money accounting, while the
+validator binds those numbers to runtime facts. `Money::FeeV1` checks
+the native-token fee spend and value conservation
+(`input_value = output_value + paid`, `paid > 0`, `burned <= paid`) and
+owns the height fee accumulator:
+
+```
+fees[h] = checked_add(fees[h], paid - burned)
+```
+
+There is no separate burn accumulator. Burning is represented by the
+fee spend not being fully re-minted: the `PoWRewardV1` transaction
+mints exactly `expected_reward(h) + fees[h]`, and the burned amount is
+absent from it.
+
+After final gas is known, validator verification requires exactly one
+well-formed `Money::FeeV1` call, checks the validity conditions above,
+and rejects malformed fee calldata fallibly instead of panicking. All
+fee arithmetic uses checked intermediates; overflow makes the
+transaction or block invalid. Fee verification can be disabled only as
+an explicit test/development mode.
+
 # Fee metering
 
 ## WASM opcodes
@@ -157,7 +253,7 @@ gas which includes the fee call itself. It is therefore covered by a
 fixed constant added to the base gas:
 
 ```
-fee = (base_tx_gas + FEE_CALL_GAS) / 100
+fee = minimum_fee(base_tx_gas + FEE_CALL_GAS)
 ```
 
 `FEE_CALL_GAS = 42_000_000` is intentionally conservative. The actual
@@ -169,7 +265,10 @@ This data-dependent variation (~+/-70K gas across runs) means no single
 constant can be exact. The 42M value provides ~24% headroom over the
 observed maximum, ensuring the estimate always covers the real overhead
 without requiring per-transaction recalibration or risking intermittent
-fee-shortfall failures.
+fee-shortfall failures. Since the mandatory burn is enforced as a
+floor, over-estimation keeps transactions valid; if the fee call ever
+outgrows the constant, fee verification rejects transactions loudly and
+the constant has to be bumped.
 
 # Gas limits
 
@@ -213,8 +312,8 @@ operation. Gas scales linearly with inputs (~4.35M each) and outputs
 
 # TODO
 
-* Implement fee burning contracts and algorithm.
-* Implement the gas to DRK conversion algorithm + priority tip.
+* Revisit adaptive fee pricing or fee periods (explicit priority tips
+  were dropped in favor of implicit tips from overpayment).
 * Re-derive fee constants on target validator architecture. The current
   ratios are calibrated on a single x86-64 machine and are approximate.
 * Finalize security budget (fees in the context of block rewards).