mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-25 16:06:18 +00:00
core, eth, internal, les: RPC methods and fields for EIP 1559 (#22964)
This commit is contained in:
parent
4f0317cb1f
commit
bfd1c0c9e0
15 changed files with 533 additions and 195 deletions
|
|
@ -83,7 +83,7 @@ type Header struct {
|
|||
Penalties []byte `json:"penalties" gencodec:"required"`
|
||||
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import (
|
|||
|
||||
var _ = (*headerMarshaling)(nil)
|
||||
|
||||
// MarshalJSON marshals as JSON.
|
||||
func (h Header) MarshalJSON() ([]byte, error) {
|
||||
type Header struct {
|
||||
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
|
||||
|
|
@ -30,6 +31,7 @@ func (h Header) MarshalJSON() ([]byte, error) {
|
|||
Extra hexutil.Bytes `json:"extraData" gencodec:"required"`
|
||||
MixDigest common.Hash `json:"mixHash" gencodec:"required"`
|
||||
Nonce BlockNonce `json:"nonce" gencodec:"required"`
|
||||
BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"`
|
||||
Hash common.Hash `json:"hash"`
|
||||
}
|
||||
var enc Header
|
||||
|
|
@ -48,10 +50,12 @@ func (h Header) MarshalJSON() ([]byte, error) {
|
|||
enc.Extra = h.Extra
|
||||
enc.MixDigest = h.MixDigest
|
||||
enc.Nonce = h.Nonce
|
||||
enc.BaseFee = (*hexutil.Big)(h.BaseFee)
|
||||
enc.Hash = h.Hash()
|
||||
return json.Marshal(&enc)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals from JSON.
|
||||
func (h *Header) UnmarshalJSON(input []byte) error {
|
||||
type Header struct {
|
||||
ParentHash *common.Hash `json:"parentHash" gencodec:"required"`
|
||||
|
|
@ -69,6 +73,7 @@ func (h *Header) UnmarshalJSON(input []byte) error {
|
|||
Extra *hexutil.Bytes `json:"extraData" gencodec:"required"`
|
||||
MixDigest *common.Hash `json:"mixHash" gencodec:"required"`
|
||||
Nonce *BlockNonce `json:"nonce" gencodec:"required"`
|
||||
BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"`
|
||||
}
|
||||
var dec Header
|
||||
if err := json.Unmarshal(input, &dec); err != nil {
|
||||
|
|
@ -134,5 +139,8 @@ func (h *Header) UnmarshalJSON(input []byte) error {
|
|||
return errors.New("missing required field 'nonce' for Header")
|
||||
}
|
||||
h.Nonce = *dec.Nonce
|
||||
if dec.BaseFee != nil {
|
||||
h.BaseFee = (*big.Int)(dec.BaseFee)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,19 @@
|
|||
// Copyright 2021 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
|
|
@ -16,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"`
|
||||
|
|
@ -72,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()
|
||||
|
|
@ -210,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)
|
||||
if dec.MaxPriorityFeePerGas == nil {
|
||||
return errors.New("missing required field 'maxPriorityFeePerGas' for txdata")
|
||||
}
|
||||
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)
|
||||
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")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -344,8 +344,8 @@ func (b *EthApiBackend) ProtocolVersion() int {
|
|||
return b.eth.EthVersion()
|
||||
}
|
||||
|
||||
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 {
|
||||
|
|
@ -393,6 +393,10 @@ func (b *EthApiBackend) GetEngine() consensus.Engine {
|
|||
return b.eth.engine
|
||||
}
|
||||
|
||||
func (b *EthApiBackend) CurrentHeader() *types.Header {
|
||||
return b.eth.blockchain.CurrentHeader()
|
||||
}
|
||||
|
||||
func (b *EthApiBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, checkLive bool) (*state.StateDB, error) {
|
||||
return b.eth.stateAtBlock(block, reexec, base, checkLive)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -691,7 +691,10 @@ func (api *PrivateDebugAPI) TraceCall(ctx context.Context, args ethapi.Transacti
|
|||
}
|
||||
}
|
||||
// Execute the trace
|
||||
msg := args.ToMessage(api.eth.ApiBackend, block.Number(), api.eth.ApiBackend.RPCGasCap())
|
||||
msg, err := args.ToMessage(api.eth.ApiBackend, block.Number(), api.eth.ApiBackend.RPCGasCap(), block.BaseFee())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vmctx := core.NewEVMBlockContext(block.Header(), api.eth.blockchain, nil)
|
||||
var traceConfig *TraceConfig
|
||||
if config != nil {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -103,8 +105,13 @@ func NewOracle(backend OracleBackend, params Config) *Oracle {
|
|||
}
|
||||
}
|
||||
|
||||
// SuggestPrice returns the recommended gas price.
|
||||
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()
|
||||
|
||||
|
|
@ -113,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()
|
||||
|
|
@ -123,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--
|
||||
|
|
@ -142,93 +149,116 @@ 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)
|
||||
}
|
||||
|
||||
// Check gas price min.
|
||||
minGasPrice := common.GetMinGasPrice(head.Number)
|
||||
if price.Cmp(minGasPrice) < 0 {
|
||||
price = new(big.Int).Set(minGasPrice)
|
||||
// Check min gas price for non-eip1559 block
|
||||
if head.BaseFee == nil {
|
||||
minGasPrice := common.GetMinGasPrice(head.Number)
|
||||
if price.Cmp(minGasPrice) < 0 {
|
||||
price = new(big.Int).Set(minGasPrice)
|
||||
}
|
||||
}
|
||||
|
||||
gpo.cacheLock.Lock()
|
||||
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
|
||||
}
|
||||
|
||||
// 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:
|
||||
}
|
||||
}
|
||||
|
|
|
|||
157
eth/gasprice/gasprice_test.go
Normal file
157
eth/gasprice/gasprice_test.go
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
// Copyright 2020 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package gasprice
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
"github.com/XinFinOrg/XDPoSChain/consensus/ethash"
|
||||
"github.com/XinFinOrg/XDPoSChain/core"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/vm"
|
||||
"github.com/XinFinOrg/XDPoSChain/crypto"
|
||||
"github.com/XinFinOrg/XDPoSChain/params"
|
||||
"github.com/XinFinOrg/XDPoSChain/rpc"
|
||||
)
|
||||
|
||||
type testBackend struct {
|
||||
chain *core.BlockChain
|
||||
}
|
||||
|
||||
func (b *testBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) {
|
||||
if number == rpc.LatestBlockNumber {
|
||||
return b.chain.CurrentBlock().Header(), nil
|
||||
}
|
||||
return b.chain.GetHeaderByNumber(uint64(number)), nil
|
||||
}
|
||||
|
||||
func (b *testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) {
|
||||
if number == rpc.LatestBlockNumber {
|
||||
return b.chain.CurrentBlock(), nil
|
||||
}
|
||||
return b.chain.GetBlockByNumber(uint64(number)), nil
|
||||
}
|
||||
|
||||
func (b *testBackend) ChainConfig() *params.ChainConfig {
|
||||
return b.chain.Config()
|
||||
}
|
||||
|
||||
func newTestBackend(t *testing.T, eip1559Block *big.Int) *testBackend {
|
||||
var (
|
||||
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
addr = crypto.PubkeyToAddress(key.PublicKey)
|
||||
gspec = &core.Genesis{
|
||||
Config: params.TestChainConfig,
|
||||
Alloc: core.GenesisAlloc{addr: {Balance: big.NewInt(math.MaxInt64)}},
|
||||
}
|
||||
signer = types.LatestSigner(gspec.Config)
|
||||
)
|
||||
if eip1559Block != nil {
|
||||
gspec.Config.Eip1559Block = eip1559Block
|
||||
signer = types.LatestSigner(gspec.Config)
|
||||
}
|
||||
engine := ethash.NewFaker()
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
genesis, _ := gspec.Commit(db)
|
||||
|
||||
// Generate testing blocks
|
||||
blocks, _ := core.GenerateChain(gspec.Config, genesis, engine, db, 32, func(i int, b *core.BlockGen) {
|
||||
b.SetCoinbase(common.Address{1})
|
||||
|
||||
var tx *types.Transaction
|
||||
if eip1559Block != nil && b.Number().Cmp(eip1559Block) >= 0 {
|
||||
txdata := &types.DynamicFeeTx{
|
||||
ChainID: gspec.Config.ChainId,
|
||||
Nonce: b.TxNonce(addr),
|
||||
To: &common.Address{},
|
||||
Gas: 30000,
|
||||
FeeCap: big.NewInt(100 * params.GWei),
|
||||
Tip: big.NewInt(int64(i+1) * params.GWei),
|
||||
Data: []byte{},
|
||||
}
|
||||
tx = types.NewTx(txdata)
|
||||
} else {
|
||||
txdata := &types.LegacyTx{
|
||||
Nonce: b.TxNonce(addr),
|
||||
To: &common.Address{},
|
||||
Gas: 21000,
|
||||
GasPrice: big.NewInt(int64(i+1) * params.GWei),
|
||||
Value: big.NewInt(100),
|
||||
Data: []byte{},
|
||||
}
|
||||
tx = types.NewTx(txdata)
|
||||
}
|
||||
tx, err := types.SignTx(tx, signer, key)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tx: %v", err)
|
||||
}
|
||||
b.AddTx(tx)
|
||||
})
|
||||
// Construct testing chain
|
||||
diskdb := rawdb.NewMemoryDatabase()
|
||||
gspec.Commit(diskdb)
|
||||
chain, err := core.NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create local chain, %v", err)
|
||||
}
|
||||
chain.InsertChain(blocks)
|
||||
return &testBackend{chain: chain}
|
||||
}
|
||||
|
||||
func (b *testBackend) CurrentHeader() *types.Header {
|
||||
return b.chain.CurrentHeader()
|
||||
}
|
||||
|
||||
func (b *testBackend) GetBlockByNumber(number uint64) *types.Block {
|
||||
return b.chain.GetBlockByNumber(number)
|
||||
}
|
||||
|
||||
func TestSuggestTipCap(t *testing.T) {
|
||||
config := Config{
|
||||
Blocks: 3,
|
||||
Percentile: 60,
|
||||
Default: big.NewInt(params.GWei),
|
||||
}
|
||||
var cases = []struct {
|
||||
fork *big.Int // Eip1559 fork number
|
||||
expect *big.Int // Expected gasprice suggestion
|
||||
}{
|
||||
{nil, big.NewInt(params.GWei * int64(30))},
|
||||
{big.NewInt(0), big.NewInt(params.GWei * int64(30))}, // Fork point in genesis
|
||||
{big.NewInt(1), big.NewInt(params.GWei * int64(30))}, // Fork point in first block
|
||||
{big.NewInt(32), big.NewInt(params.GWei * int64(30))}, // Fork point in last block
|
||||
{big.NewInt(33), big.NewInt(params.GWei * int64(30))}, // Fork point in the future
|
||||
}
|
||||
for _, c := range cases {
|
||||
backend := newTestBackend(t, c.fork)
|
||||
oracle := NewOracle(backend, config)
|
||||
|
||||
// The gas price sampled is: 32G, 31G, 30G, 29G, 28G, 27G
|
||||
got, err := oracle.SuggestTipCap(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to retrieve recommended gas price: %v", err)
|
||||
}
|
||||
if got.Cmp(c.expect) != 0 {
|
||||
t.Fatalf("Gas price mismatch, want %d, got %d", c.expect, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -816,8 +816,11 @@ func (s *Service) reportStats(conn *connWrapper) error {
|
|||
sync := s.eth.Downloader().Progress()
|
||||
syncing = s.eth.BlockChain().CurrentHeader().Number.Uint64() >= sync.HighestBlock
|
||||
|
||||
price, _ := s.eth.ApiBackend.SuggestPrice(context.Background())
|
||||
gasprice = int(price.Uint64())
|
||||
tipcap, _ := s.eth.ApiBackend.SuggestGasTipCap(context.Background())
|
||||
if head := s.eth.ApiBackend.CurrentHeader(); head.BaseFee != nil {
|
||||
tipcap.Add(tipcap, head.BaseFee)
|
||||
}
|
||||
gasprice = int(tipcap.Uint64())
|
||||
} else {
|
||||
sync := s.les.Downloader().Progress()
|
||||
syncing = s.les.BlockChain().CurrentHeader().Number.Uint64() >= sync.HighestBlock
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ import (
|
|||
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS"
|
||||
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils"
|
||||
"github.com/XinFinOrg/XDPoSChain/consensus/ethash"
|
||||
"github.com/XinFinOrg/XDPoSChain/consensus/misc"
|
||||
contractValidator "github.com/XinFinOrg/XDPoSChain/contracts/validator/contract"
|
||||
"github.com/XinFinOrg/XDPoSChain/core"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/state"
|
||||
|
|
@ -80,10 +81,25 @@ func NewPublicEthereumAPI(b Backend) *PublicEthereumAPI {
|
|||
return &PublicEthereumAPI{b}
|
||||
}
|
||||
|
||||
// GasPrice returns a suggestion for a gas price.
|
||||
// GasPrice returns a suggestion for a gas price for legacy transactions.
|
||||
func (s *PublicEthereumAPI) GasPrice(ctx context.Context) (*hexutil.Big, error) {
|
||||
price, err := s.b.SuggestPrice(ctx)
|
||||
return (*hexutil.Big)(price), err
|
||||
tipcap, err := s.b.SuggestGasTipCap(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if head := s.b.CurrentHeader(); head.BaseFee != nil {
|
||||
tipcap.Add(tipcap, head.BaseFee)
|
||||
}
|
||||
return (*hexutil.Big)(tipcap), err
|
||||
}
|
||||
|
||||
// MaxPriorityFeePerGas returns a suggestion for a gas tip cap for dynamic transactions.
|
||||
func (s *PublicEthereumAPI) MaxPriorityFeePerGas(ctx context.Context) (*hexutil.Big, error) {
|
||||
tipcap, err := s.b.SuggestGasTipCap(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return (*hexutil.Big)(tipcap), err
|
||||
}
|
||||
|
||||
// ProtocolVersion returns the current Ethereum protocol version this node supports
|
||||
|
|
@ -132,12 +148,12 @@ func (s *PublicTxPoolAPI) Content() map[string]map[string]map[string]*RPCTransac
|
|||
"queued": make(map[string]map[string]*RPCTransaction),
|
||||
}
|
||||
pending, queue := s.b.TxPoolContent()
|
||||
|
||||
curHeader := s.b.CurrentHeader()
|
||||
// Flatten the pending transactions
|
||||
for account, txs := range pending {
|
||||
dump := make(map[string]*RPCTransaction)
|
||||
for _, tx := range txs {
|
||||
dump[fmt.Sprintf("%d", tx.Nonce())] = newRPCPendingTransaction(tx)
|
||||
dump[fmt.Sprintf("%d", tx.Nonce())] = newRPCPendingTransaction(tx, curHeader, s.b.ChainConfig())
|
||||
}
|
||||
content["pending"][account.Hex()] = dump
|
||||
}
|
||||
|
|
@ -145,7 +161,7 @@ func (s *PublicTxPoolAPI) Content() map[string]map[string]map[string]*RPCTransac
|
|||
for account, txs := range queue {
|
||||
dump := make(map[string]*RPCTransaction)
|
||||
for _, tx := range txs {
|
||||
dump[fmt.Sprintf("%d", tx.Nonce())] = newRPCPendingTransaction(tx)
|
||||
dump[fmt.Sprintf("%d", tx.Nonce())] = newRPCPendingTransaction(tx, curHeader, s.b.ChainConfig())
|
||||
}
|
||||
content["queued"][account.Hex()] = dump
|
||||
}
|
||||
|
|
@ -1261,7 +1277,10 @@ func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash
|
|||
return nil, 0, false, err, nil
|
||||
}
|
||||
|
||||
msg := args.ToMessage(b, header.Number, globalGasCap)
|
||||
msg, err := args.ToMessage(b, header.Number, globalGasCap, header.BaseFee)
|
||||
if err != nil {
|
||||
return nil, 0, false, err, nil
|
||||
}
|
||||
msg.SetBalanceTokenFeeForCall()
|
||||
|
||||
// Setup context so it may be cancelled the call has completed
|
||||
|
|
@ -1558,14 +1577,11 @@ func FormatLogs(logs []vm.StructLog) []StructLogRes {
|
|||
return formatted
|
||||
}
|
||||
|
||||
// rpcOutputBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are
|
||||
// returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain
|
||||
// transaction hashes.
|
||||
func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx bool, ctx context.Context) (map[string]interface{}, error) {
|
||||
head := b.Header() // copies the header once
|
||||
fields := map[string]interface{}{
|
||||
// RPCMarshalHeader converts the given header to the RPC output .
|
||||
func RPCMarshalHeader(head *types.Header) map[string]interface{} {
|
||||
result := map[string]interface{}{
|
||||
"number": (*hexutil.Big)(head.Number),
|
||||
"hash": b.Hash(),
|
||||
"hash": head.Hash(),
|
||||
"parentHash": head.ParentHash,
|
||||
"nonce": head.Nonce,
|
||||
"mixHash": head.MixDigest,
|
||||
|
|
@ -1574,9 +1590,8 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx
|
|||
"stateRoot": head.Root,
|
||||
"miner": head.Coinbase,
|
||||
"difficulty": (*hexutil.Big)(head.Difficulty),
|
||||
"totalDifficulty": (*hexutil.Big)(s.b.GetTd(b.Hash())),
|
||||
"extraData": hexutil.Bytes(head.Extra),
|
||||
"size": hexutil.Uint64(b.Size()),
|
||||
"size": hexutil.Uint64(head.Size()),
|
||||
"gasLimit": hexutil.Uint64(head.GasLimit),
|
||||
"gasUsed": hexutil.Uint64(head.GasUsed),
|
||||
"timestamp": (*hexutil.Big)(head.Time),
|
||||
|
|
@ -1587,6 +1602,21 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx
|
|||
"penalties": hexutil.Bytes(head.Penalties),
|
||||
}
|
||||
|
||||
if head.BaseFee != nil {
|
||||
result["baseFeePerGas"] = (*hexutil.Big)(head.BaseFee)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// rpcOutputBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are
|
||||
// returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain
|
||||
// transaction hashes.
|
||||
func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx bool, ctx context.Context) (map[string]interface{}, error) {
|
||||
fields := RPCMarshalHeader(b.Header())
|
||||
fields["size"] = hexutil.Uint64(b.Size())
|
||||
fields["totalDifficulty"] = (*hexutil.Big)(s.b.GetTd(b.Hash()))
|
||||
|
||||
if inclTx {
|
||||
formatTx := func(tx *types.Transaction) (interface{}, error) {
|
||||
return tx.Hash(), nil
|
||||
|
|
@ -1773,6 +1803,8 @@ type RPCTransaction struct {
|
|||
From common.Address `json:"from"`
|
||||
Gas hexutil.Uint64 `json:"gas"`
|
||||
GasPrice *hexutil.Big `json:"gasPrice"`
|
||||
FeeCap *hexutil.Big `json:"maxFeePerGas,omitempty"`
|
||||
Tip *hexutil.Big `json:"maxPriorityFeePerGas,omitempty"`
|
||||
Hash common.Hash `json:"hash"`
|
||||
Input hexutil.Bytes `json:"input"`
|
||||
Nonce hexutil.Uint64 `json:"nonce"`
|
||||
|
|
@ -1789,7 +1821,7 @@ type RPCTransaction struct {
|
|||
|
||||
// newRPCTransaction returns a transaction that will serialize to the RPC
|
||||
// representation, with the given location metadata set (if available).
|
||||
func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64) *RPCTransaction {
|
||||
func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64, baseFee *big.Int) *RPCTransaction {
|
||||
// Determine the signer. For replay-protected transactions, use the most permissive
|
||||
// signer, because we assume that signers are backwards-compatible with old
|
||||
// transactions. For non-protected transactions, the homestead signer signer is used
|
||||
|
|
@ -1800,7 +1832,6 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber
|
|||
} else {
|
||||
signer = types.HomesteadSigner{}
|
||||
}
|
||||
|
||||
from, _ := types.Sender(signer, tx)
|
||||
v, r, s := tx.RawSignatureValues()
|
||||
result := &RPCTransaction{
|
||||
|
|
@ -1822,17 +1853,36 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber
|
|||
result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber))
|
||||
result.TransactionIndex = (*hexutil.Uint64)(&index)
|
||||
}
|
||||
if tx.Type() != types.LegacyTxType {
|
||||
switch tx.Type() {
|
||||
case types.AccessListTxType:
|
||||
al := tx.AccessList()
|
||||
result.Accesses = &al
|
||||
result.ChainID = (*hexutil.Big)(tx.ChainId())
|
||||
case types.DynamicFeeTxType:
|
||||
al := tx.AccessList()
|
||||
result.Accesses = &al
|
||||
result.ChainID = (*hexutil.Big)(tx.ChainId())
|
||||
result.FeeCap = (*hexutil.Big)(tx.FeeCap())
|
||||
result.Tip = (*hexutil.Big)(tx.Tip())
|
||||
// if the transaction has been mined, compute the effective gas price
|
||||
if baseFee != nil && blockHash != (common.Hash{}) {
|
||||
// price = min(tip, feeCap - baseFee) + baseFee = min(tip + baseFee, feeCap)
|
||||
price := math.BigMin(new(big.Int).Add(tx.Tip(), baseFee), tx.FeeCap())
|
||||
result.GasPrice = (*hexutil.Big)(price)
|
||||
} else {
|
||||
result.GasPrice = nil
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// newRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation
|
||||
func newRPCPendingTransaction(tx *types.Transaction) *RPCTransaction {
|
||||
return newRPCTransaction(tx, common.Hash{}, 0, 0)
|
||||
func newRPCPendingTransaction(tx *types.Transaction, current *types.Header, config *params.ChainConfig) *RPCTransaction {
|
||||
var baseFee *big.Int
|
||||
if current != nil {
|
||||
baseFee = misc.CalcBaseFee(config, current)
|
||||
}
|
||||
return newRPCTransaction(tx, common.Hash{}, 0, 0, baseFee)
|
||||
}
|
||||
|
||||
// newRPCTransactionFromBlockIndex returns a transaction that will serialize to the RPC representation.
|
||||
|
|
@ -1841,7 +1891,7 @@ func newRPCTransactionFromBlockIndex(b *types.Block, index uint64) *RPCTransacti
|
|||
if index >= uint64(len(txs)) {
|
||||
return nil
|
||||
}
|
||||
return newRPCTransaction(txs[index], b.Hash(), b.NumberU64(), index)
|
||||
return newRPCTransaction(txs[index], b.Hash(), b.NumberU64(), index, b.BaseFee())
|
||||
}
|
||||
|
||||
// newRPCRawTransactionFromBlockIndex returns the bytes of a transaction given a block and a transaction index.
|
||||
|
|
@ -2077,17 +2127,23 @@ func (s *PublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, addr
|
|||
}
|
||||
|
||||
// GetTransactionByHash returns the transaction for the given hash
|
||||
func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) *RPCTransaction {
|
||||
func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*RPCTransaction, error) {
|
||||
// Try to return an already finalized transaction
|
||||
if tx, blockHash, blockNumber, index := core.GetTransaction(s.b.ChainDb(), hash); tx != nil {
|
||||
return newRPCTransaction(tx, blockHash, blockNumber, index)
|
||||
tx, blockHash, blockNumber, index := core.GetTransaction(s.b.ChainDb(), hash)
|
||||
if tx != nil {
|
||||
header, err := s.b.HeaderByHash(ctx, blockHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newRPCTransaction(tx, blockHash, blockNumber, index, header.BaseFee), nil
|
||||
}
|
||||
// No finalized transaction, try to retrieve it from the pool
|
||||
if tx := s.b.GetPoolTransaction(hash); tx != nil {
|
||||
return newRPCPendingTransaction(tx)
|
||||
return newRPCPendingTransaction(tx, s.b.CurrentHeader(), s.b.ChainConfig()), nil
|
||||
}
|
||||
|
||||
// Transaction unknown, return as such
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetRawTransactionByHash returns the bytes of the transaction for the given hash.
|
||||
|
|
@ -3236,11 +3292,12 @@ func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, err
|
|||
accounts[account.Address] = struct{}{}
|
||||
}
|
||||
}
|
||||
curHeader := s.b.CurrentHeader()
|
||||
transactions := make([]*RPCTransaction, 0, len(pending))
|
||||
for _, tx := range pending {
|
||||
from, _ := types.Sender(s.signer, tx)
|
||||
if _, exists := accounts[from]; exists {
|
||||
transactions = append(transactions, newRPCPendingTransaction(tx))
|
||||
transactions = append(transactions, newRPCPendingTransaction(tx, curHeader, s.b.ChainConfig()))
|
||||
}
|
||||
}
|
||||
return transactions, nil
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ type Backend interface {
|
|||
// General Ethereum API
|
||||
Downloader() *downloader.Downloader
|
||||
ProtocolVersion() int
|
||||
SuggestPrice(ctx context.Context) (*big.Int, error)
|
||||
SuggestGasTipCap(ctx context.Context) (*big.Int, error)
|
||||
ChainDb() ethdb.Database
|
||||
AccountManager() *accounts.Manager
|
||||
RPCGasCap() uint64 // global gas cap for eth_call over rpc: DoS protection
|
||||
|
|
@ -61,6 +61,7 @@ type Backend interface {
|
|||
HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error)
|
||||
HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error)
|
||||
HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error)
|
||||
CurrentHeader() *types.Header
|
||||
BlockByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Block, error)
|
||||
BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error)
|
||||
BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import (
|
|||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/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().IsEIP1559(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().IsEIP1559(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)
|
||||
|
|
@ -104,6 +138,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: (*hexutil.Bytes)(&data),
|
||||
AccessList: args.AccessList,
|
||||
|
|
@ -124,7 +160,12 @@ 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(b Backend, number *big.Int, globalGasCap uint64) types.Message {
|
||||
func (args *TransactionArgs) ToMessage(b Backend, number *big.Int, 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()
|
||||
if addr == (common.Address{}) {
|
||||
|
|
@ -147,12 +188,38 @@ func (args *TransactionArgs) ToMessage(b Backend, number *big.Int, globalGasCap
|
|||
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()
|
||||
}
|
||||
if gasPrice.Sign() <= 0 {
|
||||
gasPrice = new(big.Int).SetUint64(defaultGasPrice)
|
||||
|
||||
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()
|
||||
}
|
||||
if gasPrice.Sign() <= 0 {
|
||||
gasPrice = new(big.Int).SetUint64(defaultGasPrice)
|
||||
}
|
||||
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 {
|
||||
|
|
@ -165,24 +232,32 @@ func (args *TransactionArgs) ToMessage(b Backend, number *big.Int, globalGasCap
|
|||
}
|
||||
|
||||
// Create new call message
|
||||
msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, nil, nil, data, accessList, false, nil, number)
|
||||
return msg
|
||||
msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, feeCap, tip, data, accessList, false, nil, number)
|
||||
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),
|
||||
|
|
@ -193,6 +268,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)
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -3766,7 +3766,7 @@ var inputTransactionFormatter = function (options){
|
|||
options.to = inputAddressFormatter(options.to);
|
||||
}
|
||||
|
||||
['gasPrice', 'gas', 'value', 'nonce'].filter(function (key) {
|
||||
['maxFeePerGas', 'maxPriorityFeePerGas', 'gasPrice', 'gas', 'value', 'nonce'].filter(function (key) {
|
||||
return options[key] !== undefined;
|
||||
}).forEach(function(key){
|
||||
options[key] = utils.fromDecimal(options[key]);
|
||||
|
|
@ -3790,6 +3790,12 @@ var outputTransactionFormatter = function (tx){
|
|||
tx.nonce = utils.toDecimal(tx.nonce);
|
||||
tx.gas = utils.toDecimal(tx.gas);
|
||||
tx.gasPrice = utils.toBigNumber(tx.gasPrice);
|
||||
if(tx.maxFeePerGas !== undefined) {
|
||||
tx.maxFeePerGas = utils.toBigNumber(tx.maxFeePerGas);
|
||||
}
|
||||
if(tx.maxPriorityFeePerGas !== undefined) {
|
||||
tx.maxPriorityFeePerGas = utils.toBigNumber(tx.maxPriorityFeePerGas);
|
||||
}
|
||||
tx.value = utils.toBigNumber(tx.value);
|
||||
return tx;
|
||||
};
|
||||
|
|
@ -3828,6 +3834,9 @@ var outputTransactionReceiptFormatter = function (receipt){
|
|||
var outputBlockFormatter = function(block) {
|
||||
|
||||
// transform to number
|
||||
if (block.baseFeePerGas !== undefined) {
|
||||
block.baseFeePerGas = utils.toBigNumber(block.baseFeePerGas);
|
||||
}
|
||||
block.gasLimit = utils.toDecimal(block.gasLimit);
|
||||
block.gasUsed = utils.toDecimal(block.gasUsed);
|
||||
block.size = utils.toDecimal(block.size);
|
||||
|
|
|
|||
|
|
@ -557,6 +557,11 @@ web3._extend({
|
|||
return formatted;
|
||||
}
|
||||
}),
|
||||
new web3._extend.Property({
|
||||
name: 'maxPriorityFeePerGas',
|
||||
getter: 'eth_maxPriorityFeePerGas',
|
||||
outputFormatter: web3._extend.utils.toBigNumber
|
||||
}),
|
||||
]
|
||||
});
|
||||
`
|
||||
|
|
|
|||
|
|
@ -269,8 +269,8 @@ func (b *LesApiBackend) ProtocolVersion() int {
|
|||
return b.eth.LesVersion() + 10000
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) SuggestPrice(ctx context.Context) (*big.Int, error) {
|
||||
return b.gpo.SuggestPrice(ctx)
|
||||
func (b *LesApiBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) {
|
||||
return b.gpo.SuggestTipCap(ctx)
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) ChainDb() ethdb.Database {
|
||||
|
|
@ -303,6 +303,10 @@ func (b *LesApiBackend) ServiceFilter(ctx context.Context, session *bloombits.Ma
|
|||
}
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) CurrentHeader() *types.Header {
|
||||
return b.eth.blockchain.CurrentHeader()
|
||||
}
|
||||
|
||||
// func (b *LesApiBackend) GetIPCClient() (*ethclient.Client, error) {
|
||||
func (b *LesApiBackend) GetIPCClient() (bind.ContractBackend, error) {
|
||||
// func (b *LesApiBackend) GetIPCClient() (bind.ContractBackend, error) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue