gas oracle work
This commit is contained in:
parent
6575396460
commit
4d414e40c8
@ -154,6 +154,20 @@ func (b *SimulatedBackend) CodeAt(ctx context.Context, contract common.Address,
|
||||
return statedb.GetCode(contract), nil
|
||||
}
|
||||
|
||||
// BaseFeeAt returns the BaseFee at the given block height.
|
||||
// If the blockNumber is nil the latest known BaseFee is returned.
|
||||
func (b *SimulatedBackend) BaseFeeAt(ctx context.Context, blockNumber *big.Int) (*big.Int, error) {
|
||||
if blockNumber == nil || blockNumber.Cmp(b.pendingBlock.Number()) == 0 {
|
||||
header := b.blockchain.CurrentHeader()
|
||||
return header.BaseFee, nil
|
||||
}
|
||||
header, err := b.HeaderByNumber(ctx, blockNumber)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return header.BaseFee, nil
|
||||
}
|
||||
|
||||
// BalanceAt returns the wei balance of a certain account in the blockchain.
|
||||
func (b *SimulatedBackend) BalanceAt(ctx context.Context, contract common.Address, blockNumber *big.Int) (*big.Int, error) {
|
||||
b.mu.Lock()
|
||||
@ -430,6 +444,16 @@ func (b *SimulatedBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error
|
||||
return big.NewInt(1), nil
|
||||
}
|
||||
|
||||
// SuggestGasPremium, since the simulated chain doesn't have miners, we just return a GasPremium of 1 for any call
|
||||
func (b *SimulatedBackend) SuggestGasPremium(ctx context.Context) (*big.Int, error) {
|
||||
return big.NewInt(1), nil
|
||||
}
|
||||
|
||||
// SuggestFeeCap, since the simulated chain doesn't have miners, we just return a FeeCap of 1 for any call
|
||||
func (b *SimulatedBackend) SuggestFeeCap(ctx context.Context) (*big.Int, error) {
|
||||
return big.NewInt(1), nil
|
||||
}
|
||||
|
||||
// EstimateGas executes the requested code against the currently pending block/state and
|
||||
// returns the used amount of gas.
|
||||
func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMsg) (uint64, error) {
|
||||
|
||||
@ -49,10 +49,14 @@ type TransactOpts struct {
|
||||
Nonce *big.Int // Nonce to use for the transaction execution (nil = use pending state)
|
||||
Signer SignerFn // Method to use for signing the transaction (mandatory)
|
||||
|
||||
Value *big.Int // Funds to transfer along the transaction (nil = 0 = no funds)
|
||||
GasPrice *big.Int // Gas price to use for the transaction execution (nil = gas price oracle)
|
||||
Value *big.Int // Funds to transfer along along the transaction (nil = 0 = no funds)
|
||||
GasLimit uint64 // Gas limit to set for the transaction execution (0 = estimate)
|
||||
|
||||
// If GasPrice, GasPremium, and FeeCap are all nil then we defer to the gas price oracle
|
||||
GasPrice *big.Int // Gas price to use for the transaction execution
|
||||
GasPremium *big.Int // Gas premium (tip) to use for EIP1559 transaction execution (
|
||||
FeeCap *big.Int // Fee cap to use for EIP1559 transaction execution
|
||||
|
||||
Context context.Context // Network context to support cancellation and timeouts (nil = no timeout)
|
||||
}
|
||||
|
||||
@ -213,7 +217,7 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
|
||||
}
|
||||
// Figure out the gas allowance and gas price values
|
||||
gasPrice := opts.GasPrice
|
||||
if gasPrice == nil {
|
||||
if gasPrice == nil && opts.FeeCap == nil && opts.GasPremium == nil {
|
||||
gasPrice, err = c.transactor.SuggestGasPrice(ensureContext(opts.Context))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to suggest gas price: %v", err)
|
||||
@ -230,7 +234,15 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
|
||||
}
|
||||
}
|
||||
// If the contract surely has code (or code is not needed), estimate the transaction
|
||||
msg := ethereum.CallMsg{From: opts.From, To: contract, GasPrice: gasPrice, Value: value, Data: input}
|
||||
msg := ethereum.CallMsg{
|
||||
From: opts.From,
|
||||
To: contract,
|
||||
GasPrice: gasPrice,
|
||||
Value: value,
|
||||
Data: input,
|
||||
GasPremium: opts.GasPremium,
|
||||
FeeCap: opts.FeeCap,
|
||||
}
|
||||
gasLimit, err = c.transactor.EstimateGas(ensureContext(opts.Context), msg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to estimate gas needed: %v", err)
|
||||
@ -239,9 +251,9 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
|
||||
// Create the transaction, sign it and schedule it for execution
|
||||
var rawTx *types.Transaction
|
||||
if contract == nil {
|
||||
rawTx = types.NewContractCreation(nonce, value, gasLimit, gasPrice, input, nil, nil)
|
||||
rawTx = types.NewContractCreation(nonce, value, gasLimit, gasPrice, input, opts.GasPremium, opts.FeeCap)
|
||||
} else {
|
||||
rawTx = types.NewTransaction(nonce, c.address, value, gasLimit, gasPrice, input, nil, nil)
|
||||
rawTx = types.NewTransaction(nonce, c.address, value, gasLimit, gasPrice, input, opts.GasPremium, opts.FeeCap)
|
||||
}
|
||||
if opts.Signer == nil {
|
||||
return nil, errors.New("no signer to authorize the transaction with")
|
||||
|
||||
16
accounts/external/backend.go
vendored
16
accounts/external/backend.go
vendored
@ -200,13 +200,15 @@ func (api *ExternalSigner) SignTx(account accounts.Account, tx *types.Transactio
|
||||
to = &t
|
||||
}
|
||||
args := &core.SendTxArgs{
|
||||
Data: &data,
|
||||
Nonce: hexutil.Uint64(tx.Nonce()),
|
||||
Value: hexutil.Big(*tx.Value()),
|
||||
Gas: hexutil.Uint64(tx.Gas()),
|
||||
GasPrice: hexutil.Big(*tx.GasPrice()),
|
||||
To: to,
|
||||
From: common.NewMixedcaseAddress(account.Address),
|
||||
Data: &data,
|
||||
Nonce: hexutil.Uint64(tx.Nonce()),
|
||||
Value: hexutil.Big(*tx.Value()),
|
||||
Gas: hexutil.Uint64(tx.Gas()),
|
||||
GasPrice: (*hexutil.Big)(tx.GasPrice()),
|
||||
GasPremium: (*hexutil.Big)(tx.GasPremium()),
|
||||
FeeCap: (*hexutil.Big)(tx.FeeCap()),
|
||||
To: to,
|
||||
From: common.NewMixedcaseAddress(account.Address),
|
||||
}
|
||||
if err := api.client.Call(&res, "account_signTransaction", args); err != nil {
|
||||
return nil, err
|
||||
|
||||
@ -883,7 +883,7 @@ func testExternalUI(api *core.SignerAPI) {
|
||||
Value: hexutil.Big(*big.NewInt(6)),
|
||||
From: common.NewMixedcaseAddress(a),
|
||||
To: &to,
|
||||
GasPrice: hexutil.Big(*big.NewInt(5)),
|
||||
GasPrice: (*hexutil.Big)(big.NewInt(5)),
|
||||
Gas: 1000,
|
||||
Input: nil,
|
||||
}
|
||||
@ -1040,7 +1040,7 @@ func GenDoc(ctx *cli.Context) {
|
||||
Value: hexutil.Big(*big.NewInt(6)),
|
||||
From: common.NewMixedcaseAddress(a),
|
||||
To: nil,
|
||||
GasPrice: hexutil.Big(*big.NewInt(5)),
|
||||
GasPrice: (*hexutil.Big)(big.NewInt(5)),
|
||||
Gas: 1000,
|
||||
Input: nil,
|
||||
}})
|
||||
@ -1056,7 +1056,7 @@ func GenDoc(ctx *cli.Context) {
|
||||
Value: hexutil.Big(*big.NewInt(6)),
|
||||
From: common.NewMixedcaseAddress(a),
|
||||
To: nil,
|
||||
GasPrice: hexutil.Big(*big.NewInt(5)),
|
||||
GasPrice: (*hexutil.Big)(big.NewInt(5)),
|
||||
Gas: 1000,
|
||||
Input: nil,
|
||||
}})
|
||||
|
||||
@ -273,6 +273,14 @@ func (b *EthAPIBackend) SuggestPrice(ctx context.Context) (*big.Int, error) {
|
||||
return b.gpo.SuggestPrice(ctx)
|
||||
}
|
||||
|
||||
func (b *EthAPIBackend) SuggestPremium(ctx context.Context) (*big.Int, error) {
|
||||
return b.gpo.SuggestPremium(ctx)
|
||||
}
|
||||
|
||||
func (b *EthAPIBackend) SuggestCap(ctx context.Context) (*big.Int, error) {
|
||||
return b.gpo.SuggestCap(ctx)
|
||||
}
|
||||
|
||||
func (b *EthAPIBackend) ChainDb() ethdb.Database {
|
||||
return b.eth.ChainDb()
|
||||
}
|
||||
|
||||
@ -221,8 +221,22 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
|
||||
|
||||
eth.APIBackend = &EthAPIBackend{ctx.ExtRPCEnabled(), eth, nil}
|
||||
gpoParams := config.GPO
|
||||
if gpoParams.Default == nil {
|
||||
gpoParams.Default = config.Miner.GasPrice
|
||||
if gpoParams.DefaultGasPrice == nil {
|
||||
gpoParams.DefaultGasPrice = config.Miner.GasPrice
|
||||
}
|
||||
if gpoParams.DefaultFeeCap == nil {
|
||||
gpoParams.DefaultFeeCap = config.Miner.GasPrice
|
||||
}
|
||||
if gpoParams.DefaultGasPremium == nil {
|
||||
baseFee := eth.blockchain.CurrentHeader().BaseFee
|
||||
if baseFee == nil {
|
||||
baseFee = new(big.Int).SetUint64(params.EIP1559InitialBaseFee)
|
||||
}
|
||||
gasPremium := new(big.Int).Sub(config.Miner.GasPrice, baseFee)
|
||||
if gasPremium.Cmp(big.NewInt(0)) < 0 {
|
||||
gasPremium = big.NewInt(0)
|
||||
}
|
||||
gpoParams.DefaultGasPremium = gasPremium
|
||||
}
|
||||
eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, gpoParams)
|
||||
|
||||
|
||||
@ -29,22 +29,31 @@ import (
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
)
|
||||
|
||||
var maxPrice = big.NewInt(500 * params.GWei)
|
||||
var (
|
||||
maxPrice = big.NewInt(500 * params.GWei)
|
||||
maxPremium = big.NewInt(500 * params.GWei)
|
||||
maxFeeCap = big.NewInt(1000 * params.GWei)
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Blocks int
|
||||
Percentile int
|
||||
Default *big.Int `toml:",omitempty"`
|
||||
Blocks int
|
||||
Percentile int
|
||||
DefaultGasPrice *big.Int `toml:",omitempty"`
|
||||
DefaultGasPremium *big.Int `toml:",omitempty"`
|
||||
DefaultFeeCap *big.Int `toml:",omitempty"`
|
||||
}
|
||||
|
||||
// Oracle recommends gas prices based on the content of recent
|
||||
// blocks. Suitable for both light and full clients.
|
||||
type Oracle struct {
|
||||
backend ethapi.Backend
|
||||
lastHead common.Hash
|
||||
lastPrice *big.Int
|
||||
cacheLock sync.RWMutex
|
||||
fetchLock sync.Mutex
|
||||
backend ethapi.Backend
|
||||
lastHead common.Hash
|
||||
lastPrice *big.Int
|
||||
lastPremium *big.Int
|
||||
lastCap *big.Int
|
||||
lastBaseFee *big.Int
|
||||
cacheLock sync.RWMutex
|
||||
fetchLock sync.Mutex
|
||||
|
||||
checkBlocks, maxEmpty, maxBlocks int
|
||||
percentile int
|
||||
@ -65,7 +74,9 @@ func NewOracle(backend ethapi.Backend, params Config) *Oracle {
|
||||
}
|
||||
return &Oracle{
|
||||
backend: backend,
|
||||
lastPrice: params.Default,
|
||||
lastPrice: params.DefaultGasPrice,
|
||||
lastPremium: params.DefaultGasPremium,
|
||||
lastCap: params.DefaultFeeCap,
|
||||
checkBlocks: blocks,
|
||||
maxEmpty: blocks / 2,
|
||||
maxBlocks: blocks * 5,
|
||||
@ -147,16 +158,216 @@ func (gpo *Oracle) SuggestPrice(ctx context.Context) (*big.Int, error) {
|
||||
return price, nil
|
||||
}
|
||||
|
||||
// SuggestPremium returns the recommended gas premium.
|
||||
func (gpo *Oracle) SuggestPremium(ctx context.Context) (*big.Int, error) {
|
||||
gpo.cacheLock.RLock()
|
||||
lastHead := gpo.lastHead
|
||||
lastPremium := gpo.lastPremium
|
||||
gpo.cacheLock.RUnlock()
|
||||
|
||||
head, _ := gpo.backend.HeaderByNumber(ctx, rpc.LatestBlockNumber)
|
||||
headHash := head.Hash()
|
||||
if headHash == lastHead {
|
||||
return lastPremium, nil
|
||||
}
|
||||
|
||||
gpo.fetchLock.Lock()
|
||||
defer gpo.fetchLock.Unlock()
|
||||
|
||||
// try checking the cache again, maybe the last fetch fetched what we need
|
||||
gpo.cacheLock.RLock()
|
||||
lastHead = gpo.lastHead
|
||||
lastPremium = gpo.lastPremium
|
||||
gpo.cacheLock.RUnlock()
|
||||
if headHash == lastHead {
|
||||
return lastPremium, nil
|
||||
}
|
||||
|
||||
blockNum := head.Number.Uint64()
|
||||
ch := make(chan getBlockPremiumsResult, gpo.checkBlocks)
|
||||
sent := 0
|
||||
exp := 0
|
||||
var blockPremiums []*big.Int
|
||||
for sent < gpo.checkBlocks && blockNum > 0 {
|
||||
go gpo.getBlockPremiums(ctx, types.MakeSigner(gpo.backend.ChainConfig(), big.NewInt(int64(blockNum))), blockNum, ch)
|
||||
sent++
|
||||
exp++
|
||||
blockNum--
|
||||
}
|
||||
maxEmpty := gpo.maxEmpty
|
||||
for exp > 0 {
|
||||
res := <-ch
|
||||
if res.err != nil {
|
||||
return lastPremium, res.err
|
||||
}
|
||||
exp--
|
||||
if res.premium != nil {
|
||||
blockPremiums = append(blockPremiums, res.premium)
|
||||
continue
|
||||
}
|
||||
if maxEmpty > 0 {
|
||||
maxEmpty--
|
||||
continue
|
||||
}
|
||||
if blockNum > 0 && sent < gpo.maxBlocks {
|
||||
go gpo.getBlockPremiums(ctx, types.MakeSigner(gpo.backend.ChainConfig(), big.NewInt(int64(blockNum))), blockNum, ch)
|
||||
sent++
|
||||
exp++
|
||||
blockNum--
|
||||
}
|
||||
}
|
||||
premium := lastPremium
|
||||
if len(blockPremiums) > 0 {
|
||||
sort.Sort(bigIntArray(blockPremiums))
|
||||
premium = blockPremiums[(len(blockPremiums)-1)*gpo.percentile/100]
|
||||
}
|
||||
if premium.Cmp(maxPremium) > 0 {
|
||||
premium = new(big.Int).Set(maxPremium)
|
||||
}
|
||||
|
||||
gpo.cacheLock.Lock()
|
||||
gpo.lastHead = headHash
|
||||
gpo.lastPremium = premium
|
||||
gpo.cacheLock.Unlock()
|
||||
return premium, nil
|
||||
}
|
||||
|
||||
// SuggestCap returns the recommended fee cap.
|
||||
func (gpo *Oracle) SuggestCap(ctx context.Context) (*big.Int, error) {
|
||||
gpo.cacheLock.RLock()
|
||||
lastHead := gpo.lastHead
|
||||
lastCap := gpo.lastCap
|
||||
gpo.cacheLock.RUnlock()
|
||||
|
||||
head, _ := gpo.backend.HeaderByNumber(ctx, rpc.LatestBlockNumber)
|
||||
headHash := head.Hash()
|
||||
if headHash == lastHead {
|
||||
return lastCap, nil
|
||||
}
|
||||
|
||||
gpo.fetchLock.Lock()
|
||||
defer gpo.fetchLock.Unlock()
|
||||
|
||||
// try checking the cache again, maybe the last fetch fetched what we need
|
||||
gpo.cacheLock.RLock()
|
||||
lastHead = gpo.lastHead
|
||||
lastCap = gpo.lastCap
|
||||
gpo.cacheLock.RUnlock()
|
||||
if headHash == lastHead {
|
||||
return lastCap, nil
|
||||
}
|
||||
|
||||
blockNum := head.Number.Uint64()
|
||||
ch := make(chan getBlockCapsResult, gpo.checkBlocks)
|
||||
sent := 0
|
||||
exp := 0
|
||||
var blockCaps []*big.Int
|
||||
for sent < gpo.checkBlocks && blockNum > 0 {
|
||||
go gpo.getBlockCaps(ctx, types.MakeSigner(gpo.backend.ChainConfig(), big.NewInt(int64(blockNum))), blockNum, ch)
|
||||
sent++
|
||||
exp++
|
||||
blockNum--
|
||||
}
|
||||
maxEmpty := gpo.maxEmpty
|
||||
for exp > 0 {
|
||||
res := <-ch
|
||||
if res.err != nil {
|
||||
return lastCap, res.err
|
||||
}
|
||||
exp--
|
||||
if res.cap != nil {
|
||||
blockCaps = append(blockCaps, res.cap)
|
||||
continue
|
||||
}
|
||||
if maxEmpty > 0 {
|
||||
maxEmpty--
|
||||
continue
|
||||
}
|
||||
if blockNum > 0 && sent < gpo.maxBlocks {
|
||||
go gpo.getBlockCaps(ctx, types.MakeSigner(gpo.backend.ChainConfig(), big.NewInt(int64(blockNum))), blockNum, ch)
|
||||
sent++
|
||||
exp++
|
||||
blockNum--
|
||||
}
|
||||
}
|
||||
cap := lastCap
|
||||
if len(blockCaps) > 0 {
|
||||
sort.Sort(bigIntArray(blockCaps))
|
||||
cap = blockCaps[(len(blockCaps)-1)*gpo.percentile/100]
|
||||
}
|
||||
if cap.Cmp(maxFeeCap) > 0 {
|
||||
cap = new(big.Int).Set(maxFeeCap)
|
||||
}
|
||||
|
||||
gpo.cacheLock.Lock()
|
||||
gpo.lastHead = headHash
|
||||
gpo.lastCap = cap
|
||||
gpo.cacheLock.Unlock()
|
||||
return cap, nil
|
||||
}
|
||||
|
||||
type getBlockPricesResult struct {
|
||||
price *big.Int
|
||||
err error
|
||||
}
|
||||
|
||||
type getBlockPremiumsResult struct {
|
||||
premium *big.Int
|
||||
err error
|
||||
}
|
||||
|
||||
type getBlockCapsResult struct {
|
||||
cap *big.Int
|
||||
err error
|
||||
}
|
||||
|
||||
type transactionsByGasPrice []*types.Transaction
|
||||
|
||||
func (t transactionsByGasPrice) Len() int { return len(t) }
|
||||
func (t transactionsByGasPrice) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
|
||||
func (t transactionsByGasPrice) Less(i, j int) bool { return t[i].GasPrice().Cmp(t[j].GasPrice()) < 0 }
|
||||
func (t transactionsByGasPrice) Len() int { return len(t) }
|
||||
func (t transactionsByGasPrice) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
|
||||
func (t transactionsByGasPrice) Less(i, j int) bool {
|
||||
iPrice := t[i].GasPrice()
|
||||
jPrice := t[j].GasPrice()
|
||||
if iPrice == nil {
|
||||
iPrice = big.NewInt(0)
|
||||
}
|
||||
if jPrice == nil {
|
||||
jPrice = big.NewInt(0)
|
||||
}
|
||||
return iPrice.Cmp(jPrice) < 0
|
||||
}
|
||||
|
||||
type transactionsByGasPremium []*types.Transaction
|
||||
|
||||
func (t transactionsByGasPremium) Len() int { return len(t) }
|
||||
func (t transactionsByGasPremium) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
|
||||
func (t transactionsByGasPremium) Less(i, j int) bool {
|
||||
iPremium := t[i].GasPremium()
|
||||
jPremium := t[j].GasPremium()
|
||||
if iPremium == nil {
|
||||
iPremium = big.NewInt(0)
|
||||
}
|
||||
if jPremium == nil {
|
||||
jPremium = big.NewInt(0)
|
||||
}
|
||||
return iPremium.Cmp(jPremium) < 0
|
||||
}
|
||||
|
||||
type transactionsByFeeCap []*types.Transaction
|
||||
|
||||
func (t transactionsByFeeCap) Len() int { return len(t) }
|
||||
func (t transactionsByFeeCap) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
|
||||
func (t transactionsByFeeCap) Less(i, j int) bool {
|
||||
iCap := t[i].FeeCap()
|
||||
jCap := t[j].FeeCap()
|
||||
if iCap == nil {
|
||||
iCap = big.NewInt(0)
|
||||
}
|
||||
if jCap == nil {
|
||||
jCap = big.NewInt(0)
|
||||
}
|
||||
return iCap.Cmp(jCap) < 0
|
||||
}
|
||||
|
||||
// getBlockPrices calculates the lowest transaction gas price in a given block
|
||||
// and sends it to the result channel. If the block is empty, price is nil.
|
||||
@ -182,6 +393,54 @@ func (gpo *Oracle) getBlockPrices(ctx context.Context, signer types.Signer, bloc
|
||||
ch <- getBlockPricesResult{nil, nil}
|
||||
}
|
||||
|
||||
// getBlockPremiums calculates the lowest transaction gas premium in a given block
|
||||
// and sends it to the result channel. If the block is empty, price is nil.
|
||||
func (gpo *Oracle) getBlockPremiums(ctx context.Context, signer types.Signer, blockNum uint64, ch chan getBlockPremiumsResult) {
|
||||
block, err := gpo.backend.BlockByNumber(ctx, rpc.BlockNumber(blockNum))
|
||||
if block == nil {
|
||||
ch <- getBlockPremiumsResult{nil, err}
|
||||
return
|
||||
}
|
||||
|
||||
blockTxs := block.Transactions()
|
||||
txs := make([]*types.Transaction, len(blockTxs))
|
||||
copy(txs, blockTxs)
|
||||
sort.Sort(transactionsByGasPremium(txs))
|
||||
|
||||
for _, tx := range txs {
|
||||
sender, err := types.Sender(signer, tx)
|
||||
if err == nil && sender != block.Coinbase() {
|
||||
ch <- getBlockPremiumsResult{tx.GasPremium(), nil}
|
||||
return
|
||||
}
|
||||
}
|
||||
ch <- getBlockPremiumsResult{nil, nil}
|
||||
}
|
||||
|
||||
// getBlockCaps calculates the lowest transaction fee cap in a given block
|
||||
// and sends it to the result channel. If the block is empty, price is nil.
|
||||
func (gpo *Oracle) getBlockCaps(ctx context.Context, signer types.Signer, blockNum uint64, ch chan getBlockCapsResult) {
|
||||
block, err := gpo.backend.BlockByNumber(ctx, rpc.BlockNumber(blockNum))
|
||||
if block == nil {
|
||||
ch <- getBlockCapsResult{nil, err}
|
||||
return
|
||||
}
|
||||
|
||||
blockTxs := block.Transactions()
|
||||
txs := make([]*types.Transaction, len(blockTxs))
|
||||
copy(txs, blockTxs)
|
||||
sort.Sort(transactionsByFeeCap(txs))
|
||||
|
||||
for _, tx := range txs {
|
||||
sender, err := types.Sender(signer, tx)
|
||||
if err == nil && sender != block.Coinbase() {
|
||||
ch <- getBlockCapsResult{tx.FeeCap(), nil}
|
||||
return
|
||||
}
|
||||
}
|
||||
ch <- getBlockCapsResult{nil, nil}
|
||||
}
|
||||
|
||||
type bigIntArray []*big.Int
|
||||
|
||||
func (s bigIntArray) Len() int { return len(s) }
|
||||
|
||||
@ -371,6 +371,16 @@ func (ec *Client) NonceAt(ctx context.Context, account common.Address, blockNumb
|
||||
return uint64(result), err
|
||||
}
|
||||
|
||||
// BaseFeeAt returns the BaseFee at the given block height.
|
||||
// If the blockNumber is nil the latest known BaseFee is returned.
|
||||
func (ec *Client) BaseFeeAt(ctx context.Context, blockNumber *big.Int) (*big.Int, error) {
|
||||
header, err := ec.HeaderByNumber(ctx, blockNumber)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return header.BaseFee, nil
|
||||
}
|
||||
|
||||
// Filters
|
||||
|
||||
// FilterLogs executes a filter query.
|
||||
@ -492,6 +502,26 @@ func (ec *Client) SuggestGasPrice(ctx context.Context) (*big.Int, error) {
|
||||
return (*big.Int)(&hex), nil
|
||||
}
|
||||
|
||||
// SuggestGasPremium retrieves the currently suggested gas premium to allow a timely
|
||||
// execution of a transaction
|
||||
func (ec *Client) SuggestGasPremium(ctx context.Context) (*big.Int, error) {
|
||||
var hex hexutil.Big
|
||||
if err := ec.c.CallContext(ctx, &hex, "eth_gasPremium"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return (*big.Int)(&hex), nil
|
||||
}
|
||||
|
||||
// SuggestFeeCap retrieves the currently suggested fee cap to allow a timely
|
||||
// execution of a transaction
|
||||
func (ec *Client) SuggestFeeCap(ctx context.Context) (*big.Int, error) {
|
||||
var hex hexutil.Big
|
||||
if err := ec.c.CallContext(ctx, &hex, "eth_feeCap"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return (*big.Int)(&hex), nil
|
||||
}
|
||||
|
||||
// EstimateGas tries to estimate the gas needed to execute a specific transaction based on
|
||||
// the current pending state of the backend blockchain. There is no guarantee that this is
|
||||
// the true gas limit requirement as other transactions may be added or removed by miners,
|
||||
|
||||
@ -65,6 +65,18 @@ func (s *PublicEthereumAPI) GasPrice(ctx context.Context) (*hexutil.Big, error)
|
||||
return (*hexutil.Big)(price), err
|
||||
}
|
||||
|
||||
// GasPremium returns a suggestion for the gas premium.
|
||||
func (s *PublicEthereumAPI) GasPremium(ctx context.Context) (*hexutil.Big, error) {
|
||||
premium, err := s.b.SuggestPremium(ctx)
|
||||
return (*hexutil.Big)(premium), err
|
||||
}
|
||||
|
||||
// FeeCap returns a suggestion for the fee cap.
|
||||
func (s *PublicEthereumAPI) FeeCap(ctx context.Context) (*hexutil.Big, error) {
|
||||
cap, err := s.b.SuggestCap(ctx)
|
||||
return (*hexutil.Big)(cap), err
|
||||
}
|
||||
|
||||
// ProtocolVersion returns the current Ethereum protocol version this node supports
|
||||
func (s *PublicEthereumAPI) ProtocolVersion() hexutil.Uint {
|
||||
return hexutil.Uint(s.b.ProtocolVersion())
|
||||
|
||||
@ -42,6 +42,8 @@ type Backend interface {
|
||||
Downloader() *downloader.Downloader
|
||||
ProtocolVersion() int
|
||||
SuggestPrice(ctx context.Context) (*big.Int, error)
|
||||
SuggestPremium(ctx context.Context) (*big.Int, error)
|
||||
SuggestCap(ctx context.Context) (*big.Int, error)
|
||||
ChainDb() ethdb.Database
|
||||
AccountManager() *accounts.Manager
|
||||
ExtRPCEnabled() bool
|
||||
|
||||
@ -246,6 +246,14 @@ func (b *LesApiBackend) SuggestPrice(ctx context.Context) (*big.Int, error) {
|
||||
return b.gpo.SuggestPrice(ctx)
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) SuggestPremium(ctx context.Context) (*big.Int, error) {
|
||||
return b.gpo.SuggestPremium(ctx)
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) SuggestCap(ctx context.Context) (*big.Int, error) {
|
||||
return b.gpo.SuggestCap(ctx)
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) ChainDb() ethdb.Database {
|
||||
return b.eth.chainDb
|
||||
}
|
||||
|
||||
@ -158,8 +158,8 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
|
||||
|
||||
leth.ApiBackend = &LesApiBackend{ctx.ExtRPCEnabled(), leth, nil}
|
||||
gpoParams := config.GPO
|
||||
if gpoParams.Default == nil {
|
||||
gpoParams.Default = config.Miner.GasPrice
|
||||
if gpoParams.DefaultGasPrice == nil {
|
||||
gpoParams.DefaultGasPrice = config.Miner.GasPrice
|
||||
}
|
||||
leth.ApiBackend.gpo = gasprice.NewOracle(leth.ApiBackend, gpoParams)
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user