diff --git a/x/feemarket/spec/01_concepts.md b/x/feemarket/spec/01_concepts.md new file mode 100644 index 000000000000..d81ab4d27aba --- /dev/null +++ b/x/feemarket/spec/01_concepts.md @@ -0,0 +1,10 @@ + + +# Concepts + +Adopt EIP 1559 idea into cosmos-sdk. + +- Maintain a minimal gas prices in consensus, which is ajusted based on total gas used in the previous block. It's called base gas price, to distinguish with the `minimal-gas-prices` configured in each node. +- In checkTx context, the `minimal-gas-prices` are also repected if it's bigger than the consensus one. \ No newline at end of file diff --git a/x/feemarket/spec/02_state_transitions.md b/x/feemarket/spec/02_state_transitions.md new file mode 100644 index 000000000000..5da62052fff7 --- /dev/null +++ b/x/feemarket/spec/02_state_transitions.md @@ -0,0 +1,45 @@ + + +# State Transitions + +This document describes the state transition operations pertaining to the base gas prices. + +## Block Gas Used + +The total gas used by current block is stored in chain state at the `EndBlock` event. + +It's initialized to `-1` in `InitGenesis`. + +## Base Gas Prices + +### Init + +The base gas prices are initialized to the parameter `InitialBasePrices` in `InitGenesis` event. + +### Adjust + +Base gas prices are adjusted in the `EndBlock` event according to the total gas used in the previous block. + +```golang +parentGP := GetState(BaseGasPrices) +parentGasUsed := GetState(BlockGasUsed) + +var expectedGP sdk.Coins +if parentGasUsed == -1: + expectedGP = parentGP +else if parentGasUsed == params.BlockGasTarget: + expectedGP = parentGP +else if parentGasUsed > params.BlockGasTarget: + delta = parentGasUsed - params.BlockGasTarget + delta = max(parentBaseFee * delta / params.BlockGasTarget / params.BaseGasPriceChangeDenominator, 1) + expectedGP = parentBaseFee + delta +else: + delta = params.BlockGasTarget - parentGasUsed + delta = parentGP * delta / params.BlockGasTarget / params.BaseGasPriceChangeDenominator + expectedGP = parentGP - delta + +SetState(BaseGasPrices, expectedGP) +``` + diff --git a/x/feemarket/spec/03_antehandlers.md b/x/feemarket/spec/03_antehandlers.md new file mode 100644 index 000000000000..73e69de93a5e --- /dev/null +++ b/x/feemarket/spec/03_antehandlers.md @@ -0,0 +1,42 @@ + + +# AnteHandlers + +## Decorators + +### `MempoolFeeDecorator` + +The `MempoolFeeDecorator` in `x/auth` module should check the `BaseGasPrices` along with the `minimal-gas-prices`. + +```golang +gas := tx.GetGas() +baseGP := GetState(BaseGasPrices) +minGP := ctx.MinGasPrices() // it's zero in deliverTx context + +requiredFees := make(sdk.Coins, 0) +if baseGP.IsZero() { + // base gas prices are not enabled, check the minimal-gas-prices only + for i, gp := range minGasPrices { + fee := gp.Amount.Mul(gas).Ceil().RoundInt() + requiredFees = append(requiredFees, sdk.NewCoin(gp.Denom, fee)) + } +} else { + // check `tx.GetFee() > max(baseGP, minGP) * tx.GetGas()` + for i, gp := range baseGP { + fee := gp.Amount.Mul(gas).Ceil().RoundInt() + amt := minGasPrices.AmountOf(gp.Denom) + if amt > fee { + fee = amt + } + requiredFees = append(requiredFees, sdk.NewCoin(gp.Denom, fee)) + } +} + +feeCoins := tx.GetFee() +if !feeCoins.IsAnyGTE(requiredFees) { + return fmt.Errorf("insufficient fees; got: %s required: %s", feeCoins, requiredFees) +} +``` + diff --git a/x/feemarket/spec/04_end_block.md b/x/feemarket/spec/04_end_block.md new file mode 100644 index 000000000000..245ce619b7a0 --- /dev/null +++ b/x/feemarket/spec/04_end_block.md @@ -0,0 +1,9 @@ + + +# End-Block + +Each abci end block call, `x/feemarket` module adjust `BaseGasPrices` and record the `BlockGasUsed`. + +- [Adjust `BaseGasPrices`](02_state_transitions.md#base-gas-prices) +- [Record `BlockGasUsed`](#02_state_transitions.md#block-gas-used) \ No newline at end of file diff --git a/x/feemarket/spec/05_events.md b/x/feemarket/spec/05_events.md new file mode 100644 index 000000000000..705f77745cb9 --- /dev/null +++ b/x/feemarket/spec/05_events.md @@ -0,0 +1,14 @@ + + +# Events + +The `x/feemarket` module emits the following events: + +## EndBlocker + +| Type | Attribute Key | Attribute Value | +| ---------- | --------------- | --------------- | +| block_gas | height | {blockHeight} | +| block_gas | amount | {blockGasUsed} | +| fee_market | base_gas_prices | {baseGasPrices} | \ No newline at end of file diff --git a/x/feemarket/spec/06_params.md b/x/feemarket/spec/06_params.md new file mode 100644 index 000000000000..fe9e6fc8fc25 --- /dev/null +++ b/x/feemarket/spec/06_params.md @@ -0,0 +1,14 @@ + + +# Parameters + +The `x/feemarket` module contains the following parameters: + +| Key | Type | Example | +| ----------------------------- | ------ | ----------- | +| BlockGasTarget | uint32 | "2000000" | +| InitialBaseGasPrices | Coins | "1000uatom" | +| BaseGasPriceChangeDenominator | uint32 | 8 | + +- `BlockGasTarget`, should be smaller than `ConsensusParams.Block.MaxGas` if the latter one is specified. \ No newline at end of file diff --git a/x/feemarket/spec/README.md b/x/feemarket/spec/README.md new file mode 100644 index 000000000000..2e06cc8983f2 --- /dev/null +++ b/x/feemarket/spec/README.md @@ -0,0 +1,23 @@ + + +# `feemarket` + +## Abstract + +This document specifies the feemarket module of the Cosmos SDK. + +The feemarket module implements a base gas prices in consensus level. + +## Contents + +1. **[Concepts](01_concepts.md)** +2. **[State Transitions](02_state_transitions.md)** +3. **[Ante Handlers](03_antehandlers.md)** +4. **[End Block](04_end_block.md)** +5. **[Events](05_events.md)** +6. **[Params](06_params.md)** \ No newline at end of file