From 4d414e40c8d18cf391d01cca46cf22aaa319248d Mon Sep 17 00:00:00 2001 From: Ian Norden Date: Fri, 10 Jan 2020 15:30:04 -0600 Subject: [PATCH] gas oracle work --- accounts/abi/bind/backends/simulated.go | 24 ++ accounts/abi/bind/base.go | 24 +- accounts/external/backend.go | 16 +- cmd/clef/main.go | 6 +- eth/api_backend.go | 8 + eth/backend.go | 18 +- eth/gasprice/gasprice.go | 285 ++++++++++++++++++++++-- ethclient/ethclient.go | 30 +++ internal/ethapi/api.go | 12 + internal/ethapi/backend.go | 2 + les/api_backend.go | 8 + les/client.go | 4 +- 12 files changed, 404 insertions(+), 33 deletions(-) diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index d0ce47937..4bd56a811 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -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) { diff --git a/accounts/abi/bind/base.go b/accounts/abi/bind/base.go index 71b93dd5c..eff108b33 100644 --- a/accounts/abi/bind/base.go +++ b/accounts/abi/bind/base.go @@ -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") diff --git a/accounts/external/backend.go b/accounts/external/backend.go index d3110fa17..c8b33d798 100644 --- a/accounts/external/backend.go +++ b/accounts/external/backend.go @@ -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 diff --git a/cmd/clef/main.go b/cmd/clef/main.go index cef6276fa..0db36357f 100644 --- a/cmd/clef/main.go +++ b/cmd/clef/main.go @@ -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, }}) diff --git a/eth/api_backend.go b/eth/api_backend.go index a82aee4eb..2eb2ff051 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -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() } diff --git a/eth/backend.go b/eth/backend.go index e4f98360d..b4f87ddf0 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -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) diff --git a/eth/gasprice/gasprice.go b/eth/gasprice/gasprice.go index 3b8db78a1..e83a6c5a8 100644 --- a/eth/gasprice/gasprice.go +++ b/eth/gasprice/gasprice.go @@ -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) } diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index a62db56b7..b8d0b39b3 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -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, diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 65d8b6802..bac46f043 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -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()) diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 245091df3..ba63460d9 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -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 diff --git a/les/api_backend.go b/les/api_backend.go index 756beaf6a..5fd29d9e9 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -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 } diff --git a/les/client.go b/les/client.go index 34a654e22..8c1bd55b3 100644 --- a/les/client.go +++ b/les/client.go @@ -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)