Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1559 rpc #22964

Merged
merged 25 commits into from
Jun 2, 2021
Merged

1559 rpc #22964

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
1090463
internal/ethapi: add baseFee to RPCMarshalHeader
ryanschneider Apr 16, 2021
e5f8e96
internal/ethapi: add FeeCap, Tip and correct GasPrice to EIP-1559 RPC…
ryanschneider Apr 16, 2021
cd61cc5
core,eth,les,internal: add support for tip estimation in gas price or…
lightclient May 2, 2021
d1182ac
internal/ethapi,eth/gasprice: don't suggest tip larger than fee cap
lightclient May 17, 2021
f6e2202
core/types,internal: use correct eip1559 terminology for json marshal…
lightclient May 19, 2021
af43220
eth, internal/ethapi: fix rebase problems
holiman May 28, 2021
3946fa3
internal/ethapi: fix rpc name of basefee
holiman May 28, 2021
88caa9e
internal/ethapi: address review concerns
holiman May 30, 2021
23242b7
core, eth, internal, les: simplify gasprice oracle (#25)
rjl493456442 May 31, 2021
88bf074
internal/ethapi: minor tweak in tx args
holiman May 31, 2021
f265a00
internal/ethapi: calculate basefee for pending block
holiman May 31, 2021
53ba4e3
internal/ethapi: fix panic
holiman May 31, 2021
7a0684d
internal/ethapi, eth/tracers: simplify txargs ToMessage
holiman May 31, 2021
ee007a6
internal/ethapi: remove unused param
holiman May 31, 2021
bf00c2c
core, eth, internal: fix regressions wrt effective gas price in the evm
karalabe Jun 1, 2021
5616646
eth/gasprice: drop weird debug println
karalabe Jun 1, 2021
e056c6d
internal/jsre/deps: hack in 1559 gas conversions into embedded web3
karalabe Jun 1, 2021
f578471
internal/jsre/deps: hack basFee to decimal conversion
karalabe Jun 1, 2021
e195a53
internal/ethapi: init feecap and tipcap for legacy txs too
karalabe Jun 1, 2021
ff44948
eth, graphql, internal, les: fix gas price suggestion on all combos
karalabe Jun 2, 2021
8ee3423
internal/jsre/deps: handle decimal tipcap and feecap
karalabe Jun 2, 2021
de02886
eth, internal: minor review fixes
karalabe Jun 2, 2021
a4e903d
graphql, internal: export max fee cap RPC endpoint
karalabe Jun 2, 2021
8111e0f
internal/ethapi: fix crash in transaction_args
holiman Jun 2, 2021
22fffde
internal/ethapi: minor refactor to make the code safer
karalabe Jun 2, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions core/chain_makers.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,6 @@ func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.S
} else {
time = parent.Time() + 10 // block time is fixed at 10 seconds
}

header := &types.Header{
Root: state.IntermediateRoot(chain.Config().IsEIP158(parent.Number())),
ParentHash: parent.Hash(),
Expand All @@ -267,11 +266,14 @@ func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.S
Number: new(big.Int).Add(parent.Number(), common.Big1),
Time: time,
}

if chain.Config().IsLondon(parent.Number()) {
if chain.Config().IsLondon(header.Number) {
header.BaseFee = misc.CalcBaseFee(chain.Config(), parent.Header())
parentGasLimit := parent.GasLimit()
if !chain.Config().IsLondon(parent.Number()) {
parentGasLimit = parent.GasLimit() * params.ElasticityMultiplier
}
header.GasLimit = CalcGasLimit1559(parentGasLimit, parentGasLimit)
}

return header
}

Expand Down
2 changes: 1 addition & 1 deletion core/types/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ type Header struct {
Nonce BlockNonce `json:"nonce"`

// BaseFee was added by EIP-1559 and is ignored in legacy headers.
BaseFee *big.Int `json:"baseFee" rlp:"optional"`
BaseFee *big.Int `json:"baseFeePerGas" rlp:"optional"`
}

