all: implement eip-1559 (#22837)

This commit is contained in:
Daniel Liu 2024-04-25 15:50:21 +08:00
parent 6a3b818069
commit e18553b855
37 changed files with 508 additions and 79 deletions

View file

@ -525,6 +525,8 @@ func (m callMsg) Nonce() uint64 { return 0 }
func (m callMsg) CheckNonce() bool { return false } func (m callMsg) CheckNonce() bool { return false }
func (m callMsg) To() *common.Address { return m.CallMsg.To } func (m callMsg) To() *common.Address { return m.CallMsg.To }
func (m callMsg) GasPrice() *big.Int { return m.CallMsg.GasPrice } 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) Gas() uint64 { return m.CallMsg.Gas }
func (m callMsg) Value() *big.Int { return m.CallMsg.Value } func (m callMsg) Value() *big.Int { return m.CallMsg.Value }
func (m callMsg) Data() []byte { return m.CallMsg.Data } func (m callMsg) Data() []byte { return m.CallMsg.Data }

View file

@ -4,6 +4,7 @@ import "math/big"
var MinGasPrice50x = big.NewInt(12500000000) var MinGasPrice50x = big.NewInt(12500000000)
var GasPrice50x = big.NewInt(12500000000) var GasPrice50x = big.NewInt(12500000000)
var BaseFee = big.NewInt(12500000000)
func GetGasFee(blockNumber, gas uint64) *big.Int { func GetGasFee(blockNumber, gas uint64) *big.Int {
fee := new(big.Int).SetUint64(gas) fee := new(big.Int).SetUint64(gas)

View file

@ -241,6 +241,10 @@ func (x *XDPoS_v1) verifyCascadingFields(chain consensus.ChainReader, header *ty
if parent.Time.Uint64()+x.config.Period > header.Time.Uint64() { if parent.Time.Uint64()+x.config.Period > header.Time.Uint64() {
return utils.ErrInvalidTimestamp 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 { if number%x.config.Epoch != 0 {
return x.verifySeal(chain, header, parents, fullVerify) return x.verifySeal(chain, header, parents, fullVerify)

View file

@ -8,7 +8,6 @@ import (
"github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/crypto/sha3" "github.com/XinFinOrg/XDPoSChain/crypto/sha3"
"github.com/XinFinOrg/XDPoSChain/log"
"github.com/XinFinOrg/XDPoSChain/params" "github.com/XinFinOrg/XDPoSChain/params"
"github.com/XinFinOrg/XDPoSChain/rlp" "github.com/XinFinOrg/XDPoSChain/rlp"
lru "github.com/hashicorp/golang-lru" 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) { func sigHash(header *types.Header) (hash common.Hash) {
hasher := sha3.NewKeccak256() hasher := sha3.NewKeccak256()
err := rlp.Encode(hasher, []interface{}{ enc := []interface{}{
header.ParentHash, header.ParentHash,
header.UncleHash, header.UncleHash,
header.Coinbase, 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.Extra[:len(header.Extra)-65], // Yes, this will panic if extra is too short
header.MixDigest, header.MixDigest,
header.Nonce, 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]) hasher.Sum(hash[:0])
return hash return hash
} }

View file

@ -20,7 +20,7 @@ import (
func sigHash(header *types.Header) (hash common.Hash) { func sigHash(header *types.Header) (hash common.Hash) {
hasher := sha3.NewKeccak256() hasher := sha3.NewKeccak256()
err := rlp.Encode(hasher, []interface{}{ enc := []interface{}{
header.ParentHash, header.ParentHash,
header.UncleHash, header.UncleHash,
header.Coinbase, header.Coinbase,
@ -38,10 +38,11 @@ func sigHash(header *types.Header) (hash common.Hash) {
header.Nonce, header.Nonce,
header.Validators, header.Validators,
header.Penalties, 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]) hasher.Sum(hash[:0])
return hash return hash
} }

View file

@ -94,7 +94,10 @@ func (x *XDPoS_v2) verifyHeader(chain consensus.ChainReader, header *types.Heade
if header.UncleHash != utils.UncleHash { if header.UncleHash != utils.UncleHash {
return utils.ErrInvalidUncleHash 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 { if header.Difficulty.Cmp(big.NewInt(1)) != 0 {
return utils.ErrInvalidDifficulty return utils.ErrInvalidDifficulty
} }

View file

@ -147,7 +147,7 @@ type SignerFn func(accounts.Account, []byte) ([]byte, error)
func sigHash(header *types.Header) (hash common.Hash) { func sigHash(header *types.Header) (hash common.Hash) {
hasher := sha3.NewKeccak256() hasher := sha3.NewKeccak256()
rlp.Encode(hasher, []interface{}{ enc := []interface{}{
header.ParentHash, header.ParentHash,
header.UncleHash, header.UncleHash,
header.Coinbase, 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.Extra[:len(header.Extra)-65], // Yes, this will panic if extra is too short
header.MixDigest, header.MixDigest,
header.Nonce, header.Nonce,
}) }
if header.BaseFee != nil {
enc = append(enc, header.BaseFee)
}
rlp.Encode(hasher, enc)
hasher.Sum(hash[:0]) hasher.Sum(hash[:0])
return hash return hash
} }

View file

@ -253,6 +253,10 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainReader, header, parent *
if header.GasUsed > header.GasLimit { if header.GasUsed > header.GasLimit {
return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", 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 // Verify that the gas limit remains within allowed bounds
diff := int64(parent.GasLimit) - int64(header.GasLimit) diff := int64(parent.GasLimit) - int64(header.GasLimit)

62
consensus/misc/eip1559.go Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
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 <nil>",
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
}
}

View file

@ -18,6 +18,7 @@ package core
import ( import (
"fmt" "fmt"
"math"
"math/big" "math/big"
"math/rand" "math/rand"
"sync" "sync"
@ -1431,7 +1432,7 @@ func TestEIP2718Transition(t *testing.T) {
// A sender who makes transactions, has some funds // A sender who makes transactions, has some funds
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
address = crypto.PubkeyToAddress(key.PublicKey) address = crypto.PubkeyToAddress(key.PublicKey)
funds = big.NewInt(1000000000) funds = big.NewInt(math.MaxInt64)
gspec = &Genesis{ gspec = &Genesis{
Config: &params.ChainConfig{ Config: &params.ChainConfig{
ChainId: new(big.Int).SetBytes([]byte("eip1559")), ChainId: new(big.Int).SetBytes([]byte("eip1559")),
@ -1458,7 +1459,7 @@ func TestEIP2718Transition(t *testing.T) {
byte(vm.SLOAD), byte(vm.SLOAD),
}, },
Nonce: 0, Nonce: 0,
Balance: big.NewInt(0), Balance: big.NewInt(50000000000),
}, },
}, },
} }
@ -1475,7 +1476,7 @@ func TestEIP2718Transition(t *testing.T) {
Nonce: 0, Nonce: 0,
To: &aa, To: &aa,
Gas: 30000, Gas: 30000,
GasPrice: big.NewInt(1), GasPrice: new(big.Int).Set(common.BaseFee),
AccessList: types.AccessList{{ AccessList: types.AccessList{{
Address: aa, Address: aa,
StorageKeys: []common.Hash{{0}}, StorageKeys: []common.Hash{{0}},

View file

@ -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 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())), Root: state.IntermediateRoot(chain.Config().IsEIP158(parent.Number())),
ParentHash: parent.Hash(), ParentHash: parent.Hash(),
Coinbase: parent.Coinbase(), 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), Number: new(big.Int).Add(parent.Number(), common.Big1),
Time: time, Time: time,
} }
header.BaseFee = misc.CalcBaseFee(chain.Config(), header)
return header
} }
// newCanonical creates a chain database, and injects a deterministic canonical // newCanonical creates a chain database, and injects a deterministic canonical

View file

@ -53,4 +53,8 @@ var (
// ErrGasUintOverflow is returned when calculating gas usage. // ErrGasUintOverflow is returned when calculating gas usage.
ErrGasUintOverflow = errors.New("gas uint64 overflow") 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")
) )

View file

@ -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 // If we don't have an explicit author (i.e. not mining), extract from the header
var ( var (
beneficiary common.Address beneficiary common.Address
baseFee *big.Int
random common.Hash random common.Hash
) )
if author == nil { if author == nil {
@ -38,6 +39,9 @@ func NewEVMBlockContext(header *types.Header, chain consensus.ChainContext, auth
} else { } else {
beneficiary = *author 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 // since xdpos chain do not use difficulty and mixdigest, we use hash of the block number as random
random = crypto.Keccak256Hash(header.Number.Bytes()) random = crypto.Keccak256Hash(header.Number.Bytes())
return vm.BlockContext{ return vm.BlockContext{
@ -48,6 +52,7 @@ func NewEVMBlockContext(header *types.Header, chain consensus.ChainContext, auth
BlockNumber: new(big.Int).Set(header.Number), BlockNumber: new(big.Int).Set(header.Number),
Time: new(big.Int).Set(header.Time), Time: new(big.Int).Set(header.Time),
Difficulty: new(big.Int).Set(header.Difficulty), Difficulty: new(big.Int).Set(header.Difficulty),
BaseFee: baseFee,
GasLimit: header.GasLimit, GasLimit: header.GasLimit,
Random: &random, Random: &random,
} }

View file

@ -264,6 +264,9 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block {
if g.Difficulty == nil { if g.Difficulty == nil {
head.Difficulty = params.GenesisDifficulty 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.Commit(false)
statedb.Database().TrieDB().Commit(root, true) statedb.Database().TrieDB().Commit(root, true)

View file

@ -118,7 +118,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, tra
} }
} }
statedb.Prepare(tx.Hash(), i) statedb.Prepare(tx.Hash(), i)
receipt, gas, err, tokenFeeUsed := applyTransaction(p.config, balanceFee, gp, statedb, coinbaseOwner, blockNumber, blockHash, tx, usedGas, vmenv) receipt, gas, err, tokenFeeUsed := applyTransaction(p.config, balanceFee, gp, statedb, coinbaseOwner, blockNumber, header.BaseFee, blockHash, tx, usedGas, vmenv)
if err != nil { if err != nil {
return nil, nil, 0, err return nil, nil, 0, err
} }
@ -198,7 +198,7 @@ func (p *StateProcessor) ProcessBlockNoValidator(cBlock *CalculatedBlock, stated
} }
} }
statedb.Prepare(tx.Hash(), i) statedb.Prepare(tx.Hash(), i)
receipt, gas, err, tokenFeeUsed := applyTransaction(p.config, balanceFee, gp, statedb, coinbaseOwner, blockNumber, blockHash, tx, usedGas, vmenv) receipt, gas, err, tokenFeeUsed := applyTransaction(p.config, balanceFee, gp, statedb, coinbaseOwner, blockNumber, header.BaseFee, blockHash, tx, usedGas, vmenv)
if err != nil { if err != nil {
return nil, nil, 0, err return nil, nil, 0, err
} }
@ -220,7 +220,7 @@ func (p *StateProcessor) ProcessBlockNoValidator(cBlock *CalculatedBlock, stated
return receipts, allLogs, *usedGas, nil return receipts, allLogs, *usedGas, nil
} }
func applyTransaction(config *params.ChainConfig, tokensFee map[common.Address]*big.Int, gp *GasPool, statedb *state.StateDB, coinbaseOwner common.Address, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, uint64, error, bool) { func applyTransaction(config *params.ChainConfig, tokensFee map[common.Address]*big.Int, gp *GasPool, statedb *state.StateDB, coinbaseOwner common.Address, blockNumber, baseFee *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, uint64, error, bool) {
to := tx.To() to := tx.To()
if to != nil { if to != nil {
if *to == common.BlockSignersBinary && config.IsTIPSigning(blockNumber) { if *to == common.BlockSignersBinary && config.IsTIPSigning(blockNumber) {
@ -246,7 +246,8 @@ func applyTransaction(config *params.ChainConfig, tokensFee map[common.Address]*
balanceFee = value balanceFee = value
} }
} }
msg, err := tx.AsMessage(types.MakeSigner(config, blockNumber), balanceFee, blockNumber) // msg, err := tx.AsMessage(types.MakeSigner(config, blockNumber), balanceFee, blockNumber)
msg, err := tx.AsMessage(types.MakeSigner(config, blockNumber), balanceFee, blockNumber, baseFee)
if err != nil { if err != nil {
return nil, 0, err, false return nil, 0, err, false
} }
@ -465,7 +466,7 @@ func ApplyTransaction(config *params.ChainConfig, tokensFee map[common.Address]*
blockContext := NewEVMBlockContext(header, bc, author) blockContext := NewEVMBlockContext(header, bc, author)
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, XDCxState, config, cfg) vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, XDCxState, config, cfg)
coinbaseOwner := getCoinbaseOwner(bc, statedb, header, author) coinbaseOwner := getCoinbaseOwner(bc, statedb, header, author)
return applyTransaction(config, tokensFee, gp, statedb, coinbaseOwner, header.Number, header.Hash(), tx, usedGas, vmenv) return applyTransaction(config, tokensFee, gp, statedb, coinbaseOwner, header.Number, header.BaseFee, header.Hash(), tx, usedGas, vmenv)
} }
func ApplySignTransaction(config *params.ChainConfig, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64) (*types.Receipt, uint64, error, bool) { func ApplySignTransaction(config *params.ChainConfig, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64) (*types.Receipt, uint64, error, bool) {

View file

@ -23,6 +23,7 @@ import (
"math/big" "math/big"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
cmath "github.com/XinFinOrg/XDPoSChain/common/math"
"github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/core/vm" "github.com/XinFinOrg/XDPoSChain/core/vm"
"github.com/XinFinOrg/XDPoSChain/log" "github.com/XinFinOrg/XDPoSChain/log"
@ -57,6 +58,8 @@ type StateTransition struct {
msg Message msg Message
gas uint64 gas uint64
gasPrice *big.Int gasPrice *big.Int
feeCap *big.Int
tip *big.Int
initialGas uint64 initialGas uint64
value *big.Int value *big.Int
data []byte data []byte
@ -71,6 +74,8 @@ type Message interface {
To() *common.Address To() *common.Address
GasPrice() *big.Int GasPrice() *big.Int
FeeCap() *big.Int
Tip() *big.Int
Gas() uint64 Gas() uint64
Value() *big.Int Value() *big.Int
@ -125,6 +130,8 @@ func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition
evm: evm, evm: evm,
msg: msg, msg: msg,
gasPrice: msg.GasPrice(), gasPrice: msg.GasPrice(),
feeCap: msg.FeeCap(),
tip: msg.Tip(),
value: msg.Value(), value: msg.Value(),
data: msg.Data(), data: msg.Data(),
state: evm.StateDB, state: evm.StateDB,
@ -197,19 +204,28 @@ func (st *StateTransition) buyGas() error {
} }
func (st *StateTransition) preCheck() error { func (st *StateTransition) preCheck() error {
// Make sure this transaction's nonce is correct // Make sure this transaction's nonce is correct.
if st.msg.CheckNonce() { msg := st.msg
// Make sure this transaction's nonce is correct. if msg.CheckNonce() {
stNonce := st.state.GetNonce(st.from().Address()) stNonce := st.state.GetNonce(msg.From())
if msgNonce := st.msg.Nonce(); stNonce < msgNonce { if msgNonce := msg.Nonce(); stNonce < msgNonce {
return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooHigh, 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 { } else if stNonce > msgNonce {
return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooLow, 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 { } else if stNonce+1 < stNonce {
return fmt.Errorf("%w: address %v, nonce: %d", ErrNonceMax, 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() 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)) st.state.AddBalance(owner, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice))
} }
} else { } 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 return ret, st.gasUsed(), vmerr != nil, nil, vmerr

View file

@ -48,6 +48,8 @@ func (m callMsg) Nonce() uint64 { return 0 }
func (m callMsg) CheckNonce() bool { return false } func (m callMsg) CheckNonce() bool { return false }
func (m callMsg) To() *common.Address { return m.CallMsg.To } func (m callMsg) To() *common.Address { return m.CallMsg.To }
func (m callMsg) GasPrice() *big.Int { return m.CallMsg.GasPrice } 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) Gas() uint64 { return m.CallMsg.Gas }
func (m callMsg) Value() *big.Int { return m.CallMsg.Value } func (m callMsg) Value() *big.Int { return m.CallMsg.Value }
func (m callMsg) Data() []byte { return m.CallMsg.Data } func (m callMsg) Data() []byte { return m.CallMsg.Data }

View file

@ -102,6 +102,8 @@ func (tx *AccessListTx) accessList() AccessList { return tx.AccessList }
func (tx *AccessListTx) data() []byte { return tx.Data } func (tx *AccessListTx) data() []byte { return tx.Data }
func (tx *AccessListTx) gas() uint64 { return tx.Gas } func (tx *AccessListTx) gas() uint64 { return tx.Gas }
func (tx *AccessListTx) gasPrice() *big.Int { return tx.GasPrice } 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) value() *big.Int { return tx.Value }
func (tx *AccessListTx) nonce() uint64 { return tx.Nonce } func (tx *AccessListTx) nonce() uint64 { return tx.Nonce }
func (tx *AccessListTx) to() *common.Address { return tx.To } func (tx *AccessListTx) to() *common.Address { return tx.To }

View file

@ -81,6 +81,9 @@ type Header struct {
Validators []byte `json:"validators" gencodec:"required"` Validators []byte `json:"validators" gencodec:"required"`
Validator []byte `json:"validator" gencodec:"required"` Validator []byte `json:"validator" gencodec:"required"`
Penalties []byte `json:"penalties" 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 // field type overrides for gencodec
@ -91,6 +94,7 @@ type headerMarshaling struct {
GasUsed hexutil.Uint64 GasUsed hexutil.Uint64
Time *hexutil.Big Time *hexutil.Big
Extra hexutil.Bytes Extra hexutil.Bytes
BaseFee *hexutil.Big
Hash common.Hash `json:"hash"` // adds call to Hash() in MarshalJSON Hash common.Hash `json:"hash"` // adds call to Hash() in MarshalJSON
} }
@ -264,6 +268,9 @@ func CopyHeader(h *Header) *Header {
if cpy.Number = new(big.Int); h.Number != nil { if cpy.Number = new(big.Int); h.Number != nil {
cpy.Number.Set(h.Number) cpy.Number.Set(h.Number)
} }
if h.BaseFee != nil {
cpy.BaseFee = new(big.Int).Set(h.BaseFee)
}
if len(h.Extra) > 0 { if len(h.Extra) > 0 {
cpy.Extra = make([]byte, len(h.Extra)) cpy.Extra = make([]byte, len(h.Extra))
copy(cpy.Extra, h.Extra) copy(cpy.Extra, h.Extra)
@ -340,6 +347,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) Penalties() []byte { return common.CopyBytes(b.header.Penalties) }
func (b *Block) Validator() []byte { return common.CopyBytes(b.header.Validator) } 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) } func (b *Block) Header() *Header { return CopyHeader(b.header) }
// Body returns the non-header content of the block. // Body returns the non-header content of the block.

View file

@ -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 <http://www.gnu.org/licenses/>.
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
}

View file

@ -98,6 +98,8 @@ func (tx *LegacyTx) accessList() AccessList { return nil }
func (tx *LegacyTx) data() []byte { return tx.Data } func (tx *LegacyTx) data() []byte { return tx.Data }
func (tx *LegacyTx) gas() uint64 { return tx.Gas } func (tx *LegacyTx) gas() uint64 { return tx.Gas }
func (tx *LegacyTx) gasPrice() *big.Int { return tx.GasPrice } 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) value() *big.Int { return tx.Value }
func (tx *LegacyTx) nonce() uint64 { return tx.Nonce } func (tx *LegacyTx) nonce() uint64 { return tx.Nonce }
func (tx *LegacyTx) to() *common.Address { return tx.To } func (tx *LegacyTx) to() *common.Address { return tx.To }

View file

@ -124,10 +124,6 @@ func (r *Receipt) EncodeRLP(w io.Writer) error {
if r.Type == LegacyTxType { if r.Type == LegacyTxType {
return rlp.Encode(w, data) return rlp.Encode(w, data)
} }
// It's an EIP-2718 typed TX receipt.
if r.Type != AccessListTxType {
return ErrTxTypeNotSupported
}
buf := encodeBufferPool.Get().(*bytes.Buffer) buf := encodeBufferPool.Get().(*bytes.Buffer)
defer encodeBufferPool.Put(buf) defer encodeBufferPool.Put(buf)
buf.Reset() buf.Reset()
@ -163,7 +159,7 @@ func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
return errEmptyTypedReceipt return errEmptyTypedReceipt
} }
r.Type = b[0] r.Type = b[0]
if r.Type == AccessListTxType { if r.Type == AccessListTxType || r.Type == DynamicFeeTxType {
var dec receiptRLP var dec receiptRLP
if err := rlp.DecodeBytes(b[1:], &dec); err != nil { if err := rlp.DecodeBytes(b[1:], &dec); err != nil {
return err return err

View file

@ -27,6 +27,7 @@ import (
"time" "time"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/math"
"github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/rlp" "github.com/XinFinOrg/XDPoSChain/rlp"
) )
@ -56,6 +57,7 @@ var (
const ( const (
LegacyTxType = iota LegacyTxType = iota
AccessListTxType AccessListTxType
DynamicFeeTxType
) )
// Transaction is an Ethereum transaction. // Transaction is an Ethereum transaction.
@ -88,6 +90,8 @@ type TxData interface {
data() []byte data() []byte
gas() uint64 gas() uint64
gasPrice() *big.Int gasPrice() *big.Int
tip() *big.Int
feeCap() *big.Int
value() *big.Int value() *big.Int
nonce() uint64 nonce() uint64
to() *common.Address to() *common.Address
@ -191,6 +195,10 @@ func (tx *Transaction) decodeTyped(b []byte) (TxData, error) {
var inner AccessListTx var inner AccessListTx
err := rlp.DecodeBytes(b[1:], &inner) err := rlp.DecodeBytes(b[1:], &inner)
return &inner, err return &inner, err
case DynamicFeeTxType:
var inner DynamicFeeTx
err := rlp.DecodeBytes(b[1:], &inner)
return &inner, err
default: default:
return nil, ErrTxTypeNotSupported return nil, ErrTxTypeNotSupported
} }
@ -274,6 +282,12 @@ func (tx *Transaction) Gas() uint64 { return tx.inner.gas() }
// GasPrice returns the gas price of the transaction. // GasPrice returns the gas price of the transaction.
func (tx *Transaction) GasPrice() *big.Int { return new(big.Int).Set(tx.inner.gasPrice()) } 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. // Value returns the ether amount of the transaction.
func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.inner.value()) } 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. // 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, blockNumber, baseFee *big.Int) (Message, error) {
msg := Message{ msg := Message{
nonce: tx.Nonce(), nonce: tx.Nonce(),
gasLimit: tx.Gas(), gasLimit: tx.Gas(),
gasPrice: new(big.Int).Set(tx.GasPrice()), gasPrice: new(big.Int).Set(tx.GasPrice()),
feeCap: new(big.Int).Set(tx.FeeCap()),
tip: new(big.Int).Set(tx.Tip()),
to: tx.To(), to: tx.To(),
amount: tx.Value(), amount: tx.Value(),
data: tx.Data(), data: tx.Data(),
@ -364,17 +380,23 @@ func (tx *Transaction) AsMessage(s Signer, balanceFee *big.Int, number *big.Int)
balanceTokenFee: balanceFee, balanceTokenFee: balanceFee,
} }
if balanceFee != nil {
if blockNumber != nil {
if blockNumber.Cmp(common.BlockNumberGas50x) >= 0 {
msg.gasPrice = common.GasPrice50x
} else if blockNumber.Cmp(common.TIPTRC21Fee) > 0 {
msg.gasPrice = common.TRC21GasPrice
} else {
msg.gasPrice = common.TRC21GasPriceBefore
}
}
} else if baseFee != nil {
// If baseFee provided, set gasPrice to effectiveGasPrice.
msg.gasPrice = math.BigMin(msg.gasPrice.Add(msg.tip, baseFee), msg.feeCap)
}
var err error var err error
msg.from, err = Sender(s, tx) msg.from, err = Sender(s, tx)
if balanceFee != nil {
if number.Cmp(common.BlockNumberGas50x) >= 0 {
msg.gasPrice = common.GasPrice50x
} else if number.Cmp(common.TIPTRC21Fee) > 0 {
msg.gasPrice = common.TRC21GasPrice
} else {
msg.gasPrice = common.TRC21GasPriceBefore
}
}
return msg, err return msg, err
} }
@ -742,13 +764,15 @@ type Message struct {
amount *big.Int amount *big.Int
gasLimit uint64 gasLimit uint64
gasPrice *big.Int gasPrice *big.Int
feeCap *big.Int
tip *big.Int
data []byte data []byte
accessList AccessList accessList AccessList
checkNonce bool checkNonce bool
balanceTokenFee *big.Int 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 { if balanceTokenFee != nil {
gasPrice = common.GetGasPrice(number) gasPrice = common.GetGasPrice(number)
} }
@ -759,6 +783,8 @@ func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *b
amount: amount, amount: amount,
gasLimit: gasLimit, gasLimit: gasLimit,
gasPrice: gasPrice, gasPrice: gasPrice,
feeCap: feeCap,
tip: tip,
data: data, data: data,
accessList: accessList, accessList: accessList,
checkNonce: checkNonce, checkNonce: checkNonce,
@ -770,6 +796,8 @@ func (m Message) From() common.Address { return m.from }
func (m Message) BalanceTokenFee() *big.Int { return m.balanceTokenFee } func (m Message) BalanceTokenFee() *big.Int { return m.balanceTokenFee }
func (m Message) To() *common.Address { return m.to } func (m Message) To() *common.Address { return m.to }
func (m Message) GasPrice() *big.Int { return m.gasPrice } 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) Value() *big.Int { return m.amount }
func (m Message) Gas() uint64 { return m.gasLimit } func (m Message) Gas() uint64 { return m.gasLimit }
func (m Message) Nonce() uint64 { return m.nonce } func (m Message) Nonce() uint64 { return m.nonce }

View file

@ -14,15 +14,19 @@ type txJSON struct {
Type hexutil.Uint64 `json:"type"` Type hexutil.Uint64 `json:"type"`
// Common transaction fields: // Common transaction fields:
Nonce *hexutil.Uint64 `json:"nonce"` Nonce *hexutil.Uint64 `json:"nonce"`
GasPrice *hexutil.Big `json:"gasPrice"` GasPrice *hexutil.Big `json:"gasPrice"`
Gas *hexutil.Uint64 `json:"gas"` FeeCap *hexutil.Big `json:"feeCap"`
Value *hexutil.Big `json:"value"` Tip *hexutil.Big `json:"tip"`
Data *hexutil.Bytes `json:"input"` MaxPriorityFeePerGas *hexutil.Big `json:"maxPriorityFeePerGas"`
V *hexutil.Big `json:"v"` MaxFeePerGas *hexutil.Big `json:"maxFeePerGas"`
R *hexutil.Big `json:"r"` Gas *hexutil.Uint64 `json:"gas"`
S *hexutil.Big `json:"s"` Value *hexutil.Big `json:"value"`
To *common.Address `json:"to"` 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: // Access list transaction fields:
ChainID *hexutil.Big `json:"chainId,omitempty"` ChainID *hexutil.Big `json:"chainId,omitempty"`
@ -63,6 +67,19 @@ func (t *Transaction) MarshalJSON() ([]byte, error) {
enc.V = (*hexutil.Big)(tx.V) enc.V = (*hexutil.Big)(tx.V)
enc.R = (*hexutil.Big)(tx.R) enc.R = (*hexutil.Big)(tx.R)
enc.S = (*hexutil.Big)(tx.S) 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) 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: default:
return ErrTxTypeNotSupported return ErrTxTypeNotSupported
} }

View file

@ -42,7 +42,7 @@ func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer {
var signer Signer var signer Signer
switch { switch {
case config.IsEIP1559(blockNumber): case config.IsEIP1559(blockNumber):
signer = NewEIP2930Signer(config.ChainId) signer = NewLondonSigner(config.ChainId)
case config.IsEIP155(blockNumber): case config.IsEIP155(blockNumber):
signer = NewEIP155Signer(config.ChainId) signer = NewEIP155Signer(config.ChainId)
case config.IsHomestead(blockNumber): case config.IsHomestead(blockNumber):
@ -63,7 +63,7 @@ func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer {
func LatestSigner(config *params.ChainConfig) Signer { func LatestSigner(config *params.ChainConfig) Signer {
if config.ChainId != nil { if config.ChainId != nil {
if common.Eip1559Block.Uint64() != 9999999999 || config.Eip1559Block != nil { if common.Eip1559Block.Uint64() != 9999999999 || config.Eip1559Block != nil {
return NewEIP2930Signer(config.ChainId) return NewLondonSigner(config.ChainId)
} }
if config.EIP155Block != nil { if config.EIP155Block != nil {
return NewEIP155Signer(config.ChainId) return NewEIP155Signer(config.ChainId)
@ -83,7 +83,7 @@ func LatestSignerForChainID(chainID *big.Int) Signer {
if chainID == nil { if chainID == nil {
return HomesteadSigner{} return HomesteadSigner{}
} }
return NewEIP2930Signer(chainID) return NewLondonSigner(chainID)
} }
// SignTx signs the transaction using the given signer and private key. // SignTx signs the transaction using the given signer and private key.
@ -170,6 +170,72 @@ type Signer interface {
Equal(Signer) bool 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 } type eip2930Signer struct{ EIP155Signer }
// NewEIP2930Signer returns a signer that accepts EIP-2930 access list transactions, // 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: case LegacyTxType:
return s.EIP155Signer.Sender(tx) return s.EIP155Signer.Sender(tx)
case AccessListTxType: case AccessListTxType:
// ACL txs are defined to use 0 and 1 as their recovery id, add // AL txs are defined to use 0 and 1 as their recovery
// 27 to become equivalent to unprotected Homestead signatures. // id, add 27 to become equivalent to unprotected Homestead signatures.
V = new(big.Int).Add(V, big.NewInt(27)) V = new(big.Int).Add(V, big.NewInt(27))
default: default:
return common.Address{}, ErrTxTypeNotSupported return common.Address{}, ErrTxTypeNotSupported

View file

@ -158,7 +158,7 @@ func enable3198(jt *JumpTable) {
// opBaseFee implements BASEFEE opcode // opBaseFee implements BASEFEE opcode
func opBaseFee(pc *uint64, interpreter *EVMInterpreter, callContext *ScopeContext) ([]byte, error) { func opBaseFee(pc *uint64, interpreter *EVMInterpreter, callContext *ScopeContext) ([]byte, error) {
baseFee, _ := uint256.FromBig(common.MinGasPrice50x) baseFee, _ := uint256.FromBig(common.BaseFee)
callContext.Stack.push(baseFee) callContext.Stack.push(baseFee)
return nil, nil return nil, nil
} }

View file

@ -101,6 +101,7 @@ type BlockContext struct {
BlockNumber *big.Int // Provides information for NUMBER BlockNumber *big.Int // Provides information for NUMBER
Time *big.Int // Provides information for TIME Time *big.Int // Provides information for TIME
Difficulty *big.Int // Provides information for DIFFICULTY Difficulty *big.Int // Provides information for DIFFICULTY
BaseFee *big.Int // Provides information for BASEFEE
Random *common.Hash // Provides information for PREVRANDAO Random *common.Hash // Provides information for PREVRANDAO
} }

View file

@ -28,7 +28,6 @@ import (
"time" "time"
"github.com/XinFinOrg/XDPoSChain/XDCx/tradingstate" "github.com/XinFinOrg/XDPoSChain/XDCx/tradingstate"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/hexutil" "github.com/XinFinOrg/XDPoSChain/common/hexutil"
"github.com/XinFinOrg/XDPoSChain/core" "github.com/XinFinOrg/XDPoSChain/core"
@ -242,7 +241,8 @@ func (api *PrivateDebugAPI) traceChain(ctx context.Context, start, end *types.Bl
balance = value balance = value
} }
} }
msg, _ := tx.AsMessage(signer, balance, task.block.Number()) header := task.block.Header()
msg, _ := tx.AsMessage(signer, balance, header.Number, header.BaseFee)
txctx := &tracers.Context{ txctx := &tracers.Context{
BlockHash: task.block.Hash(), BlockHash: task.block.Hash(),
TxIndex: i, TxIndex: i,
@ -486,7 +486,8 @@ func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block,
balance = value balance = value
} }
} }
msg, _ := txs[task.index].AsMessage(signer, balance, block.Number()) header := block.Header()
msg, _ := txs[task.index].AsMessage(signer, balance, header.Number, header.BaseFee)
txctx := &tracers.Context{ txctx := &tracers.Context{
BlockHash: blockHash, BlockHash: blockHash,
TxIndex: task.index, TxIndex: task.index,
@ -518,7 +519,8 @@ func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block,
} }
} }
// Generate the next state snapshot fast without tracing // Generate the next state snapshot fast without tracing
msg, _ := tx.AsMessage(signer, balance, block.Number()) header := block.Header()
msg, _ := tx.AsMessage(signer, balance, header.Number, header.BaseFee)
txContext := core.NewEVMTxContext(msg) txContext := core.NewEVMTxContext(msg)
statedb.Prepare(tx.Hash(), i) statedb.Prepare(tx.Hash(), i)
@ -800,7 +802,8 @@ func (api *PrivateDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int, ree
balanceFee = value balanceFee = value
} }
} }
msg, err := tx.AsMessage(types.MakeSigner(api.config, block.Header().Number), balanceFee, block.Number()) header := block.Header()
msg, err := tx.AsMessage(types.MakeSigner(api.config, header.Number), balanceFee, header.Number, header.BaseFee)
if err != nil { if err != nil {
return nil, vm.BlockContext{}, nil, fmt.Errorf("tx %x failed: %v", tx.Hash(), err) return nil, vm.BlockContext{}, nil, fmt.Errorf("tx %x failed: %v", tx.Hash(), err)
} }

View file

@ -115,7 +115,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
t.Fatalf("failed to create call tracer: %v", err) t.Fatalf("failed to create call tracer: %v", err)
} }
evm := vm.NewEVM(context, txContext, statedb, nil, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer}) evm := vm.NewEVM(context, txContext, statedb, nil, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer})
msg, err := tx.AsMessage(signer, nil, nil) msg, err := tx.AsMessage(signer, nil, nil, nil)
if err != nil { if err != nil {
t.Fatalf("failed to prepare transaction for tracing: %v", err) t.Fatalf("failed to prepare transaction for tracing: %v", err)
} }
@ -201,7 +201,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
b.Fatalf("failed to parse testcase input: %v", err) b.Fatalf("failed to parse testcase input: %v", err)
} }
signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number))) signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)))
msg, err := tx.AsMessage(signer, nil, nil) msg, err := tx.AsMessage(signer, nil, nil, nil)
if err != nil { if err != nil {
b.Fatalf("failed to prepare transaction for tracing: %v", err) b.Fatalf("failed to prepare transaction for tracing: %v", err)
} }

View file

@ -153,7 +153,7 @@ func TestZeroValueToNotExitCall(t *testing.T) {
t.Fatalf("failed to create call tracer: %v", err) t.Fatalf("failed to create call tracer: %v", err)
} }
evm := vm.NewEVM(context, txContext, statedb, nil, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tracer}) evm := vm.NewEVM(context, txContext, statedb, nil, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tracer})
msg, err := tx.AsMessage(signer, nil, nil) msg, err := tx.AsMessage(signer, nil, nil, nil)
if err != nil { if err != nil {
t.Fatalf("failed to prepare transaction for tracing: %v", err) t.Fatalf("failed to prepare transaction for tracing: %v", err)
} }
@ -239,7 +239,7 @@ func TestPrestateTracerCreate2(t *testing.T) {
} }
evm := vm.NewEVM(context, txContext, statedb, nil, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tracer}) evm := vm.NewEVM(context, txContext, statedb, nil, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tracer})
msg, err := tx.AsMessage(signer, nil, nil) msg, err := tx.AsMessage(signer, nil, nil, nil)
if err != nil { if err != nil {
t.Fatalf("failed to prepare transaction for tracing: %v", err) t.Fatalf("failed to prepare transaction for tracing: %v", err)
} }
@ -336,7 +336,7 @@ func BenchmarkTransactionTrace(b *testing.B) {
//EnableReturnData: false, //EnableReturnData: false,
}) })
evm := vm.NewEVM(context, txContext, statedb, nil, params.AllEthashProtocolChanges, vm.Config{Debug: true, Tracer: tracer}) evm := vm.NewEVM(context, txContext, statedb, nil, params.AllEthashProtocolChanges, vm.Config{Debug: true, Tracer: tracer})
msg, err := tx.AsMessage(signer, nil, nil) msg, err := tx.AsMessage(signer, nil, nil, nil)
if err != nil { if err != nil {
b.Fatalf("failed to prepare transaction for tracing: %v", err) b.Fatalf("failed to prepare transaction for tracing: %v", err)
} }

View file

@ -120,7 +120,11 @@ type CallMsg struct {
Value *big.Int // amount of wei sent along with the call Value *big.Int // amount of wei sent along with the call
Data []byte // input data, usually an ABI-encoded contract method invocation Data []byte // input data, usually an ABI-encoded contract method invocation
BalanceTokenFee *big.Int 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 // A ContractCaller provides contract calls, essentially transactions that are executed by

View file

@ -1822,7 +1822,7 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber
result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber)) result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber))
result.TransactionIndex = (*hexutil.Uint64)(&index) result.TransactionIndex = (*hexutil.Uint64)(&index)
} }
if tx.Type() == types.AccessListTxType { if tx.Type() != types.LegacyTxType {
al := tx.AccessList() al := tx.AccessList()
result.Accesses = &al result.Accesses = &al
result.ChainID = (*hexutil.Big)(tx.ChainId()) result.ChainID = (*hexutil.Big)(tx.ChainId())
@ -1960,7 +1960,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH
if value, ok := feeCapacity[to]; ok { if value, ok := feeCapacity[to]; ok {
balanceTokenFee = value 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 // Apply the transaction with the access list tracer
tracer := vm.NewAccessListTracer(accessList, args.from(), to, precompiles) tracer := vm.NewAccessListTracer(accessList, args.from(), to, precompiles)

View file

@ -165,7 +165,7 @@ func (args *TransactionArgs) ToMessage(b Backend, number *big.Int, globalGasCap
} }
// Create new call message // 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 return msg
} }

View file

@ -133,7 +133,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
if value, ok := feeCapacity[testContractAddr]; ok { if value, ok := feeCapacity[testContractAddr]; ok {
balanceTokenFee = value 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) context := core.NewEVMBlockContext(header, bc, nil)
txContext := core.NewEVMTxContext(msg) 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 { if value, ok := feeCapacity[testContractAddr]; ok {
balanceTokenFee = value 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) context := core.NewEVMBlockContext(header, lc, nil)
txContext := core.NewEVMTxContext(msg) txContext := core.NewEVMTxContext(msg)
vmenv := vm.NewEVM(context, txContext, statedb, nil, config, vm.Config{}) vmenv := vm.NewEVM(context, txContext, statedb, nil, config, vm.Config{})

View file

@ -184,7 +184,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain
if value, ok := feeCapacity[testContractAddr]; ok { if value, ok := feeCapacity[testContractAddr]; ok {
balanceTokenFee = value 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) txContext := core.NewEVMTxContext(msg)
context := core.NewEVMBlockContext(header, chain, nil) context := core.NewEVMBlockContext(header, chain, nil)
vmenv := vm.NewEVM(context, txContext, st, nil, config, vm.Config{}) vmenv := vm.NewEVM(context, txContext, st, nil, config, vm.Config{})

View file

@ -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. 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 MaxCodeSize = 24576 // Maximum bytecode to permit for a contract
// Precompiled contract gas prices // Precompiled contract gas prices

View file

@ -241,7 +241,7 @@ func (tx *stTransaction) toMessage(ps stPostState, number *big.Int) (core.Messag
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid tx data %q", dataHex) 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 return msg, nil
} }