diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go
index ba62d58a700a..411b53b23cb0 100644
--- a/accounts/abi/bind/backends/simulated.go
+++ b/accounts/abi/bind/backends/simulated.go
@@ -525,6 +525,8 @@ func (m callMsg) Nonce() uint64 { return 0 }
func (m callMsg) CheckNonce() bool { return false }
func (m callMsg) To() *common.Address { return m.CallMsg.To }
func (m callMsg) GasPrice() *big.Int { return m.CallMsg.GasPrice }
+func (m callMsg) FeeCap() *big.Int { return m.CallMsg.FeeCap }
+func (m callMsg) Tip() *big.Int { return m.CallMsg.Tip }
func (m callMsg) Gas() uint64 { return m.CallMsg.Gas }
func (m callMsg) Value() *big.Int { return m.CallMsg.Value }
func (m callMsg) Data() []byte { return m.CallMsg.Data }
diff --git a/common/gas.go b/common/gas.go
index a5b5690a7691..1e40721b145a 100644
--- a/common/gas.go
+++ b/common/gas.go
@@ -4,6 +4,7 @@ import "math/big"
var MinGasPrice50x = big.NewInt(12500000000)
var GasPrice50x = big.NewInt(12500000000)
+var BaseFee = big.NewInt(12500000000)
func GetGasFee(blockNumber, gas uint64) *big.Int {
fee := new(big.Int).SetUint64(gas)
diff --git a/consensus/XDPoS/engines/engine_v1/engine.go b/consensus/XDPoS/engines/engine_v1/engine.go
index c67dda874494..b1dcb9a7af6e 100644
--- a/consensus/XDPoS/engines/engine_v1/engine.go
+++ b/consensus/XDPoS/engines/engine_v1/engine.go
@@ -241,6 +241,10 @@ func (x *XDPoS_v1) verifyCascadingFields(chain consensus.ChainReader, header *ty
if parent.Time.Uint64()+x.config.Period > header.Time.Uint64() {
return utils.ErrInvalidTimestamp
}
+ // Verify the header's EIP-1559 attributes.
+ if err := misc.VerifyEip1559Header(chain.Config(), header); err != nil {
+ return err
+ }
if number%x.config.Epoch != 0 {
return x.verifySeal(chain, header, parents, fullVerify)
diff --git a/consensus/XDPoS/engines/engine_v1/utils.go b/consensus/XDPoS/engines/engine_v1/utils.go
index 56f1716a8379..a629c9a6913e 100644
--- a/consensus/XDPoS/engines/engine_v1/utils.go
+++ b/consensus/XDPoS/engines/engine_v1/utils.go
@@ -8,7 +8,6 @@ import (
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/crypto/sha3"
- "github.com/XinFinOrg/XDPoSChain/log"
"github.com/XinFinOrg/XDPoSChain/params"
"github.com/XinFinOrg/XDPoSChain/rlp"
lru "github.com/hashicorp/golang-lru"
@@ -62,7 +61,7 @@ func getM1M2(masternodes []common.Address, validators []int64, currentHeader *ty
func sigHash(header *types.Header) (hash common.Hash) {
hasher := sha3.NewKeccak256()
- err := rlp.Encode(hasher, []interface{}{
+ enc := []interface{}{
header.ParentHash,
header.UncleHash,
header.Coinbase,
@@ -78,10 +77,11 @@ func sigHash(header *types.Header) (hash common.Hash) {
header.Extra[:len(header.Extra)-65], // Yes, this will panic if extra is too short
header.MixDigest,
header.Nonce,
- })
- if err != nil {
- log.Debug("Fail to encode", err)
}
+ if header.BaseFee != nil {
+ enc = append(enc, header.BaseFee)
+ }
+ rlp.Encode(hasher, enc)
hasher.Sum(hash[:0])
return hash
}
diff --git a/consensus/XDPoS/engines/engine_v2/utils.go b/consensus/XDPoS/engines/engine_v2/utils.go
index 20198816280b..106d8c444bc8 100644
--- a/consensus/XDPoS/engines/engine_v2/utils.go
+++ b/consensus/XDPoS/engines/engine_v2/utils.go
@@ -19,7 +19,7 @@ import (
func sigHash(header *types.Header) (hash common.Hash) {
hasher := sha3.NewKeccak256()
- err := rlp.Encode(hasher, []interface{}{
+ enc := []interface{}{
header.ParentHash,
header.UncleHash,
header.Coinbase,
@@ -37,10 +37,11 @@ func sigHash(header *types.Header) (hash common.Hash) {
header.Nonce,
header.Validators,
header.Penalties,
- })
- if err != nil {
- log.Debug("Fail to encode", err)
}
+ if header.BaseFee != nil {
+ enc = append(enc, header.BaseFee)
+ }
+ rlp.Encode(hasher, enc)
hasher.Sum(hash[:0])
return hash
}
diff --git a/consensus/XDPoS/engines/engine_v2/verifyHeader.go b/consensus/XDPoS/engines/engine_v2/verifyHeader.go
index 7ba672bccbaa..518700fcc817 100644
--- a/consensus/XDPoS/engines/engine_v2/verifyHeader.go
+++ b/consensus/XDPoS/engines/engine_v2/verifyHeader.go
@@ -94,7 +94,10 @@ func (x *XDPoS_v2) verifyHeader(chain consensus.ChainReader, header *types.Heade
if header.UncleHash != utils.UncleHash {
return utils.ErrInvalidUncleHash
}
-
+ // Verify the header's EIP-1559 attributes.
+ if err := misc.VerifyEip1559Header(chain.Config(), header); err != nil {
+ return err
+ }
if header.Difficulty.Cmp(big.NewInt(1)) != 0 {
return utils.ErrInvalidDifficulty
}
diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go
index 9bae8fd7439c..3078d2966d76 100644
--- a/consensus/clique/clique.go
+++ b/consensus/clique/clique.go
@@ -147,7 +147,7 @@ type SignerFn func(accounts.Account, []byte) ([]byte, error)
func sigHash(header *types.Header) (hash common.Hash) {
hasher := sha3.NewKeccak256()
- rlp.Encode(hasher, []interface{}{
+ enc := []interface{}{
header.ParentHash,
header.UncleHash,
header.Coinbase,
@@ -163,7 +163,11 @@ func sigHash(header *types.Header) (hash common.Hash) {
header.Extra[:len(header.Extra)-65], // Yes, this will panic if extra is too short
header.MixDigest,
header.Nonce,
- })
+ }
+ if header.BaseFee != nil {
+ enc = append(enc, header.BaseFee)
+ }
+ rlp.Encode(hasher, enc)
hasher.Sum(hash[:0])
return hash
}
diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go
index faa4c5230250..7b978a6da1c3 100644
--- a/consensus/ethash/consensus.go
+++ b/consensus/ethash/consensus.go
@@ -253,6 +253,10 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainReader, header, parent *
if header.GasUsed > header.GasLimit {
return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit)
}
+ // Verify the header's EIP-1559 attributes.
+ if err := misc.VerifyEip1559Header(chain.Config(), header); err != nil {
+ return err
+ }
// Verify that the gas limit remains within allowed bounds
diff := int64(parent.GasLimit) - int64(header.GasLimit)
diff --git a/consensus/misc/eip1559.go b/consensus/misc/eip1559.go
new file mode 100644
index 000000000000..c993d97062a2
--- /dev/null
+++ b/consensus/misc/eip1559.go
@@ -0,0 +1,62 @@
+// 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 .
+
+package misc
+
+import (
+ "fmt"
+ "math/big"
+
+ "github.com/XinFinOrg/XDPoSChain/common"
+ "github.com/XinFinOrg/XDPoSChain/core/types"
+ "github.com/XinFinOrg/XDPoSChain/params"
+)
+
+// VerifyEip1559Header verifies some header attributes which were changed in EIP-1559,
+// - gas limit check
+// - basefee check
+func VerifyEip1559Header(config *params.ChainConfig, header *types.Header) error {
+ if !config.IsEIP1559(header.Number) {
+ if header.BaseFee != nil {
+ return fmt.Errorf("invalid baseFee: have %s, want ",
+ header.BaseFee)
+ }
+ return nil
+ }
+
+ // Verify the header is not malformed
+ if header.BaseFee == nil {
+ return fmt.Errorf("header is missing baseFee")
+ }
+
+ // Verify the baseFee is correct based on the current header.
+ expectedBaseFee := CalcBaseFee(config, header)
+ if header.BaseFee.Cmp(expectedBaseFee) != 0 {
+ return fmt.Errorf("invalid baseFee: have %s, want %s",
+ header.BaseFee, expectedBaseFee)
+ }
+ return nil
+}
+
+// CalcBaseFee calculates the basefee of the header.
+func CalcBaseFee(config *params.ChainConfig, header *types.Header) *big.Int {
+ // If the current block is the first EIP-1559 block, return the InitialBaseFee.
+ if config.IsEIP1559(header.Number) {
+ return new(big.Int).Set(common.BaseFee)
+ } else {
+ return nil
+ }
+}
diff --git a/core/blockchain_test.go b/core/blockchain_test.go
index d4f948b38932..b8c702423595 100644
--- a/core/blockchain_test.go
+++ b/core/blockchain_test.go
@@ -18,6 +18,7 @@ package core
import (
"fmt"
+ "math"
"math/big"
"math/rand"
"sync"
@@ -1428,7 +1429,7 @@ func TestEIP2718Transition(t *testing.T) {
// A sender who makes transactions, has some funds
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
address = crypto.PubkeyToAddress(key.PublicKey)
- funds = big.NewInt(1000000000)
+ funds = big.NewInt(math.MaxInt64)
gspec = &Genesis{
Config: ¶ms.ChainConfig{
ChainId: new(big.Int).SetBytes([]byte("eip1559")),
@@ -1455,7 +1456,7 @@ func TestEIP2718Transition(t *testing.T) {
byte(vm.SLOAD),
},
Nonce: 0,
- Balance: big.NewInt(0),
+ Balance: big.NewInt(50000000000),
},
},
}
@@ -1472,7 +1473,7 @@ func TestEIP2718Transition(t *testing.T) {
Nonce: 0,
To: &aa,
Gas: 30000,
- GasPrice: big.NewInt(1),
+ GasPrice: new(big.Int).Set(common.BaseFee),
AccessList: types.AccessList{{
Address: aa,
StorageKeys: []common.Hash{{0}},
diff --git a/core/chain_makers.go b/core/chain_makers.go
index 7a4012945f7d..32c9dcaca38c 100644
--- a/core/chain_makers.go
+++ b/core/chain_makers.go
@@ -265,7 +265,7 @@ func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.S
time = new(big.Int).Add(parent.Time(), big.NewInt(10)) // block time is fixed at 10 seconds
}
- return &types.Header{
+ header := &types.Header{
Root: state.IntermediateRoot(chain.Config().IsEIP158(parent.Number())),
ParentHash: parent.Hash(),
Coinbase: parent.Coinbase(),
@@ -279,6 +279,10 @@ func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.S
Number: new(big.Int).Add(parent.Number(), common.Big1),
Time: time,
}
+
+ header.BaseFee = misc.CalcBaseFee(chain.Config(), header)
+
+ return header
}
// newCanonical creates a chain database, and injects a deterministic canonical
diff --git a/core/error.go b/core/error.go
index 5503a6e6f2ef..fd45fdc73d3a 100644
--- a/core/error.go
+++ b/core/error.go
@@ -53,4 +53,8 @@ var (
// ErrGasUintOverflow is returned when calculating gas usage.
ErrGasUintOverflow = errors.New("gas uint64 overflow")
+
+ // ErrFeeCapTooLow is returned if the transaction fee cap is less than the
+ // the base fee of the block.
+ ErrFeeCapTooLow = errors.New("fee cap less than block base fee")
)
diff --git a/core/evm.go b/core/evm.go
index 48d0aca12239..9847a8d790b1 100644
--- a/core/evm.go
+++ b/core/evm.go
@@ -31,6 +31,7 @@ func NewEVMBlockContext(header *types.Header, chain consensus.ChainContext, auth
// If we don't have an explicit author (i.e. not mining), extract from the header
var (
beneficiary common.Address
+ baseFee *big.Int
random common.Hash
)
if author == nil {
@@ -38,6 +39,9 @@ func NewEVMBlockContext(header *types.Header, chain consensus.ChainContext, auth
} else {
beneficiary = *author
}
+ if header.BaseFee != nil {
+ baseFee = new(big.Int).Set(header.BaseFee)
+ }
// since xdpos chain do not use difficulty and mixdigest, we use hash of the block number as random
random = crypto.Keccak256Hash(header.Number.Bytes())
return vm.BlockContext{
@@ -48,6 +52,7 @@ func NewEVMBlockContext(header *types.Header, chain consensus.ChainContext, auth
BlockNumber: new(big.Int).Set(header.Number),
Time: new(big.Int).Set(header.Time),
Difficulty: new(big.Int).Set(header.Difficulty),
+ BaseFee: baseFee,
GasLimit: header.GasLimit,
Random: &random,
}
diff --git a/core/genesis.go b/core/genesis.go
index 2156ddc7259d..c45ec967a99c 100644
--- a/core/genesis.go
+++ b/core/genesis.go
@@ -264,6 +264,9 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block {
if g.Difficulty == nil {
head.Difficulty = params.GenesisDifficulty
}
+ if g.Config != nil && g.Config.IsEIP1559(common.Big0) {
+ head.BaseFee = new(big.Int).SetUint64(params.InitialBaseFee)
+ }
statedb.Commit(false)
statedb.Database().TrieDB().Commit(root, true)
diff --git a/core/state_processor.go b/core/state_processor.go
index 292538c39d7d..fa64ac059be6 100644
--- a/core/state_processor.go
+++ b/core/state_processor.go
@@ -240,7 +240,7 @@ func applyTransaction(config *params.ChainConfig, tokensFee map[common.Address]*
balanceFee = value
}
}
- msg, err := tx.AsMessage(types.MakeSigner(config, header.Number), balanceFee, header.Number)
+ msg, err := tx.AsMessage(types.MakeSigner(config, header.Number), balanceFee, header)
if err != nil {
return nil, 0, err, false
}
diff --git a/core/state_transition.go b/core/state_transition.go
index 92bbfcd41297..d1a1db534c4f 100644
--- a/core/state_transition.go
+++ b/core/state_transition.go
@@ -23,6 +23,7 @@ import (
"math/big"
"github.com/XinFinOrg/XDPoSChain/common"
+ cmath "github.com/XinFinOrg/XDPoSChain/common/math"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/core/vm"
"github.com/XinFinOrg/XDPoSChain/log"
@@ -57,6 +58,8 @@ type StateTransition struct {
msg Message
gas uint64
gasPrice *big.Int
+ feeCap *big.Int
+ tip *big.Int
initialGas uint64
value *big.Int
data []byte
@@ -71,6 +74,8 @@ type Message interface {
To() *common.Address
GasPrice() *big.Int
+ FeeCap() *big.Int
+ Tip() *big.Int
Gas() uint64
Value() *big.Int
@@ -125,6 +130,8 @@ func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition
evm: evm,
msg: msg,
gasPrice: msg.GasPrice(),
+ feeCap: msg.FeeCap(),
+ tip: msg.Tip(),
value: msg.Value(),
data: msg.Data(),
state: evm.StateDB,
@@ -197,19 +204,28 @@ func (st *StateTransition) buyGas() error {
}
func (st *StateTransition) preCheck() error {
- // Make sure this transaction's nonce is correct
- if st.msg.CheckNonce() {
- // Make sure this transaction's nonce is correct.
- stNonce := st.state.GetNonce(st.from().Address())
- if msgNonce := st.msg.Nonce(); stNonce < msgNonce {
+ // Make sure this transaction's nonce is correct.
+ msg := st.msg
+ if msg.CheckNonce() {
+ stNonce := st.state.GetNonce(msg.From())
+ if msgNonce := msg.Nonce(); stNonce < msgNonce {
return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooHigh,
- st.msg.From().Hex(), msgNonce, stNonce)
+ msg.From().Hex(), msgNonce, stNonce)
} else if stNonce > msgNonce {
return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooLow,
- st.msg.From().Hex(), msgNonce, stNonce)
+ msg.From().Hex(), msgNonce, stNonce)
} else if stNonce+1 < stNonce {
return fmt.Errorf("%w: address %v, nonce: %d", ErrNonceMax,
- st.msg.From().Hex(), stNonce)
+ msg.From().Hex(), stNonce)
+ }
+ }
+ // Make sure that transaction feeCap is greater than the baseFee (post london)
+ if st.evm.ChainConfig().IsEIP1559(st.evm.Context.BlockNumber) {
+ // This will panic if baseFee is nil, but basefee presence is verified
+ // as part of header validation.
+ if st.feeCap.Cmp(st.evm.Context.BaseFee) < 0 {
+ return fmt.Errorf("%w: address %v, feeCap: %s baseFee: %s", ErrFeeCapTooLow,
+ msg.From().Hex(), st.feeCap, st.evm.Context.BaseFee)
}
}
return st.buyGas()
@@ -307,7 +323,11 @@ func (st *StateTransition) TransitionDb(owner common.Address) (ret []byte, usedG
st.state.AddBalance(owner, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice))
}
} else {
- st.state.AddBalance(st.evm.Context.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice))
+ effectiveTip := st.gasPrice
+ if st.evm.ChainConfig().IsEIP1559(st.evm.Context.BlockNumber) {
+ effectiveTip = cmath.BigMin(st.tip, new(big.Int).Sub(st.feeCap, st.evm.Context.BaseFee))
+ }
+ st.state.AddBalance(st.evm.Context.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), effectiveTip))
}
return ret, st.gasUsed(), vmerr != nil, nil, vmerr
diff --git a/core/token_validator.go b/core/token_validator.go
index 59a4faa5a432..dae490946553 100644
--- a/core/token_validator.go
+++ b/core/token_validator.go
@@ -48,6 +48,8 @@ func (m callMsg) Nonce() uint64 { return 0 }
func (m callMsg) CheckNonce() bool { return false }
func (m callMsg) To() *common.Address { return m.CallMsg.To }
func (m callMsg) GasPrice() *big.Int { return m.CallMsg.GasPrice }
+func (m callMsg) FeeCap() *big.Int { return m.CallMsg.FeeCap }
+func (m callMsg) Tip() *big.Int { return m.CallMsg.Tip }
func (m callMsg) Gas() uint64 { return m.CallMsg.Gas }
func (m callMsg) Value() *big.Int { return m.CallMsg.Value }
func (m callMsg) Data() []byte { return m.CallMsg.Data }
diff --git a/core/types/access_list_tx.go b/core/types/access_list_tx.go
index f80044e108fa..2131a743f113 100644
--- a/core/types/access_list_tx.go
+++ b/core/types/access_list_tx.go
@@ -102,6 +102,8 @@ func (tx *AccessListTx) accessList() AccessList { return tx.AccessList }
func (tx *AccessListTx) data() []byte { return tx.Data }
func (tx *AccessListTx) gas() uint64 { return tx.Gas }
func (tx *AccessListTx) gasPrice() *big.Int { return tx.GasPrice }
+func (tx *AccessListTx) tip() *big.Int { return tx.GasPrice }
+func (tx *AccessListTx) feeCap() *big.Int { return tx.GasPrice }
func (tx *AccessListTx) value() *big.Int { return tx.Value }
func (tx *AccessListTx) nonce() uint64 { return tx.Nonce }
func (tx *AccessListTx) to() *common.Address { return tx.To }
diff --git a/core/types/block.go b/core/types/block.go
index 071666a801fa..e933c7613b4f 100644
--- a/core/types/block.go
+++ b/core/types/block.go
@@ -86,6 +86,9 @@ type Header struct {
Validators []byte `json:"validators" gencodec:"required"`
Validator []byte `json:"validator" gencodec:"required"`
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"`
}
// field type overrides for gencodec
@@ -96,6 +99,7 @@ type headerMarshaling struct {
GasUsed hexutil.Uint64
Time *hexutil.Big
Extra hexutil.Bytes
+ BaseFee *hexutil.Big
Hash common.Hash `json:"hash"` // adds call to Hash() in MarshalJSON
}
@@ -269,6 +273,9 @@ func CopyHeader(h *Header) *Header {
if cpy.Number = new(big.Int); h.Number != nil {
cpy.Number.Set(h.Number)
}
+ if h.BaseFee != nil {
+ cpy.BaseFee = new(big.Int).Set(h.BaseFee)
+ }
if len(h.Extra) > 0 {
cpy.Extra = make([]byte, len(h.Extra))
copy(cpy.Extra, h.Extra)
@@ -345,6 +352,13 @@ func (b *Block) Extra() []byte { return common.CopyBytes(b.header.Ext
func (b *Block) Penalties() []byte { return common.CopyBytes(b.header.Penalties) }
func (b *Block) Validator() []byte { return common.CopyBytes(b.header.Validator) }
+func (b *Block) BaseFee() *big.Int {
+ if b.header.BaseFee == nil {
+ return nil
+ }
+ return new(big.Int).Set(b.header.BaseFee)
+}
+
func (b *Block) Header() *Header { return CopyHeader(b.header) }
// Body returns the non-header content of the block.
diff --git a/core/types/dynamic_fee_tx.go b/core/types/dynamic_fee_tx.go
new file mode 100644
index 000000000000..ef4c66f2f58c
--- /dev/null
+++ b/core/types/dynamic_fee_tx.go
@@ -0,0 +1,104 @@
+// 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 .
+
+package types
+
+import (
+ "math/big"
+
+ "github.com/XinFinOrg/XDPoSChain/common"
+)
+
+type DynamicFeeTx struct {
+ ChainID *big.Int
+ Nonce uint64
+ Tip *big.Int
+ FeeCap *big.Int
+ Gas uint64
+ To *common.Address `rlp:"nil"` // nil means contract creation
+ Value *big.Int
+ Data []byte
+ AccessList AccessList
+
+ // Signature values
+ V *big.Int `json:"v" gencodec:"required"`
+ R *big.Int `json:"r" gencodec:"required"`
+ S *big.Int `json:"s" gencodec:"required"`
+}
+
+// copy creates a deep copy of the transaction data and initializes all fields.
+func (tx *DynamicFeeTx) copy() TxData {
+ cpy := &DynamicFeeTx{
+ Nonce: tx.Nonce,
+ To: tx.To, // TODO: copy pointed-to address
+ Data: common.CopyBytes(tx.Data),
+ Gas: tx.Gas,
+ // These are copied below.
+ AccessList: make(AccessList, len(tx.AccessList)),
+ Value: new(big.Int),
+ ChainID: new(big.Int),
+ Tip: new(big.Int),
+ FeeCap: new(big.Int),
+ V: new(big.Int),
+ R: new(big.Int),
+ S: new(big.Int),
+ }
+ copy(cpy.AccessList, tx.AccessList)
+ if tx.Value != nil {
+ cpy.Value.Set(tx.Value)
+ }
+ if tx.ChainID != nil {
+ cpy.ChainID.Set(tx.ChainID)
+ }
+ if tx.Tip != nil {
+ cpy.Tip.Set(tx.Tip)
+ }
+ if tx.FeeCap != nil {
+ cpy.FeeCap.Set(tx.FeeCap)
+ }
+ if tx.V != nil {
+ cpy.V.Set(tx.V)
+ }
+ if tx.R != nil {
+ cpy.R.Set(tx.R)
+ }
+ if tx.S != nil {
+ cpy.S.Set(tx.S)
+ }
+ return cpy
+}
+
+// accessors for innerTx.
+func (tx *DynamicFeeTx) txType() byte { return DynamicFeeTxType }
+func (tx *DynamicFeeTx) chainID() *big.Int { return tx.ChainID }
+func (tx *DynamicFeeTx) protected() bool { return true }
+func (tx *DynamicFeeTx) accessList() AccessList { return tx.AccessList }
+func (tx *DynamicFeeTx) data() []byte { return tx.Data }
+func (tx *DynamicFeeTx) gas() uint64 { return tx.Gas }
+func (tx *DynamicFeeTx) feeCap() *big.Int { return tx.FeeCap }
+func (tx *DynamicFeeTx) tip() *big.Int { return tx.Tip }
+func (tx *DynamicFeeTx) gasPrice() *big.Int { return tx.FeeCap }
+func (tx *DynamicFeeTx) value() *big.Int { return tx.Value }
+func (tx *DynamicFeeTx) nonce() uint64 { return tx.Nonce }
+func (tx *DynamicFeeTx) to() *common.Address { return tx.To }
+
+func (tx *DynamicFeeTx) rawSignatureValues() (v, r, s *big.Int) {
+ return tx.V, tx.R, tx.S
+}
+
+func (tx *DynamicFeeTx) setSignatureValues(chainID, v, r, s *big.Int) {
+ tx.ChainID, tx.V, tx.R, tx.S = chainID, v, r, s
+}
diff --git a/core/types/legacy_tx.go b/core/types/legacy_tx.go
index 146a1e2877e9..5593f87b3100 100644
--- a/core/types/legacy_tx.go
+++ b/core/types/legacy_tx.go
@@ -98,6 +98,8 @@ func (tx *LegacyTx) accessList() AccessList { return nil }
func (tx *LegacyTx) data() []byte { return tx.Data }
func (tx *LegacyTx) gas() uint64 { return tx.Gas }
func (tx *LegacyTx) gasPrice() *big.Int { return tx.GasPrice }
+func (tx *LegacyTx) tip() *big.Int { return tx.GasPrice }
+func (tx *LegacyTx) feeCap() *big.Int { return tx.GasPrice }
func (tx *LegacyTx) value() *big.Int { return tx.Value }
func (tx *LegacyTx) nonce() uint64 { return tx.Nonce }
func (tx *LegacyTx) to() *common.Address { return tx.To }
diff --git a/core/types/receipt.go b/core/types/receipt.go
index 9ac2616fe20d..ce6af8c2f68e 100644
--- a/core/types/receipt.go
+++ b/core/types/receipt.go
@@ -124,10 +124,6 @@ func (r *Receipt) EncodeRLP(w io.Writer) error {
if r.Type == LegacyTxType {
return rlp.Encode(w, data)
}
- // It's an EIP-2718 typed TX receipt.
- if r.Type != AccessListTxType {
- return ErrTxTypeNotSupported
- }
buf := encodeBufferPool.Get().(*bytes.Buffer)
defer encodeBufferPool.Put(buf)
buf.Reset()
@@ -163,7 +159,7 @@ func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
return errEmptyTypedReceipt
}
r.Type = b[0]
- if r.Type == AccessListTxType {
+ if r.Type == AccessListTxType || r.Type == DynamicFeeTxType {
var dec receiptRLP
if err := rlp.DecodeBytes(b[1:], &dec); err != nil {
return err
diff --git a/core/types/transaction.go b/core/types/transaction.go
index 1c02d70537c3..67c8a47dea3e 100644
--- a/core/types/transaction.go
+++ b/core/types/transaction.go
@@ -27,6 +27,7 @@ import (
"time"
"github.com/XinFinOrg/XDPoSChain/common"
+ "github.com/XinFinOrg/XDPoSChain/common/math"
"github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/rlp"
)
@@ -56,6 +57,7 @@ var (
const (
LegacyTxType = iota
AccessListTxType
+ DynamicFeeTxType
)
// Transaction is an Ethereum transaction.
@@ -88,6 +90,8 @@ type TxData interface {
data() []byte
gas() uint64
gasPrice() *big.Int
+ tip() *big.Int
+ feeCap() *big.Int
value() *big.Int
nonce() uint64
to() *common.Address
@@ -191,6 +195,10 @@ func (tx *Transaction) decodeTyped(b []byte) (TxData, error) {
var inner AccessListTx
err := rlp.DecodeBytes(b[1:], &inner)
return &inner, err
+ case DynamicFeeTxType:
+ var inner DynamicFeeTx
+ err := rlp.DecodeBytes(b[1:], &inner)
+ return &inner, err
default:
return nil, ErrTxTypeNotSupported
}
@@ -274,6 +282,12 @@ func (tx *Transaction) Gas() uint64 { return tx.inner.gas() }
// GasPrice returns the gas price of the transaction.
func (tx *Transaction) GasPrice() *big.Int { return new(big.Int).Set(tx.inner.gasPrice()) }
+// Tip returns the tip per gas of the transaction.
+func (tx *Transaction) Tip() *big.Int { return new(big.Int).Set(tx.inner.tip()) }
+
+// FeeCap returns the fee cap per gas of the transaction.
+func (tx *Transaction) FeeCap() *big.Int { return new(big.Int).Set(tx.inner.feeCap()) }
+
// Value returns the ether amount of the transaction.
func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.inner.value()) }
@@ -351,11 +365,13 @@ func (tx *Transaction) Size() common.StorageSize {
}
// AsMessage returns the transaction as a core.Message.
-func (tx *Transaction) AsMessage(s Signer, balanceFee *big.Int, number *big.Int) (Message, error) {
+func (tx *Transaction) AsMessage(s Signer, balanceFee *big.Int, header *Header) (Message, error) {
msg := Message{
nonce: tx.Nonce(),
gasLimit: tx.Gas(),
gasPrice: new(big.Int).Set(tx.GasPrice()),
+ feeCap: new(big.Int).Set(tx.FeeCap()),
+ tip: new(big.Int).Set(tx.Tip()),
to: tx.To(),
amount: tx.Value(),
data: tx.Data(),
@@ -364,17 +380,24 @@ func (tx *Transaction) AsMessage(s Signer, balanceFee *big.Int, number *big.Int)
balanceTokenFee: balanceFee,
}
- var err error
- msg.from, err = Sender(s, tx)
+ // If baseFee provided, set gasPrice to effectiveGasPrice.
+ if header != nil && header.BaseFee != nil {
+ msg.gasPrice = math.BigMin(msg.gasPrice.Add(msg.tip, header.BaseFee), msg.feeCap)
+ }
+
if balanceFee != nil {
- if number.Cmp(common.BlockNumberGas50x) >= 0 {
+ // header != nil when balanceFee != nil
+ if header.Number.Cmp(common.BlockNumberGas50x) >= 0 {
msg.gasPrice = common.GasPrice50x
- } else if number.Cmp(common.TIPTRC21Fee) > 0 {
+ } else if header.Number.Cmp(common.TIPTRC21Fee) > 0 {
msg.gasPrice = common.TRC21GasPrice
} else {
msg.gasPrice = common.TRC21GasPriceBefore
}
}
+
+ var err error
+ msg.from, err = Sender(s, tx)
return msg, err
}
@@ -742,13 +765,15 @@ type Message struct {
amount *big.Int
gasLimit uint64
gasPrice *big.Int
+ feeCap *big.Int
+ tip *big.Int
data []byte
accessList AccessList
checkNonce bool
balanceTokenFee *big.Int
}
-func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte, accessList AccessList, checkNonce bool, balanceTokenFee *big.Int, number *big.Int) Message {
+func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *big.Int, gasLimit uint64, gasPrice, feeCap, tip *big.Int, data []byte, accessList AccessList, checkNonce bool, balanceTokenFee *big.Int, number *big.Int) Message {
if balanceTokenFee != nil {
gasPrice = common.GetGasPrice(number)
}
@@ -759,6 +784,8 @@ func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *b
amount: amount,
gasLimit: gasLimit,
gasPrice: gasPrice,
+ feeCap: feeCap,
+ tip: tip,
data: data,
accessList: accessList,
checkNonce: checkNonce,
@@ -770,6 +797,8 @@ func (m Message) From() common.Address { return m.from }
func (m Message) BalanceTokenFee() *big.Int { return m.balanceTokenFee }
func (m Message) To() *common.Address { return m.to }
func (m Message) GasPrice() *big.Int { return m.gasPrice }
+func (m Message) FeeCap() *big.Int { return m.feeCap }
+func (m Message) Tip() *big.Int { return m.tip }
func (m Message) Value() *big.Int { return m.amount }
func (m Message) Gas() uint64 { return m.gasLimit }
func (m Message) Nonce() uint64 { return m.nonce }
diff --git a/core/types/transaction_marshalling.go b/core/types/transaction_marshalling.go
index 91403994bf7e..f4a47c7ee640 100644
--- a/core/types/transaction_marshalling.go
+++ b/core/types/transaction_marshalling.go
@@ -14,15 +14,19 @@ type txJSON struct {
Type hexutil.Uint64 `json:"type"`
// Common transaction fields:
- Nonce *hexutil.Uint64 `json:"nonce"`
- GasPrice *hexutil.Big `json:"gasPrice"`
- Gas *hexutil.Uint64 `json:"gas"`
- Value *hexutil.Big `json:"value"`
- Data *hexutil.Bytes `json:"input"`
- V *hexutil.Big `json:"v"`
- R *hexutil.Big `json:"r"`
- S *hexutil.Big `json:"s"`
- To *common.Address `json:"to"`
+ 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"`
+ Value *hexutil.Big `json:"value"`
+ Data *hexutil.Bytes `json:"input"`
+ V *hexutil.Big `json:"v"`
+ R *hexutil.Big `json:"r"`
+ S *hexutil.Big `json:"s"`
+ To *common.Address `json:"to"`
// Access list transaction fields:
ChainID *hexutil.Big `json:"chainId,omitempty"`
@@ -63,6 +67,19 @@ func (t *Transaction) MarshalJSON() ([]byte, error) {
enc.V = (*hexutil.Big)(tx.V)
enc.R = (*hexutil.Big)(tx.R)
enc.S = (*hexutil.Big)(tx.S)
+ case *DynamicFeeTx:
+ enc.ChainID = (*hexutil.Big)(tx.ChainID)
+ 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.Value = (*hexutil.Big)(tx.Value)
+ enc.Data = (*hexutil.Bytes)(&tx.Data)
+ enc.To = t.To()
+ enc.V = (*hexutil.Big)(tx.V)
+ enc.R = (*hexutil.Big)(tx.R)
+ enc.S = (*hexutil.Big)(tx.S)
}
return json.Marshal(&enc)
}
@@ -175,6 +192,75 @@ func (t *Transaction) UnmarshalJSON(input []byte) error {
}
}
+ case DynamicFeeTxType:
+ var itx DynamicFeeTx
+ inner = &itx
+ // Access list is optional for now.
+ if dec.AccessList != nil {
+ itx.AccessList = *dec.AccessList
+ }
+ if dec.ChainID == nil {
+ return errors.New("missing required field 'chainId' in transaction")
+ }
+ itx.ChainID = (*big.Int)(dec.ChainID)
+ if dec.To != nil {
+ itx.To = dec.To
+ }
+ if dec.Nonce == nil {
+ 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.Gas == nil {
+ return errors.New("missing required field 'gas' for txdata")
+ }
+ itx.Gas = uint64(*dec.Gas)
+ if dec.Value == nil {
+ return errors.New("missing required field 'value' in transaction")
+ }
+ itx.Value = (*big.Int)(dec.Value)
+ if dec.Data == nil {
+ return errors.New("missing required field 'input' in transaction")
+ }
+ itx.Data = *dec.Data
+ if dec.V == nil {
+ return errors.New("missing required field 'v' in transaction")
+ }
+ itx.V = (*big.Int)(dec.V)
+ if dec.R == nil {
+ return errors.New("missing required field 'r' in transaction")
+ }
+ itx.R = (*big.Int)(dec.R)
+ if dec.S == nil {
+ return errors.New("missing required field 's' in transaction")
+ }
+ itx.S = (*big.Int)(dec.S)
+ withSignature := itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0
+ if withSignature {
+ if err := sanityCheckSignature(itx.V, itx.R, itx.S, false); err != nil {
+ return err
+ }
+ }
+
default:
return ErrTxTypeNotSupported
}
diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go
index f4174dae4858..2715e718f98d 100644
--- a/core/types/transaction_signing.go
+++ b/core/types/transaction_signing.go
@@ -42,7 +42,7 @@ func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer {
var signer Signer
switch {
case config.IsEIP1559(blockNumber):
- signer = NewEIP2930Signer(config.ChainId)
+ signer = NewLondonSigner(config.ChainId)
case config.IsEIP155(blockNumber):
signer = NewEIP155Signer(config.ChainId)
case config.IsHomestead(blockNumber):
@@ -63,7 +63,7 @@ func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer {
func LatestSigner(config *params.ChainConfig) Signer {
if config.ChainId != nil {
if common.Eip1559Block.Uint64() != 9999999999 || config.Eip1559Block != nil {
- return NewEIP2930Signer(config.ChainId)
+ return NewLondonSigner(config.ChainId)
}
if config.EIP155Block != nil {
return NewEIP155Signer(config.ChainId)
@@ -83,7 +83,7 @@ func LatestSignerForChainID(chainID *big.Int) Signer {
if chainID == nil {
return HomesteadSigner{}
}
- return NewEIP2930Signer(chainID)
+ return NewLondonSigner(chainID)
}
// SignTx signs the transaction using the given signer and private key.
@@ -170,6 +170,72 @@ type Signer interface {
Equal(Signer) bool
}
+type londonSigner struct{ eip2930Signer }
+
+// NewLondonSigner returns a signer that accepts
+// - EIP-1559 dynamic fee transactions
+// - EIP-2930 access list transactions,
+// - EIP-155 replay protected transactions, and
+// - legacy Homestead transactions.
+func NewLondonSigner(chainId *big.Int) Signer {
+ return londonSigner{eip2930Signer{NewEIP155Signer(chainId)}}
+}
+
+func (s londonSigner) Sender(tx *Transaction) (common.Address, error) {
+ if tx.Type() != DynamicFeeTxType {
+ return s.eip2930Signer.Sender(tx)
+ }
+ V, R, S := tx.RawSignatureValues()
+ // DynamicFee txs are defined to use 0 and 1 as their recovery
+ // id, add 27 to become equivalent to unprotected Homestead signatures.
+ V = new(big.Int).Add(V, big.NewInt(27))
+ if tx.ChainId().Cmp(s.chainId) != 0 {
+ return common.Address{}, ErrInvalidChainId
+ }
+ return recoverPlain(s.Hash(tx), R, S, V, true)
+}
+
+func (s londonSigner) Equal(s2 Signer) bool {
+ x, ok := s2.(londonSigner)
+ return ok && x.chainId.Cmp(s.chainId) == 0
+}
+
+func (s londonSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) {
+ txdata, ok := tx.inner.(*DynamicFeeTx)
+ if !ok {
+ return s.eip2930Signer.SignatureValues(tx, sig)
+ }
+ // Check that chain ID of tx matches the signer. We also accept ID zero here,
+ // because it indicates that the chain ID was not specified in the tx.
+ if txdata.ChainID.Sign() != 0 && txdata.ChainID.Cmp(s.chainId) != 0 {
+ return nil, nil, nil, ErrInvalidChainId
+ }
+ R, S, _ = decodeSignature(sig)
+ V = big.NewInt(int64(sig[64]))
+ return R, S, V, nil
+}
+
+// Hash returns the hash to be signed by the sender.
+// It does not uniquely identify the transaction.
+func (s londonSigner) Hash(tx *Transaction) common.Hash {
+ if tx.Type() != DynamicFeeTxType {
+ return s.eip2930Signer.Hash(tx)
+ }
+ return prefixedRlpHash(
+ tx.Type(),
+ []interface{}{
+ s.chainId,
+ tx.Nonce(),
+ tx.Tip(),
+ tx.FeeCap(),
+ tx.Gas(),
+ tx.To(),
+ tx.Value(),
+ tx.Data(),
+ tx.AccessList(),
+ })
+}
+
type eip2930Signer struct{ EIP155Signer }
// NewEIP2930Signer returns a signer that accepts EIP-2930 access list transactions,
@@ -193,8 +259,8 @@ func (s eip2930Signer) Sender(tx *Transaction) (common.Address, error) {
case LegacyTxType:
return s.EIP155Signer.Sender(tx)
case AccessListTxType:
- // ACL txs are defined to use 0 and 1 as their recovery id, add
- // 27 to become equivalent to unprotected Homestead signatures.
+ // AL txs are defined to use 0 and 1 as their recovery
+ // id, add 27 to become equivalent to unprotected Homestead signatures.
V = new(big.Int).Add(V, big.NewInt(27))
default:
return common.Address{}, ErrTxTypeNotSupported
diff --git a/core/vm/eips.go b/core/vm/eips.go
index 19ea9a8980ff..2c4641d699d3 100644
--- a/core/vm/eips.go
+++ b/core/vm/eips.go
@@ -158,7 +158,7 @@ func enable3198(jt *JumpTable) {
// opBaseFee implements BASEFEE opcode
func opBaseFee(pc *uint64, interpreter *EVMInterpreter, callContext *ScopeContext) ([]byte, error) {
- baseFee, _ := uint256.FromBig(common.MinGasPrice50x)
+ baseFee, _ := uint256.FromBig(common.BaseFee)
callContext.Stack.push(baseFee)
return nil, nil
}
diff --git a/core/vm/evm.go b/core/vm/evm.go
index b34fe5cfb99f..f9f1966970a4 100644
--- a/core/vm/evm.go
+++ b/core/vm/evm.go
@@ -99,6 +99,7 @@ type BlockContext struct {
BlockNumber *big.Int // Provides information for NUMBER
Time *big.Int // Provides information for TIME
Difficulty *big.Int // Provides information for DIFFICULTY
+ BaseFee *big.Int // Provides information for BASEFEE
Random *common.Hash // Provides information for PREVRANDAO
}
diff --git a/eth/api_tracer.go b/eth/api_tracer.go
index 1b4b5adea129..33526d8b9655 100644
--- a/eth/api_tracer.go
+++ b/eth/api_tracer.go
@@ -28,7 +28,6 @@ import (
"time"
"github.com/XinFinOrg/XDPoSChain/XDCx/tradingstate"
-
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
"github.com/XinFinOrg/XDPoSChain/core"
@@ -242,7 +241,7 @@ func (api *PrivateDebugAPI) traceChain(ctx context.Context, start, end *types.Bl
balance = value
}
}
- msg, _ := tx.AsMessage(signer, balance, task.block.Number())
+ msg, _ := tx.AsMessage(signer, balance, task.block.Header())
txctx := &tracers.Context{
BlockHash: task.block.Hash(),
TxIndex: i,
@@ -486,7 +485,7 @@ func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block,
balance = value
}
}
- msg, _ := txs[task.index].AsMessage(signer, balance, block.Number())
+ msg, _ := txs[task.index].AsMessage(signer, balance, block.Header())
txctx := &tracers.Context{
BlockHash: blockHash,
TxIndex: task.index,
@@ -518,7 +517,7 @@ func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block,
}
}
// Generate the next state snapshot fast without tracing
- msg, _ := tx.AsMessage(signer, balance, block.Number())
+ msg, _ := tx.AsMessage(signer, balance, block.Header())
txContext := core.NewEVMTxContext(msg)
statedb.Prepare(tx.Hash(), block.Hash(), i)
@@ -800,7 +799,7 @@ func (api *PrivateDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int, ree
balanceFee = value
}
}
- msg, err := tx.AsMessage(types.MakeSigner(api.config, block.Header().Number), balanceFee, block.Number())
+ msg, err := tx.AsMessage(types.MakeSigner(api.config, block.Header().Number), balanceFee, block.Header())
if err != nil {
return nil, vm.BlockContext{}, nil, fmt.Errorf("tx %x failed: %v", tx.Hash(), err)
}
diff --git a/interfaces.go b/interfaces.go
index dfd96b217a1a..5d00baa5a0d7 100644
--- a/interfaces.go
+++ b/interfaces.go
@@ -120,7 +120,11 @@ type CallMsg struct {
Value *big.Int // amount of wei sent along with the call
Data []byte // input data, usually an ABI-encoded contract method invocation
BalanceTokenFee *big.Int
- AccessList types.AccessList // EIP-2930 access list.
+
+ FeeCap *big.Int // EIP-1559 fee cap per gas.
+ Tip *big.Int // EIP-1559 tip per gas.
+
+ AccessList types.AccessList // EIP-2930 access list.
}
// A ContractCaller provides contract calls, essentially transactions that are executed by
diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go
index 62e0f101ece4..0fd4d27aea8c 100644
--- a/internal/ethapi/api.go
+++ b/internal/ethapi/api.go
@@ -1816,7 +1816,7 @@ 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.AccessListTxType {
+ if tx.Type() != types.LegacyTxType {
al := tx.AccessList()
result.Accesses = &al
result.ChainID = (*hexutil.Big)(tx.ChainId())
@@ -1954,7 +1954,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH
if value, ok := feeCapacity[to]; ok {
balanceTokenFee = value
}
- msg := types.NewMessage(args.from(), args.To, uint64(*args.Nonce), args.Value.ToInt(), uint64(*args.Gas), args.GasPrice.ToInt(), args.data(), accessList, false, balanceTokenFee, header.Number)
+ msg := types.NewMessage(args.from(), args.To, uint64(*args.Nonce), args.Value.ToInt(), uint64(*args.Gas), args.GasPrice.ToInt(), nil, nil, args.data(), accessList, false, balanceTokenFee, header.Number)
// Apply the transaction with the access list tracer
tracer := vm.NewAccessListTracer(accessList, args.from(), to, precompiles)
diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go
index 48374f8fa9d8..f2df0a5b64e8 100644
--- a/internal/ethapi/transaction_args.go
+++ b/internal/ethapi/transaction_args.go
@@ -165,7 +165,7 @@ func (args *TransactionArgs) ToMessage(b Backend, number *big.Int, globalGasCap
}
// Create new call message
- msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, data, accessList, false, nil, number)
+ msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, nil, nil, data, accessList, false, nil, number)
return msg
}
diff --git a/les/odr_test.go b/les/odr_test.go
index 1495398379a0..7d9431dcf302 100644
--- a/les/odr_test.go
+++ b/les/odr_test.go
@@ -133,7 +133,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
if value, ok := feeCapacity[testContractAddr]; ok {
balanceTokenFee = value
}
- msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), 100000, new(big.Int), data, nil, false, balanceTokenFee, header.Number)}
+ msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), 100000, new(big.Int), nil, nil, data, nil, false, balanceTokenFee, header.Number)}
context := core.NewEVMBlockContext(header, bc, nil)
txContext := core.NewEVMTxContext(msg)
@@ -154,7 +154,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
if value, ok := feeCapacity[testContractAddr]; ok {
balanceTokenFee = value
}
- msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 100000, new(big.Int), data, nil, false, balanceTokenFee, header.Number)}
+ msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 100000, new(big.Int), nil, nil, data, nil, false, balanceTokenFee, header.Number)}
context := core.NewEVMBlockContext(header, lc, nil)
txContext := core.NewEVMTxContext(msg)
vmenv := vm.NewEVM(context, txContext, statedb, nil, config, vm.Config{})
diff --git a/light/odr_test.go b/light/odr_test.go
index c2c22d265712..7be95dd96975 100644
--- a/light/odr_test.go
+++ b/light/odr_test.go
@@ -184,7 +184,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain
if value, ok := feeCapacity[testContractAddr]; ok {
balanceTokenFee = value
}
- msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 1000000, new(big.Int), data, nil, false, balanceTokenFee, header.Number)}
+ msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 1000000, new(big.Int), nil, nil, data, nil, false, balanceTokenFee, header.Number)}
txContext := core.NewEVMTxContext(msg)
context := core.NewEVMBlockContext(header, chain, nil)
vmenv := vm.NewEVM(context, txContext, st, nil, config, vm.Config{})
diff --git a/params/protocol_params.go b/params/protocol_params.go
index fa013701e226..098f69403c60 100644
--- a/params/protocol_params.go
+++ b/params/protocol_params.go
@@ -67,6 +67,8 @@ const (
TxDataNonZeroGas uint64 = 68 // Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions.
+ InitialBaseFee = 12500000000 // Initial base fee for EIP-1559 blocks.
+
MaxCodeSize = 24576 // Maximum bytecode to permit for a contract
// Precompiled contract gas prices
diff --git a/tests/state_test_util.go b/tests/state_test_util.go
index afb35c9d02db..cc1e79223237 100644
--- a/tests/state_test_util.go
+++ b/tests/state_test_util.go
@@ -241,7 +241,7 @@ func (tx *stTransaction) toMessage(ps stPostState, number *big.Int) (core.Messag
if err != nil {
return nil, fmt.Errorf("invalid tx data %q", dataHex)
}
- msg := types.NewMessage(from, to, tx.Nonce, value, gasLimit, tx.GasPrice, data, nil, true, nil, number)
+ msg := types.NewMessage(from, to, tx.Nonce, value, gasLimit, tx.GasPrice, nil, nil, data, nil, true, nil, number)
return msg, nil
}