core, eth, internal, les: RPC methods and fields for EIP 1559 (#22964)

* internal/ethapi: add baseFee to RPCMarshalHeader

* internal/ethapi: add FeeCap, Tip and correct GasPrice to EIP-1559 RPCTransaction results

* core,eth,les,internal: add support for tip estimation in gas price oracle

* internal/ethapi,eth/gasprice: don't suggest tip larger than fee cap

* core/types,internal: use correct eip1559 terminology for json marshalling

* eth, internal/ethapi: fix rebase problems

* internal/ethapi: fix rpc name of basefee

* internal/ethapi: address review concerns

* core, eth, internal, les: simplify gasprice oracle (#25)

* core, eth, internal, les: simplify gasprice oracle

* eth/gasprice: fix typo

* internal/ethapi: minor tweak in tx args

* internal/ethapi: calculate basefee for pending block

* internal/ethapi: fix panic

* internal/ethapi, eth/tracers: simplify txargs ToMessage

* internal/ethapi: remove unused param

* core, eth, internal: fix regressions wrt effective gas price in the evm

* eth/gasprice: drop weird debug println

* internal/jsre/deps: hack in 1559 gas conversions into embedded web3

* internal/jsre/deps: hack basFee to decimal conversion

* internal/ethapi: init feecap and tipcap for legacy txs too

* eth, graphql, internal, les: fix gas price suggestion on all combos

* internal/jsre/deps: handle decimal tipcap and feecap

* eth, internal: minor review fixes

* graphql, internal: export max fee cap RPC endpoint

* internal/ethapi: fix crash in transaction_args

* internal/ethapi: minor refactor to make the code safer

Co-authored-by: Ryan Schneider <ryanleeschneider@gmail.com>
Co-authored-by: lightclient@protonmail.com <lightclient@protonmail.com>
Co-authored-by: gary rong <garyrong0905@gmail.com>
Co-authored-by: Péter Szilágyi <peterke@gmail.com>
This commit is contained in:
Martin Holst Swende
2021-06-02 15:13:10 +02:00
committed by GitHub
parent 2dee31930c
commit 5cff9754d7
19 changed files with 410 additions and 159 deletions

View File

@ -20,6 +20,7 @@ import (
"bytes"
"context"
"errors"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
@ -37,6 +38,8 @@ type TransactionArgs struct {
To *common.Address `json:"to"`
Gas *hexutil.Uint64 `json:"gas"`
GasPrice *hexutil.Big `json:"gasPrice"`
FeeCap *hexutil.Big `json:"maxFeePerGas"`
Tip *hexutil.Big `json:"maxPriorityFeePerGas"`
Value *hexutil.Big `json:"value"`
Nonce *hexutil.Uint64 `json:"nonce"`
@ -72,12 +75,43 @@ func (arg *TransactionArgs) data() []byte {
// setDefaults fills in default values for unspecified tx fields.
func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error {
if args.GasPrice == nil {
price, err := b.SuggestPrice(ctx)
if err != nil {
return err
if args.GasPrice != nil && (args.FeeCap != nil || args.Tip != nil) {
return errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
}
// After london, default to 1559 unless gasPrice is set
head := b.CurrentHeader()
if b.ChainConfig().IsLondon(head.Number) && args.GasPrice == nil {
if args.Tip == nil {
tip, err := b.SuggestGasTipCap(ctx)
if err != nil {
return err
}
args.Tip = (*hexutil.Big)(tip)
}
if args.FeeCap == nil {
feeCap := new(big.Int).Add(
(*big.Int)(args.Tip),
new(big.Int).Mul(head.BaseFee, big.NewInt(2)),
)
args.FeeCap = (*hexutil.Big)(feeCap)
}
if args.FeeCap.ToInt().Cmp(args.Tip.ToInt()) < 0 {
return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", args.FeeCap, args.Tip)
}
} else {
if args.FeeCap != nil || args.Tip != nil {
return errors.New("maxFeePerGas or maxPriorityFeePerGas specified but london is not active yet")
}
if args.GasPrice == nil {
price, err := b.SuggestGasTipCap(ctx)
if err != nil {
return err
}
if b.ChainConfig().IsLondon(head.Number) {
price.Add(price, head.BaseFee)
}
args.GasPrice = (*hexutil.Big)(price)
}
args.GasPrice = (*hexutil.Big)(price)
}
if args.Value == nil {
args.Value = new(hexutil.Big)
@ -103,6 +137,8 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error {
From: args.From,
To: args.To,
GasPrice: args.GasPrice,
FeeCap: args.FeeCap,
Tip: args.Tip,
Value: args.Value,
Data: args.Data,
AccessList: args.AccessList,
@ -123,7 +159,11 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error {
}
// ToMessage converts TransactionArgs to the Message type used by the core evm
func (args *TransactionArgs) ToMessage(globalGasCap uint64) types.Message {
func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (types.Message, error) {
// Reject invalid combinations of pre- and post-1559 fee styles
if args.GasPrice != nil && (args.FeeCap != nil || args.Tip != nil) {
return types.Message{}, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
}
// Set sender address or use zero address if none specified.
addr := args.from()
@ -139,9 +179,34 @@ func (args *TransactionArgs) ToMessage(globalGasCap uint64) types.Message {
log.Warn("Caller gas above allowance, capping", "requested", gas, "cap", globalGasCap)
gas = globalGasCap
}
gasPrice := new(big.Int)
if args.GasPrice != nil {
gasPrice = args.GasPrice.ToInt()
var (
gasPrice *big.Int
feeCap *big.Int
tip *big.Int
)
if baseFee == nil {
// If there's no basefee, then it must be a non-1559 execution
gasPrice = new(big.Int)
if args.GasPrice != nil {
gasPrice = args.GasPrice.ToInt()
}
feeCap, tip = gasPrice, gasPrice
} else {
// A basefee is provided, necessitating 1559-type execution
if args.GasPrice != nil {
gasPrice = args.GasPrice.ToInt()
feeCap, tip = gasPrice, gasPrice
} else {
feeCap = new(big.Int)
if args.FeeCap != nil {
feeCap = args.FeeCap.ToInt()
}
tip = new(big.Int)
if args.Tip != nil {
tip = args.Tip.ToInt()
}
gasPrice = math.BigMin(new(big.Int).Add(tip, baseFee), feeCap)
}
}
value := new(big.Int)
if args.Value != nil {
@ -152,24 +217,32 @@ func (args *TransactionArgs) ToMessage(globalGasCap uint64) types.Message {
if args.AccessList != nil {
accessList = *args.AccessList
}
msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, nil, nil, data, accessList, false)
return msg
msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, feeCap, tip, data, accessList, false)
return msg, nil
}
// toTransaction converts the arguments to a transaction.
// This assumes that setDefaults has been called.
func (args *TransactionArgs) toTransaction() *types.Transaction {
var data types.TxData
if args.AccessList == nil {
data = &types.LegacyTx{
To: args.To,
Nonce: uint64(*args.Nonce),
Gas: uint64(*args.Gas),
GasPrice: (*big.Int)(args.GasPrice),
Value: (*big.Int)(args.Value),
Data: args.data(),
switch {
case args.FeeCap != nil:
al := types.AccessList{}
if args.AccessList != nil {
al = *args.AccessList
}
} else {
data = &types.DynamicFeeTx{
To: args.To,
ChainID: (*big.Int)(args.ChainID),
Nonce: uint64(*args.Nonce),
Gas: uint64(*args.Gas),
FeeCap: (*big.Int)(args.FeeCap),
Tip: (*big.Int)(args.Tip),
Value: (*big.Int)(args.Value),
Data: args.data(),
AccessList: al,
}
case args.AccessList != nil:
data = &types.AccessListTx{
To: args.To,
ChainID: (*big.Int)(args.ChainID),
@ -180,6 +253,15 @@ func (args *TransactionArgs) toTransaction() *types.Transaction {
Data: args.data(),
AccessList: *args.AccessList,
}
default:
data = &types.LegacyTx{
To: args.To,
Nonce: uint64(*args.Nonce),
Gas: uint64(*args.Gas),
GasPrice: (*big.Int)(args.GasPrice),
Value: (*big.Int)(args.Value),
Data: args.data(),
}
}
return types.NewTx(data)
}