// field type overrides for gencodec
Expand Down
6 changes: 6 additions & 0 deletions core/types/gen_header_json.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions core/types/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -604,12 +604,10 @@ func (tx *Transaction) AsMessage(s Signer, baseFee *big.Int) (Message, error) {
accessList: tx.AccessList(),
checkNonce: true,
}

// If baseFee provided, set gasPrice to effectiveGasPrice.
if baseFee != nil {
msg.gasPrice = math.BigMin(msg.gasPrice.Add(msg.tip, baseFee), msg.feeCap)
}

var err error
msg.from, err = Sender(s, tx)
return msg, err
Expand Down
32 changes: 9 additions & 23 deletions core/types/transaction_marshalling.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ type txJSON struct {
// Common transaction fields:
Nonce *hexutil.Uint64 `json:"nonce"`
GasPrice *hexutil.Big `json:"gasPrice"`
FeeCap *hexutil.Big `json:"feeCap"`
Tip *hexutil.Big `json:"tip"`
MaxPriorityFeePerGas *hexutil.Big `json:"maxPriorityFeePerGas"`
MaxFeePerGas *hexutil.Big `json:"maxFeePerGas"`
Gas *hexutil.Uint64 `json:"gas"`
Expand Down Expand Up @@ -88,8 +86,8 @@ func (t *Transaction) MarshalJSON() ([]byte, error) {
enc.AccessList = &tx.AccessList
enc.Nonce = (*hexutil.Uint64)(&tx.Nonce)
enc.Gas = (*hexutil.Uint64)(&tx.Gas)
enc.FeeCap = (*hexutil.Big)(tx.FeeCap)
enc.Tip = (*hexutil.Big)(tx.Tip)
enc.MaxFeePerGas = (*hexutil.Big)(tx.FeeCap)
enc.MaxPriorityFeePerGas = (*hexutil.Big)(tx.Tip)
enc.Value = (*hexutil.Big)(tx.Value)
enc.Data = (*hexutil.Bytes)(&tx.Data)
enc.To = t.To()
Expand Down Expand Up @@ -226,26 +224,14 @@ func (t *Transaction) UnmarshalJSON(input []byte) error {
return errors.New("missing required field 'nonce' in transaction")
}
itx.Nonce = uint64(*dec.Nonce)
switch {
case dec.Tip == nil && dec.MaxPriorityFeePerGas == nil:
return errors.New("at least one of 'tip' or 'maxPriorityFeePerGas' must be defined")
case dec.Tip != nil && dec.MaxPriorityFeePerGas != nil:
return errors.New("only one of 'tip' or 'maxPriorityFeePerGas' may be defined")
case dec.Tip != nil && dec.MaxPriorityFeePerGas == nil:
itx.Tip = (*big.Int)(dec.Tip)
case dec.Tip == nil && dec.MaxPriorityFeePerGas != nil:
itx.Tip = (*big.Int)(dec.MaxPriorityFeePerGas)
}
switch {
case dec.FeeCap == nil && dec.MaxFeePerGas == nil:
return errors.New("at least one of 'feeCap' or 'maxFeePerGas' must be defined")
case dec.FeeCap != nil && dec.MaxFeePerGas != nil:
return errors.New("only one of 'feeCap' or 'maxFeePerGas' may be defined")
case dec.FeeCap != nil && dec.MaxFeePerGas == nil:
itx.FeeCap = (*big.Int)(dec.FeeCap)
case dec.FeeCap == nil && dec.MaxFeePerGas != nil:
itx.FeeCap = (*big.Int)(dec.MaxFeePerGas)
if dec.MaxPriorityFeePerGas == nil {
return errors.New("missing required field 'maxPriorityFeePerGas' for txdata")
}
itx.Tip = (*big.Int)(dec.MaxPriorityFeePerGas)
if dec.MaxFeePerGas == nil {
return errors.New("missing required field 'maxFeePerGas' for txdata")
}
itx.FeeCap = (*big.Int)(dec.MaxFeePerGas)
if dec.Gas == nil {
return errors.New("missing required field 'gas' for txdata")
}
Expand Down
4 changes: 2 additions & 2 deletions eth/api_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,8 @@ func (b *EthAPIBackend) Downloader() *downloader.Downloader {
return b.eth.Downloader()
}

func (b *EthAPIBackend) SuggestPrice(ctx context.Context) (*big.Int, error) {
return b.gpo.SuggestPrice(ctx)
func (b *EthAPIBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) {
return b.gpo.SuggestTipCap(ctx)
}

func (b *EthAPIBackend) ChainDb() ethdb.Database {
Expand Down
99 changes: 63 additions & 36 deletions eth/gasprice/gasprice.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ import (

const sampleNumber = 3 // Number of transactions sampled in a block

var DefaultMaxPrice = big.NewInt(500 * params.GWei)
var DefaultIgnorePrice = big.NewInt(2 * params.Wei)
var (
DefaultMaxPrice = big.NewInt(500 * params.GWei)
DefaultIgnorePrice = big.NewInt(2 * params.Wei)
)

type Config struct {
Blocks int
Expand Down Expand Up @@ -103,9 +105,13 @@ func NewOracle(backend OracleBackend, params Config) *Oracle {
}
}

// SuggestPrice returns a gasprice so that newly created transaction can
// have a very high chance to be included in the following blocks.
func (gpo *Oracle) SuggestPrice(ctx context.Context) (*big.Int, error) {
// SuggestTipCap returns a tip cap so that newly created transaction can have a
// very high chance to be included in the following blocks.
//
// Note, for legacy transactions and the legacy eth_gasPrice RPC call, it will be
// necessary to add the basefee to the returned number to fall back to the legacy
// behavior.
func (gpo *Oracle) SuggestTipCap(ctx context.Context) (*big.Int, error) {
head, _ := gpo.backend.HeaderByNumber(ctx, rpc.LatestBlockNumber)
headHash := head.Hash()

Expand All @@ -114,7 +120,7 @@ func (gpo *Oracle) SuggestPrice(ctx context.Context) (*big.Int, error) {
lastHead, lastPrice := gpo.lastHead, gpo.lastPrice
gpo.cacheLock.RUnlock()
if headHash == lastHead {
return lastPrice, nil
return new(big.Int).Set(lastPrice), nil
}
gpo.fetchLock.Lock()
defer gpo.fetchLock.Unlock()
Expand All @@ -124,17 +130,17 @@ func (gpo *Oracle) SuggestPrice(ctx context.Context) (*big.Int, error) {
lastHead, lastPrice = gpo.lastHead, gpo.lastPrice
gpo.cacheLock.RUnlock()
if headHash == lastHead {
return lastPrice, nil
return new(big.Int).Set(lastPrice), nil
}
var (
sent, exp int
number = head.Number.Uint64()
result = make(chan getBlockPricesResult, gpo.checkBlocks)
result = make(chan results, gpo.checkBlocks)
quit = make(chan struct{})
txPrices []*big.Int
results []*big.Int
)
for sent < gpo.checkBlocks && number > 0 {
go gpo.getBlockPrices(ctx, types.MakeSigner(gpo.backend.ChainConfig(), big.NewInt(int64(number))), number, sampleNumber, gpo.ignorePrice, result, quit)
go gpo.getBlockValues(ctx, types.MakeSigner(gpo.backend.ChainConfig(), big.NewInt(int64(number))), number, sampleNumber, gpo.ignorePrice, result, quit)
sent++
exp++
number--
Expand All @@ -143,31 +149,31 @@ func (gpo *Oracle) SuggestPrice(ctx context.Context) (*big.Int, error) {
res := <-result
if res.err != nil {
close(quit)
return lastPrice, res.err
return new(big.Int).Set(lastPrice), res.err
}
exp--
// Nothing returned. There are two special cases here:
// - The block is empty
// - All the transactions included are sent by the miner itself.
// In these cases, use the latest calculated price for samping.
if len(res.prices) == 0 {
res.prices = []*big.Int{lastPrice}
if len(res.values) == 0 {
res.values = []*big.Int{lastPrice}
}
// Besides, in order to collect enough data for sampling, if nothing
// meaningful returned, try to query more blocks. But the maximum
// is 2*checkBlocks.
if len(res.prices) == 1 && len(txPrices)+1+exp < gpo.checkBlocks*2 && number > 0 {
go gpo.getBlockPrices(ctx, types.MakeSigner(gpo.backend.ChainConfig(), big.NewInt(int64(number))), number, sampleNumber, gpo.ignorePrice, result, quit)
if len(res.values) == 1 && len(results)+1+exp < gpo.checkBlocks*2 && number > 0 {
go gpo.getBlockValues(ctx, types.MakeSigner(gpo.backend.ChainConfig(), big.NewInt(int64(number))), number, sampleNumber, gpo.ignorePrice, result, quit)
sent++
exp++
number--
}
txPrices = append(txPrices, res.prices...)
results = append(results, res.values...)
}
price := lastPrice
if len(txPrices) > 0 {
sort.Sort(bigIntArray(txPrices))
price = txPrices[(len(txPrices)-1)*gpo.percentile/100]
if len(results) > 0 {
sort.Sort(bigIntArray(results))
price = results[(len(results)-1)*gpo.percentile/100]
}
if price.Cmp(gpo.maxPrice) > 0 {
price = new(big.Int).Set(gpo.maxPrice)
Expand All @@ -176,53 +182,74 @@ func (gpo *Oracle) SuggestPrice(ctx context.Context) (*big.Int, error) {
gpo.lastHead = headHash
gpo.lastPrice = price
gpo.cacheLock.Unlock()
return price, nil

return new(big.Int).Set(price), nil
}

type getBlockPricesResult struct {
prices []*big.Int
type results struct {
values []*big.Int
err error
}

type transactionsByGasPrice []*types.Transaction
type txSorter struct {
txs []*types.Transaction
baseFee *big.Int
}

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].FeeCapCmp(t[j]) < 0 }
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].EffectiveTip(s.baseFee)
tip2, _ := s.txs[j].EffectiveTip(s.baseFee)
return tip1.Cmp(tip2) < 0
}
holiman marked this conversation as resolved.
Show resolved Hide resolved

// 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
// 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.
func (gpo *Oracle) getBlockPrices(ctx context.Context, signer types.Signer, blockNum uint64, limit int, ignoreUnder *big.Int, result chan getBlockPricesResult, quit chan struct{}) {
func (gpo *Oracle) getBlockValues(ctx context.Context, signer types.Signer, blockNum uint64, limit int, ignoreUnder *big.Int, result chan results, quit chan struct{}) {
block, err := gpo.backend.BlockByNumber(ctx, rpc.BlockNumber(blockNum))
if block == nil {
select {
case result <- getBlockPricesResult{nil, err}:
case result <- results{nil, err}:
case <-quit:
}
return
}
blockTxs := block.Transactions()
txs := make([]*types.Transaction, len(blockTxs))
copy(txs, blockTxs)
sort.Sort(transactionsByGasPrice(txs))
// Sort the transaction by effective tip in ascending sort.
txs := make([]*types.Transaction, len(block.Transactions()))
copy(txs, block.Transactions())
sorter := newSorter(txs, block.BaseFee())
sort.Sort(sorter)

var prices []*big.Int
for _, tx := range txs {
if ignoreUnder != nil && tx.GasPrice().Cmp(ignoreUnder) == -1 {
for _, tx := range sorter.txs {
tip, _ := tx.EffectiveTip(block.BaseFee())
if ignoreUnder != nil && tip.Cmp(ignoreUnder) == -1 {
continue
}
sender, err := types.Sender(signer, tx)
if err == nil && sender != block.Coinbase() {
prices = append(prices, tx.GasPrice())
prices = append(prices, tip)
if len(prices) >= limit {
break
}
}
}
select {
case result <- getBlockPricesResult{prices, nil}:
case result <- results{prices, nil}:
case <-quit:
}
}
Expand Down
Loading