mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-15 17:30:44 +00:00
Merge pull request #732 from gzliudan/gas-price
eth/gasprice: fix wrong gas price with empty blocks
This commit is contained in:
commit
e8a9807be6
7 changed files with 91 additions and 93 deletions
|
|
@ -17,6 +17,7 @@
|
||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
@ -77,23 +78,44 @@ type Vote struct {
|
||||||
Voter Address
|
Voter Address
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BytesToHash sets b to hash.
|
||||||
|
// If b is larger than len(h), b will be cropped from the left.
|
||||||
func BytesToHash(b []byte) Hash {
|
func BytesToHash(b []byte) Hash {
|
||||||
var h Hash
|
var h Hash
|
||||||
h.SetBytes(b)
|
h.SetBytes(b)
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
func StringToHash(s string) Hash { return BytesToHash([]byte(s)) }
|
func StringToHash(s string) Hash { return BytesToHash([]byte(s)) }
|
||||||
func BigToHash(b *big.Int) Hash { return BytesToHash(b.Bytes()) }
|
|
||||||
|
// BigToHash sets byte representation of b to hash.
|
||||||
|
// If b is larger than len(h), b will be cropped from the left.
|
||||||
|
func BigToHash(b *big.Int) Hash { return BytesToHash(b.Bytes()) }
|
||||||
|
|
||||||
func Uint64ToHash(b uint64) Hash { return BytesToHash(new(big.Int).SetUint64(b).Bytes()) }
|
func Uint64ToHash(b uint64) Hash { return BytesToHash(new(big.Int).SetUint64(b).Bytes()) }
|
||||||
func HexToHash(s string) Hash { return BytesToHash(FromHex(s)) }
|
|
||||||
|
// HexToHash sets byte representation of s to hash.
|
||||||
|
// If b is larger than len(h), b will be cropped from the left.
|
||||||
|
func HexToHash(s string) Hash { return BytesToHash(FromHex(s)) }
|
||||||
|
|
||||||
|
// Cmp compares two hashes.
|
||||||
|
func (h Hash) Cmp(other Hash) int {
|
||||||
|
return bytes.Compare(h[:], other[:])
|
||||||
|
}
|
||||||
|
|
||||||
// IsZero returns if a Hash is empty
|
// IsZero returns if a Hash is empty
|
||||||
func (h Hash) IsZero() bool { return h == Hash{} }
|
func (h Hash) IsZero() bool { return h == Hash{} }
|
||||||
|
|
||||||
// Get the string representation of the underlying hash
|
// Get the string representation of the underlying hash
|
||||||
func (h Hash) Str() string { return string(h[:]) }
|
func (h Hash) Str() string { return string(h[:]) }
|
||||||
|
|
||||||
|
// Bytes gets the byte representation of the underlying hash.
|
||||||
func (h Hash) Bytes() []byte { return h[:] }
|
func (h Hash) Bytes() []byte { return h[:] }
|
||||||
|
|
||||||
|
// Big converts a hash to a big integer.
|
||||||
func (h Hash) Big() *big.Int { return new(big.Int).SetBytes(h[:]) }
|
func (h Hash) Big() *big.Int { return new(big.Int).SetBytes(h[:]) }
|
||||||
|
|
||||||
|
// Hex converts a hash to a hex string.
|
||||||
func (h Hash) Hex() string { return hexutil.Encode(h[:]) }
|
func (h Hash) Hex() string { return hexutil.Encode(h[:]) }
|
||||||
|
|
||||||
// TerminalString implements log.TerminalStringer, formatting a string for console
|
// TerminalString implements log.TerminalStringer, formatting a string for console
|
||||||
|
|
@ -129,7 +151,8 @@ func (h Hash) MarshalText() ([]byte, error) {
|
||||||
return hexutil.Bytes(h[:]).MarshalText()
|
return hexutil.Bytes(h[:]).MarshalText()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the hash to the value of b. If b is larger than len(h), 'b' will be cropped (from the left).
|
// SetBytes sets the hash to the value of b.
|
||||||
|
// If b is larger than len(h), b will be cropped from the left.
|
||||||
func (h *Hash) SetBytes(b []byte) {
|
func (h *Hash) SetBytes(b []byte) {
|
||||||
if len(b) > len(h) {
|
if len(b) > len(h) {
|
||||||
b = b[len(b)-HashLength:]
|
b = b[len(b)-HashLength:]
|
||||||
|
|
|
||||||
|
|
@ -225,11 +225,7 @@ func New(ctx *node.ServiceContext, config *ethconfig.Config, XDCXServ *XDCx.XDCX
|
||||||
} else {
|
} else {
|
||||||
eth.ApiBackend = &EthApiBackend{eth, nil, nil}
|
eth.ApiBackend = &EthApiBackend{eth, nil, nil}
|
||||||
}
|
}
|
||||||
gpoParams := config.GPO
|
eth.ApiBackend.gpo = gasprice.NewOracle(eth.ApiBackend, config.GPO, config.GasPrice)
|
||||||
if gpoParams.Default == nil {
|
|
||||||
gpoParams.Default = config.GasPrice
|
|
||||||
}
|
|
||||||
eth.ApiBackend.gpo = gasprice.NewOracle(eth.ApiBackend, gpoParams)
|
|
||||||
|
|
||||||
// Set global ipc endpoint.
|
// Set global ipc endpoint.
|
||||||
eth.blockchain.IPCEndpoint = ctx.GetConfig().IPCEndpoint()
|
eth.blockchain.IPCEndpoint = ctx.GetConfig().IPCEndpoint()
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
"sort"
|
"slices"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/common"
|
"github.com/XinFinOrg/XDPoSChain/common"
|
||||||
|
|
@ -56,7 +56,12 @@ type blockFees struct {
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
// processedFees contains the results of a processed block and is also used for caching
|
type cacheKey struct {
|
||||||
|
number uint64
|
||||||
|
percentiles string
|
||||||
|
}
|
||||||
|
|
||||||
|
// processedFees contains the results of a processed block.
|
||||||
type processedFees struct {
|
type processedFees struct {
|
||||||
reward []*big.Int
|
reward []*big.Int
|
||||||
baseFee, nextBaseFee *big.Int
|
baseFee, nextBaseFee *big.Int
|
||||||
|
|
@ -64,20 +69,9 @@ type processedFees struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// txGasAndReward is sorted in ascending order based on reward
|
// txGasAndReward is sorted in ascending order based on reward
|
||||||
type (
|
type txGasAndReward struct {
|
||||||
txGasAndReward struct {
|
gasUsed uint64
|
||||||
gasUsed uint64
|
reward *big.Int
|
||||||
reward *big.Int
|
|
||||||
}
|
|
||||||
sortGasAndReward []txGasAndReward
|
|
||||||
)
|
|
||||||
|
|
||||||
func (s sortGasAndReward) Len() int { return len(s) }
|
|
||||||
func (s sortGasAndReward) Swap(i, j int) {
|
|
||||||
s[i], s[j] = s[j], s[i]
|
|
||||||
}
|
|
||||||
func (s sortGasAndReward) Less(i, j int) bool {
|
|
||||||
return s[i].reward.Cmp(s[j].reward) < 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// processBlock takes a blockFees structure with the blockNumber, the header and optionally
|
// processBlock takes a blockFees structure with the blockNumber, the header and optionally
|
||||||
|
|
@ -112,12 +106,14 @@ func (oracle *Oracle) processBlock(bf *blockFees, percentiles []float64) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
sorter := make(sortGasAndReward, len(bf.block.Transactions()))
|
sorter := make([]txGasAndReward, len(bf.block.Transactions()))
|
||||||
for i, tx := range bf.block.Transactions() {
|
for i, tx := range bf.block.Transactions() {
|
||||||
reward, _ := tx.EffectiveGasTip(bf.block.BaseFee())
|
reward, _ := tx.EffectiveGasTip(bf.block.BaseFee())
|
||||||
sorter[i] = txGasAndReward{gasUsed: bf.receipts[i].GasUsed, reward: reward}
|
sorter[i] = txGasAndReward{gasUsed: bf.receipts[i].GasUsed, reward: reward}
|
||||||
}
|
}
|
||||||
sort.Stable(sorter)
|
slices.SortStableFunc(sorter, func(a, b txGasAndReward) int {
|
||||||
|
return a.reward.Cmp(b.reward)
|
||||||
|
})
|
||||||
|
|
||||||
var txIndex int
|
var txIndex int
|
||||||
sumGasUsed := sorter[0].gasUsed
|
sumGasUsed := sorter[0].gasUsed
|
||||||
|
|
@ -268,13 +264,10 @@ func (oracle *Oracle) FeeHistory(ctx context.Context, blocks uint64, unresolvedL
|
||||||
oracle.processBlock(fees, rewardPercentiles)
|
oracle.processBlock(fees, rewardPercentiles)
|
||||||
results <- fees
|
results <- fees
|
||||||
} else {
|
} else {
|
||||||
cacheKey := struct {
|
cacheKey := cacheKey{number: blockNumber, percentiles: string(percentileKey)}
|
||||||
number uint64
|
|
||||||
percentiles string
|
|
||||||
}{blockNumber, string(percentileKey)}
|
|
||||||
|
|
||||||
if p, ok := oracle.historyCache.Get(cacheKey); ok {
|
if p, ok := oracle.historyCache.Get(cacheKey); ok {
|
||||||
fees.results = p.(processedFees)
|
fees.results = p
|
||||||
results <- fees
|
results <- fees
|
||||||
} else {
|
} else {
|
||||||
if len(rewardPercentiles) != 0 {
|
if len(rewardPercentiles) != 0 {
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ func TestFeeHistory(t *testing.T) {
|
||||||
MaxBlockHistory: c.maxBlock,
|
MaxBlockHistory: c.maxBlock,
|
||||||
}
|
}
|
||||||
backend := newTestBackend(t, big.NewInt(16), c.pending)
|
backend := newTestBackend(t, big.NewInt(16), c.pending)
|
||||||
oracle := NewOracle(backend, config)
|
oracle := NewOracle(backend, config, nil)
|
||||||
|
|
||||||
first, reward, baseFee, ratio, err := oracle.FeeHistory(context.Background(), c.count, c.last, c.percent)
|
first, reward, baseFee, ratio, err := oracle.FeeHistory(context.Background(), c.count, c.last, c.percent)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,17 +19,17 @@ package gasprice
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"math/big"
|
"math/big"
|
||||||
"sort"
|
"slices"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/common"
|
"github.com/XinFinOrg/XDPoSChain/common"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/common/lru"
|
||||||
"github.com/XinFinOrg/XDPoSChain/core"
|
"github.com/XinFinOrg/XDPoSChain/core"
|
||||||
"github.com/XinFinOrg/XDPoSChain/core/types"
|
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||||
"github.com/XinFinOrg/XDPoSChain/event"
|
"github.com/XinFinOrg/XDPoSChain/event"
|
||||||
"github.com/XinFinOrg/XDPoSChain/log"
|
"github.com/XinFinOrg/XDPoSChain/log"
|
||||||
"github.com/XinFinOrg/XDPoSChain/params"
|
"github.com/XinFinOrg/XDPoSChain/params"
|
||||||
"github.com/XinFinOrg/XDPoSChain/rpc"
|
"github.com/XinFinOrg/XDPoSChain/rpc"
|
||||||
lru "github.com/hashicorp/golang-lru"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const sampleNumber = 3 // Number of transactions sampled in a block
|
const sampleNumber = 3 // Number of transactions sampled in a block
|
||||||
|
|
@ -44,7 +44,6 @@ type Config struct {
|
||||||
Percentile int
|
Percentile int
|
||||||
MaxHeaderHistory uint64
|
MaxHeaderHistory uint64
|
||||||
MaxBlockHistory uint64
|
MaxBlockHistory uint64
|
||||||
Default *big.Int `toml:",omitempty"`
|
|
||||||
MaxPrice *big.Int `toml:",omitempty"`
|
MaxPrice *big.Int `toml:",omitempty"`
|
||||||
IgnorePrice *big.Int `toml:",omitempty"`
|
IgnorePrice *big.Int `toml:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
@ -72,12 +71,13 @@ type Oracle struct {
|
||||||
|
|
||||||
checkBlocks, percentile int
|
checkBlocks, percentile int
|
||||||
maxHeaderHistory, maxBlockHistory uint64
|
maxHeaderHistory, maxBlockHistory uint64
|
||||||
historyCache *lru.Cache
|
|
||||||
|
historyCache *lru.Cache[cacheKey, processedFees]
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewOracle returns a new gasprice oracle which can recommend suitable
|
// NewOracle returns a new gasprice oracle which can recommend suitable
|
||||||
// gasprice for newly created transaction.
|
// gasprice for newly created transaction.
|
||||||
func NewOracle(backend OracleBackend, params Config) *Oracle {
|
func NewOracle(backend OracleBackend, params Config, startPrice *big.Int) *Oracle {
|
||||||
blocks := params.Blocks
|
blocks := params.Blocks
|
||||||
if blocks < 1 {
|
if blocks < 1 {
|
||||||
blocks = 1
|
blocks = 1
|
||||||
|
|
@ -87,8 +87,7 @@ func NewOracle(backend OracleBackend, params Config) *Oracle {
|
||||||
if percent < 0 {
|
if percent < 0 {
|
||||||
percent = 0
|
percent = 0
|
||||||
log.Warn("Sanitizing invalid gasprice oracle sample percentile", "provided", params.Percentile, "updated", percent)
|
log.Warn("Sanitizing invalid gasprice oracle sample percentile", "provided", params.Percentile, "updated", percent)
|
||||||
}
|
} else if percent > 100 {
|
||||||
if percent > 100 {
|
|
||||||
percent = 100
|
percent = 100
|
||||||
log.Warn("Sanitizing invalid gasprice oracle sample percentile", "provided", params.Percentile, "updated", percent)
|
log.Warn("Sanitizing invalid gasprice oracle sample percentile", "provided", params.Percentile, "updated", percent)
|
||||||
}
|
}
|
||||||
|
|
@ -104,8 +103,21 @@ func NewOracle(backend OracleBackend, params Config) *Oracle {
|
||||||
} else if ignorePrice.Int64() > 0 {
|
} else if ignorePrice.Int64() > 0 {
|
||||||
log.Info("Gasprice oracle is ignoring threshold set", "threshold", ignorePrice)
|
log.Info("Gasprice oracle is ignoring threshold set", "threshold", ignorePrice)
|
||||||
}
|
}
|
||||||
|
maxHeaderHistory := params.MaxHeaderHistory
|
||||||
|
if maxHeaderHistory < 1 {
|
||||||
|
maxHeaderHistory = 1
|
||||||
|
log.Warn("Sanitizing invalid gasprice oracle max header history", "provided", params.MaxHeaderHistory, "updated", maxHeaderHistory)
|
||||||
|
}
|
||||||
|
maxBlockHistory := params.MaxBlockHistory
|
||||||
|
if maxBlockHistory < 1 {
|
||||||
|
maxBlockHistory = 1
|
||||||
|
log.Warn("Sanitizing invalid gasprice oracle max block history", "provided", params.MaxBlockHistory, "updated", maxBlockHistory)
|
||||||
|
}
|
||||||
|
if startPrice == nil {
|
||||||
|
startPrice = new(big.Int)
|
||||||
|
}
|
||||||
|
|
||||||
cache, _ := lru.New(2048)
|
cache := lru.NewCache[cacheKey, processedFees](2048)
|
||||||
headEvent := make(chan core.ChainHeadEvent, 1)
|
headEvent := make(chan core.ChainHeadEvent, 1)
|
||||||
backend.SubscribeChainHeadEvent(headEvent)
|
backend.SubscribeChainHeadEvent(headEvent)
|
||||||
go func() {
|
go func() {
|
||||||
|
|
@ -120,13 +132,13 @@ func NewOracle(backend OracleBackend, params Config) *Oracle {
|
||||||
|
|
||||||
return &Oracle{
|
return &Oracle{
|
||||||
backend: backend,
|
backend: backend,
|
||||||
lastPrice: params.Default,
|
lastPrice: startPrice,
|
||||||
maxPrice: maxPrice,
|
maxPrice: maxPrice,
|
||||||
ignorePrice: ignorePrice,
|
ignorePrice: ignorePrice,
|
||||||
checkBlocks: blocks,
|
checkBlocks: blocks,
|
||||||
percentile: percent,
|
percentile: percent,
|
||||||
maxHeaderHistory: params.MaxHeaderHistory,
|
maxHeaderHistory: maxHeaderHistory,
|
||||||
maxBlockHistory: params.MaxBlockHistory,
|
maxBlockHistory: maxBlockHistory,
|
||||||
historyCache: cache,
|
historyCache: cache,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -166,7 +178,7 @@ func (oracle *Oracle) SuggestTipCap(ctx context.Context) (*big.Int, error) {
|
||||||
results []*big.Int
|
results []*big.Int
|
||||||
)
|
)
|
||||||
for sent < oracle.checkBlocks && number > 0 {
|
for sent < oracle.checkBlocks && number > 0 {
|
||||||
go oracle.getBlockValues(ctx, types.MakeSigner(oracle.backend.ChainConfig(), big.NewInt(int64(number))), number, sampleNumber, oracle.ignorePrice, result, quit)
|
go oracle.getBlockValues(ctx, number, sampleNumber, oracle.ignorePrice, result, quit)
|
||||||
sent++
|
sent++
|
||||||
exp++
|
exp++
|
||||||
number--
|
number--
|
||||||
|
|
@ -181,15 +193,15 @@ func (oracle *Oracle) SuggestTipCap(ctx context.Context) (*big.Int, error) {
|
||||||
// Nothing returned. There are two special cases here:
|
// Nothing returned. There are two special cases here:
|
||||||
// - The block is empty
|
// - The block is empty
|
||||||
// - All the transactions included are sent by the miner itself.
|
// - All the transactions included are sent by the miner itself.
|
||||||
// In these cases, use the latest calculated price for samping.
|
// In these cases, use half of the latest calculated price for samping.
|
||||||
if len(res.values) == 0 {
|
if len(res.values) == 0 {
|
||||||
res.values = []*big.Int{lastPrice}
|
res.values = []*big.Int{new(big.Int).Div(lastPrice, common.Big2)}
|
||||||
}
|
}
|
||||||
// Besides, in order to collect enough data for sampling, if nothing
|
// Besides, in order to collect enough data for sampling, if nothing
|
||||||
// meaningful returned, try to query more blocks. But the maximum
|
// meaningful returned, try to query more blocks. But the maximum
|
||||||
// is 2*checkBlocks.
|
// is 2*checkBlocks.
|
||||||
if len(res.values) == 1 && len(results)+1+exp < oracle.checkBlocks*2 && number > 0 {
|
if len(res.values) == 1 && len(results)+1+exp < oracle.checkBlocks*2 && number > 0 {
|
||||||
go oracle.getBlockValues(ctx, types.MakeSigner(oracle.backend.ChainConfig(), big.NewInt(int64(number))), number, sampleNumber, oracle.ignorePrice, result, quit)
|
go oracle.getBlockValues(ctx, number, sampleNumber, oracle.ignorePrice, result, quit)
|
||||||
sent++
|
sent++
|
||||||
exp++
|
exp++
|
||||||
number--
|
number--
|
||||||
|
|
@ -198,7 +210,7 @@ func (oracle *Oracle) SuggestTipCap(ctx context.Context) (*big.Int, error) {
|
||||||
}
|
}
|
||||||
price := lastPrice
|
price := lastPrice
|
||||||
if len(results) > 0 {
|
if len(results) > 0 {
|
||||||
sort.Sort(bigIntArray(results))
|
slices.SortFunc(results, func(a, b *big.Int) int { return a.Cmp(b) })
|
||||||
price = results[(len(results)-1)*oracle.percentile/100]
|
price = results[(len(results)-1)*oracle.percentile/100]
|
||||||
}
|
}
|
||||||
if price.Cmp(oracle.maxPrice) > 0 {
|
if price.Cmp(oracle.maxPrice) > 0 {
|
||||||
|
|
@ -226,35 +238,11 @@ type results struct {
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
type txSorter struct {
|
// getBlockValues calculates the lowest transaction gas price in a given block
|
||||||
txs []*types.Transaction
|
|
||||||
baseFee *big.Int
|
|
||||||
}
|
|
||||||
|
|
||||||
func newSorter(txs []*types.Transaction, baseFee *big.Int) *txSorter {
|
|
||||||
return &txSorter{
|
|
||||||
txs: txs,
|
|
||||||
baseFee: baseFee,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *txSorter) Len() int { return len(s.txs) }
|
|
||||||
func (s *txSorter) Swap(i, j int) {
|
|
||||||
s.txs[i], s.txs[j] = s.txs[j], s.txs[i]
|
|
||||||
}
|
|
||||||
func (s *txSorter) Less(i, j int) bool {
|
|
||||||
// It's okay to discard the error because a tx would never be
|
|
||||||
// accepted into a block with an invalid effective tip.
|
|
||||||
tip1, _ := s.txs[i].EffectiveGasTip(s.baseFee)
|
|
||||||
tip2, _ := s.txs[j].EffectiveGasTip(s.baseFee)
|
|
||||||
return tip1.Cmp(tip2) < 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// getBlockPrices calculates the lowest transaction gas price in a given block
|
|
||||||
// and sends it to the result channel. If the block is empty or all transactions
|
// and sends it to the result channel. If the block is empty or all transactions
|
||||||
// are sent by the miner itself(it doesn't make any sense to include this kind of
|
// are sent by the miner itself(it doesn't make any sense to include this kind of
|
||||||
// transaction prices for sampling), nil gasprice is returned.
|
// transaction prices for sampling), nil gasprice is returned.
|
||||||
func (oracle *Oracle) getBlockValues(ctx context.Context, signer types.Signer, blockNum uint64, limit int, ignoreUnder *big.Int, result chan results, quit chan struct{}) {
|
func (oracle *Oracle) getBlockValues(ctx context.Context, blockNum uint64, limit int, ignoreUnder *big.Int, result chan results, quit chan struct{}) {
|
||||||
block, err := oracle.backend.BlockByNumber(ctx, rpc.BlockNumber(blockNum))
|
block, err := oracle.backend.BlockByNumber(ctx, rpc.BlockNumber(blockNum))
|
||||||
if block == nil {
|
if block == nil {
|
||||||
select {
|
select {
|
||||||
|
|
@ -263,15 +251,24 @@ func (oracle *Oracle) getBlockValues(ctx context.Context, signer types.Signer, b
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
signer := types.MakeSigner(oracle.backend.ChainConfig(), block.Number())
|
||||||
|
|
||||||
// Sort the transaction by effective tip in ascending sort.
|
// Sort the transaction by effective tip in ascending sort.
|
||||||
txs := make([]*types.Transaction, len(block.Transactions()))
|
txs := block.Transactions()
|
||||||
copy(txs, block.Transactions())
|
sortedTxs := make([]*types.Transaction, len(txs))
|
||||||
sorter := newSorter(txs, block.BaseFee())
|
copy(sortedTxs, txs)
|
||||||
sort.Sort(sorter)
|
baseFee := block.BaseFee()
|
||||||
|
slices.SortFunc(sortedTxs, func(a, b *types.Transaction) int {
|
||||||
|
// It's okay to discard the error because a tx would never be
|
||||||
|
// accepted into a block with an invalid effective tip.
|
||||||
|
tip1, _ := a.EffectiveGasTip(baseFee)
|
||||||
|
tip2, _ := b.EffectiveGasTip(baseFee)
|
||||||
|
return tip1.Cmp(tip2)
|
||||||
|
})
|
||||||
|
|
||||||
var prices []*big.Int
|
var prices []*big.Int
|
||||||
for _, tx := range sorter.txs {
|
for _, tx := range sortedTxs {
|
||||||
tip, _ := tx.EffectiveGasTip(block.BaseFee())
|
tip, _ := tx.EffectiveGasTip(baseFee)
|
||||||
if ignoreUnder != nil && tip.Cmp(ignoreUnder) == -1 {
|
if ignoreUnder != nil && tip.Cmp(ignoreUnder) == -1 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -288,9 +285,3 @@ func (oracle *Oracle) getBlockValues(ctx context.Context, signer types.Signer, b
|
||||||
case <-quit:
|
case <-quit:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type bigIntArray []*big.Int
|
|
||||||
|
|
||||||
func (s bigIntArray) Len() int { return len(s) }
|
|
||||||
func (s bigIntArray) Less(i, j int) bool { return s[i].Cmp(s[j]) < 0 }
|
|
||||||
func (s bigIntArray) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
|
||||||
|
|
|
||||||
|
|
@ -174,7 +174,6 @@ func TestSuggestTipCap(t *testing.T) {
|
||||||
config := Config{
|
config := Config{
|
||||||
Blocks: 3,
|
Blocks: 3,
|
||||||
Percentile: 60,
|
Percentile: 60,
|
||||||
Default: big.NewInt(params.GWei),
|
|
||||||
}
|
}
|
||||||
var cases = []struct {
|
var cases = []struct {
|
||||||
fork *big.Int // Eip1559 fork number
|
fork *big.Int // Eip1559 fork number
|
||||||
|
|
@ -188,7 +187,7 @@ func TestSuggestTipCap(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
backend := newTestBackend(t, c.fork, false)
|
backend := newTestBackend(t, c.fork, false)
|
||||||
oracle := NewOracle(backend, config)
|
oracle := NewOracle(backend, config, big.NewInt(params.GWei))
|
||||||
|
|
||||||
// The gas price sampled is: 32G, 31G, 30G, 29G, 28G, 27G
|
// The gas price sampled is: 32G, 31G, 30G, 29G, 28G, 27G
|
||||||
got, err := oracle.SuggestTipCap(context.Background())
|
got, err := oracle.SuggestTipCap(context.Background())
|
||||||
|
|
|
||||||
|
|
@ -131,11 +131,7 @@ func New(ctx *node.ServiceContext, config *ethconfig.Config) (*LightEthereum, er
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
leth.ApiBackend = &LesApiBackend{leth, nil}
|
leth.ApiBackend = &LesApiBackend{leth, nil}
|
||||||
gpoParams := config.GPO
|
leth.ApiBackend.gpo = gasprice.NewOracle(leth.ApiBackend, config.GPO, config.GasPrice)
|
||||||
if gpoParams.Default == nil {
|
|
||||||
gpoParams.Default = config.GasPrice
|
|
||||||
}
|
|
||||||
leth.ApiBackend.gpo = gasprice.NewOracle(leth.ApiBackend, gpoParams)
|
|
||||||
return leth, nil
|
return leth, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue