Skip to content

Commit

Permalink
Working toward supporting dynamic gas prices
Browse files Browse the repository at this point in the history
  • Loading branch information
HerbertJordan committed Nov 14, 2024
1 parent a8511ec commit 2ffc636
Show file tree
Hide file tree
Showing 9 changed files with 52 additions and 21 deletions.
1 change: 1 addition & 0 deletions evmcore/dummy_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ func ToEvmHeader(block *inter.Block, prevHash common.Hash, rules opera.Rules) *E
Root: block.StateRoot,
Number: big.NewInt(int64(block.Number)),
Time: block.Time,
Duration: time.Duration(block.Duration) * time.Nanosecond,
GasLimit: block.GasLimit,
GasUsed: block.GasUsed,
BaseFee: baseFee,
Expand Down
2 changes: 1 addition & 1 deletion gossip/apply_genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func (s *Store) ApplyGenesis(g genesis.Genesis) (err error) {
WithTime(evmcore.FakeGenesisTime-1). // TODO: extend genesis generator to provide time
WithGasLimit(gasLimit).
WithStateRoot(common.Hash{}). // TODO: get proper state root from genesis data
WithBaseFee(big.NewInt(0)). // TODO: set initial base fee according to the rules
WithBaseFee(gasprice.GetInitialBaseFee(rules.Economy)).
Build(),
)

