github.com/klaytn/klaytn@v1.12.1/node/cn/gasprice/gasprice.go (about) 1 // Modifications Copyright 2018 The klaytn Authors 2 // Copyright 2016 The go-ethereum Authors 3 // This file is part of go-ethereum. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from eth/gasprice/gasprice.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package gasprice 22 23 import ( 24 "context" 25 "math/big" 26 "sync" 27 28 "github.com/klaytn/klaytn/blockchain/types" 29 "github.com/klaytn/klaytn/networks/rpc" 30 31 "github.com/klaytn/klaytn/common" 32 "github.com/klaytn/klaytn/params" 33 ) 34 35 var maxPrice = big.NewInt(500 * params.Ston) 36 37 type Config struct { 38 Blocks int 39 Percentile int 40 MaxHeaderHistory int 41 MaxBlockHistory int 42 Default *big.Int `toml:",omitempty"` 43 } 44 45 // OracleBackend includes all necessary background APIs for oracle. 46 type OracleBackend interface { 47 HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) 48 BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) 49 GetBlockReceipts(ctx context.Context, hash common.Hash) types.Receipts 50 ChainConfig() *params.ChainConfig 51 CurrentBlock() *types.Block 52 } 53 54 type TxPool interface { 55 GasPrice() *big.Int 56 } 57 58 // Oracle recommends gas prices based on the content of recent 59 // blocks. Suitable for both light and full clients. 60 type Oracle struct { 61 backend OracleBackend 62 lastHead common.Hash 63 lastPrice *big.Int 64 cacheLock sync.RWMutex 65 fetchLock sync.Mutex 66 txPool TxPool 67 68 checkBlocks, maxEmpty, maxBlocks int 69 percentile int 70 maxHeaderHistory, maxBlockHistory int 71 } 72 73 // NewOracle returns a new oracle. 74 func NewOracle(backend OracleBackend, params Config, txPool TxPool) *Oracle { 75 blocks := params.Blocks 76 if blocks < 1 { 77 blocks = 1 78 } 79 percent := params.Percentile 80 if percent < 0 { 81 percent = 0 82 } 83 if percent > 100 { 84 percent = 100 85 } 86 return &Oracle{ 87 backend: backend, 88 lastPrice: params.Default, 89 checkBlocks: blocks, 90 maxEmpty: blocks / 2, 91 maxBlocks: blocks * 5, 92 percentile: percent, 93 maxHeaderHistory: params.MaxHeaderHistory, 94 maxBlockHistory: params.MaxBlockHistory, 95 txPool: txPool, 96 } 97 } 98 99 // Tx gas price requirements has changed over the hardforks 100 // 101 // | Fork | gasPrice | maxFeePerGas | maxPriorityFeePerGas | 102 // |------------------ |----------------------------- |----------------------------- |----------------------------- | 103 // | Before EthTxType | must be fixed UnitPrice (1) | N/A (2) | N/A (2) | 104 // | After EthTxType | must be fixed UnitPrice (1) | must be fixed UnitPrice (3) | must be fixed UnitPrice (3) | 105 // | After Magma | BaseFee or higher (4) | BaseFee or higher (4) | Ignored (4) | 106 // 107 // (1) If tx.type != 2 && !rules.IsMagma: https://github.com/klaytn/klaytn/blob/v1.11.1/blockchain/tx_pool.go#L729 108 // (2) If tx.type == 2 && !rules.IsEthTxType: https://github.com/klaytn/klaytn/blob/v1.11.1/blockchain/tx_pool.go#L670 109 // (3) If tx.type == 2 && !rules.IsMagma: https://github.com/klaytn/klaytn/blob/v1.11.1/blockchain/tx_pool.go#L710 110 // (4) If tx.type == 2 && rules.IsMagma: https://github.com/klaytn/klaytn/blob/v1.11.1/blockchain/tx_pool.go#L703 111 // 112 // The suggested prices needs to match the requirements. 113 // 114 // | Fork | SuggestPrice (for gasPrice and maxFeePerGas) | SuggestTipCap (for maxPriorityFeePerGas) | 115 // |------------------ |------------------------------------------------------------ |----------------------------- | 116 // | Before Magma | Fixed UnitPrice | Fixed UnitPrice | 117 // | After Magma | BaseFee * 2 | Zero | 118 119 // SuggestPrice returns the recommended gas price. 120 // This value is intended to be used as gasPrice or maxFeePerGas. 121 func (gpo *Oracle) SuggestPrice(ctx context.Context) (*big.Int, error) { 122 if gpo.txPool == nil { 123 // If txpool is not set, just return 0. This is used for testing. 124 return common.Big0, nil 125 } 126 127 nextNum := new(big.Int).Add(gpo.backend.CurrentBlock().Number(), common.Big1) 128 if gpo.backend.ChainConfig().IsMagmaForkEnabled(nextNum) { 129 // After Magma, return the twice of BaseFee as a buffer. 130 baseFee := gpo.txPool.GasPrice() 131 return new(big.Int).Mul(baseFee, common.Big2), nil 132 } else { 133 // Before Magma, return the fixed UnitPrice. 134 unitPrice := gpo.txPool.GasPrice() 135 return unitPrice, nil 136 } 137 } 138 139 // SuggestTipCap returns the recommended gas tip cap. 140 // This value is intended to be used as maxPriorityFeePerGas. 141 // Though Klaytn does not recognize gas tip, this function returns some value for compatibility. 142 func (gpo *Oracle) SuggestTipCap(ctx context.Context) (*big.Int, error) { 143 if gpo.txPool == nil { 144 // If txpool is not set, just return 0. This is used for testing. 145 return common.Big0, nil 146 } 147 148 nextNum := new(big.Int).Add(gpo.backend.CurrentBlock().Number(), common.Big1) 149 if gpo.backend.ChainConfig().IsMagmaForkEnabled(nextNum) { 150 // After Magma, return zero 151 return common.Big0, nil 152 } else { 153 // Before Magma, return the fixed UnitPrice. 154 unitPrice := gpo.txPool.GasPrice() 155 return unitPrice, nil 156 } 157 }