Expand Down
6 changes: 3 additions & 3 deletions gossip/blockproc/evmmodule/evm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,15 @@ func TestEvm_IgnoresGasPriceOfInternalTransactions(t *testing.T) {
nil,
nil,
opera.Rules{
Blocks: opera.BlocksRules{
MaxBlockGas: 1e10,
},
Economy: opera.EconomyRules{
MinGasPrice: big.NewInt(12), // > than 0 offered by the internal transactions
},
Upgrades: opera.Upgrades{
London: true,
},
Blocks: opera.BlocksRules{
MaxBlockGas: 1e12,
},
},
&params.ChainConfig{
LondonBlock: big.NewInt(0),
Expand Down
5 changes: 4 additions & 1 deletion gossip/c_block_callbacks.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,13 +225,15 @@ func consensusCallbackBeginBlockFn(
number := uint64(blockCtx.Idx)
lastBlockHeader := evmStateReader.GetHeaderByNumber(number - 1)
maxBlockGas := es.Rules.Blocks.MaxBlockGas
blockDuration := time.Duration(blockCtx.Time - bs.LastBlock.Time)
blockBuilder := inter.NewBlockBuilder().
WithEpoch(es.Epoch).
WithNumber(number).
WithParentHash(lastBlockHeader.Hash).
WithTime(blockCtx.Time).
WithPrevRandao(prevRandao).
WithGasLimit(maxBlockGas)
WithGasLimit(maxBlockGas).
WithDuration(blockDuration)

for i := range preInternalTxs {
blockBuilder.AddTransaction(
Expand Down Expand Up @@ -343,6 +345,7 @@ func consensusCallbackBeginBlockFn(

block := blockBuilder.Build()
evmBlock.Hash = block.Hash()
evmBlock.Duration = blockDuration

for _, tx := range blockBuilder.GetTransactions() {
store.evm.SetTx(tx.Hash(), tx)
Expand Down
4 changes: 2 additions & 2 deletions gossip/c_llr_callbacks.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ func (s *Store) WriteFullBlockRecord(baseFee *big.Int, blobGasPrice *big.Int, ga
WithGasLimit(gasLimit).
WithGasUsed(br.GasUsed).
WithBaseFee(baseFee).
WithPrevRandao(common.Hash{1})
// TODO: add duration
WithPrevRandao(common.Hash{1}).
WithDuration(duration)

for i := range br.Txs {
copy := types.Receipt(*br.Receipts[i])
Expand Down
8 changes: 4 additions & 4 deletions gossip/gasprice/base_fee.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,17 @@ func GetInitialBaseFee(rules opera.EconomyRules) *big.Int {
// no minimum gas price is set in the rules.
const defaultInitialBaseFee = 1e9
fee := big.NewInt(defaultInitialBaseFee)
if rules.MinGasPrice != nil && rules.MinGasPrice.Cmp(fee) > 0 {
fee = new(big.Int).Set(rules.MinGasPrice)
if rules.MinBaseFee != nil && rules.MinBaseFee.Cmp(fee) > 0 {
fee = new(big.Int).Set(rules.MinBaseFee)
}
return fee
}

// GetBaseFeeForNextBlock computes the base fee for the next block based on the parent block.
func GetBaseFeeForNextBlock(parent *evmcore.EvmHeader, rules opera.EconomyRules) *big.Int {
newPrice := getBaseFeeForNextBlock(parent, rules)
if rules.MinGasPrice != nil && newPrice.Cmp(rules.MinGasPrice) < 0 {
newPrice.Set(rules.MinGasPrice)
if rules.MinBaseFee != nil && newPrice.Cmp(rules.MinBaseFee) < 0 {
newPrice.Set(rules.MinBaseFee)
}
return newPrice
}
Expand Down
8 changes: 4 additions & 4 deletions gossip/gasprice/base_fee_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,22 +276,22 @@ func TestBaseFee_DecayTimeFromInitialToZeroIsApproximately35Minutes(t *testing.T
}
}

func TestBaseFee_InitialPriceIsAtLeastMinGasPrice(t *testing.T) {
func TestBaseFee_InitialPriceIsAtLeastMinBaseFee(t *testing.T) {
for _, minPrice := range []int64{-1, 0, 1, 1e8, 1e9, 1e10, 1e12} {
rules := opera.EconomyRules{MinGasPrice: big.NewInt(int64(minPrice))}
rules := opera.EconomyRules{MinBaseFee: big.NewInt(int64(minPrice))}
got := GetInitialBaseFee(rules).Int64()
if got < minPrice {
t.Errorf("initial price is below min gas price; got %d, min %d", got, minPrice)
}
}
}

func TestBaseFee_DoesNotSinkBelowMinGasPrice(t *testing.T) {
func TestBaseFee_DoesNotSinkBelowMinBaseFee(t *testing.T) {
for _, minPrice := range []int64{-1, 0, 1, 1e8, 1e9, 1e10} {
t.Run(fmt.Sprintf("minPrice=%d", minPrice), func(t *testing.T) {
minPrice := big.NewInt(minPrice)
rules := opera.EconomyRules{
MinGasPrice: minPrice,
MinBaseFee: minPrice,
ShortGasPower: opera.GasPowerRules{
AllocPerSec: 1e6,
},
Expand Down
20 changes: 19 additions & 1 deletion inter/block.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package inter

import (
"encoding/binary"
"math/big"
"slices"
"time"
"unsafe"

"github.com/Fantom-foundation/lachesis-base/inter/idx"
Expand Down Expand Up @@ -43,6 +45,10 @@ type Block struct {
// Fields required for linking the block internally to a lachesis epoch.
Epoch idx.Epoch

// The duration of this block, being the difference between the predecessor
// block's timestamp and this block's timestamp, in nanoseconds.
Duration uint64

// The hash of this block, cached on first access.
hash common.Hash
}
Expand All @@ -57,6 +63,10 @@ func (b *Block) Hash() common.Hash {

// GetEthereumHeader returns the Ethereum header corresponding to this block.
func (b *Block) GetEthereumHeader() *types.Header {
// TODO: consider condensing the extra data into a single 8-byte field.
extra := make([]byte, 16)
binary.BigEndian.PutUint64(extra[:8], uint64(b.Time)) // < only nano-second part needed
binary.BigEndian.PutUint64(extra[8:], uint64(b.Duration)) // < could be measured in microseconds instead of nanoseconds
return &types.Header{
ParentHash: b.ParentHash,
UncleHash: types.EmptyUncleHash,
Expand All @@ -70,7 +80,7 @@ func (b *Block) GetEthereumHeader() *types.Header {
GasLimit: b.GasLimit,
GasUsed: b.GasUsed,
Time: uint64(b.Time.Time().Unix()),
Extra: nil, // TODO: fill in extra data required for gas computation
Extra: extra,
MixDigest: b.PrevRandao,
Nonce: types.BlockNonce{}, // constant 0 in Ethereum
BaseFee: b.BaseFee,
Expand Down Expand Up @@ -137,6 +147,14 @@ func (b *BlockBuilder) WithTime(time Timestamp) *BlockBuilder {
return b
}

func (b *BlockBuilder) WithDuration(duration time.Duration) *BlockBuilder {
if duration < 0 {
duration = 0
}
b.block.Duration = uint64(duration.Nanoseconds())
return b
}

func (b *BlockBuilder) WithDifficulty(difficulty uint64) *BlockBuilder {
b.block.Difficulty = difficulty
return b
Expand Down
19 changes: 14 additions & 5 deletions opera/rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,14 +135,22 @@ type EconomyRules struct {
// based on load observed during an epoch. Base fees charged
// on the network correspond exactly to the MinGasPrice.
//
// On the Sonic network: MinGasPrice is the lower boundary for
// the gas price automatically adjusted by the network based
// on the consumed gas on a block basis. The actual base fees in
// blocks are at least equal to the MinGasPrice or higher.
// On the Sonic network: this parameter is ignored. Base fees
// are controlled by the MinBaseFee parameter.
MinGasPrice *big.Int

// MinBaseFee is a lower bound for the base fee on the network.
// This option is only supported by the Sonic network. On the
// Fantom network it is ignored.
//
// On the Sonic network, base fees are automatically adjusted
// after each block based on the observed gas consumption rate.
// The value set by this parameter is a lower bound for these
// adjustments. Base fees may never fall below this value.
// Adjustments are made dynamically analogous to EIP-1559.
// See https://eips.ethereum.org/EIPS/eip-1559 and https://t.ly/BKrcr
// for additional information.
MinGasPrice *big.Int
MinBaseFee *big.Int

ShortGasPower GasPowerRules
LongGasPower GasPowerRules
Expand Down Expand Up @@ -275,6 +283,7 @@ func DefaultEconomyRules() EconomyRules {
BlockMissedSlack: 50,
Gas: DefaultGasRules(),
MinGasPrice: big.NewInt(1e9),
MinBaseFee: big.NewInt(1e3),
ShortGasPower: DefaultShortGasPowerRules(),
LongGasPower: DefaulLongGasPowerRules(),
}
Expand Down

0 comments on commit 2ffc636

Please sign in to comment.