Skip to content

Commit

Permalink
all: implement eip-1559 (ethereum#22837)
Browse files Browse the repository at this point in the history
  • Loading branch information
gzliudan committed Aug 26, 2024
1 parent 3ca88af commit a082617
Show file tree
Hide file tree
Showing 37 changed files with 492 additions and 67 deletions.
2 changes: 2 additions & 0 deletions accounts/abi/bind/backends/simulated.go
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,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 }
Expand Down
1 change: 1 addition & 0 deletions common/gas.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 4 additions & 0 deletions consensus/XDPoS/engines/engine_v1/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
10 changes: 5 additions & 5 deletions consensus/XDPoS/engines/engine_v1/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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,
Expand All @@ -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
}
Expand Down
9 changes: 5 additions & 4 deletions consensus/XDPoS/engines/engine_v2/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
}
Expand Down
5 changes: 4 additions & 1 deletion consensus/XDPoS/engines/engine_v2/verifyHeader.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
8 changes: 6 additions & 2 deletions consensus/clique/clique.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
}
Expand Down
4 changes: 4 additions & 0 deletions consensus/ethash/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
62 changes: 62 additions & 0 deletions consensus/misc/eip1559.go
Original file line number Diff line number Diff line change
@@ -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
}
}
7 changes: 4 additions & 3 deletions core/blockchain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package core

import (
"fmt"
"math"
"math/big"
"math/rand"
"sync"
Expand Down Expand Up @@ -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: &params.ChainConfig{
ChainId: new(big.Int).SetBytes([]byte("eip1559")),
Expand All @@ -1455,7 +1456,7 @@ func TestEIP2718Transition(t *testing.T) {
byte(vm.SLOAD),
},
Nonce: 0,
Balance: big.NewInt(0),
Balance: big.NewInt(50000000000),
},
},
}
Expand All @@ -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}},
Expand Down
6 changes: 5 additions & 1 deletion core/chain_makers.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand All @@ -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
Expand Down
4 changes: 4 additions & 0 deletions core/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
)
5 changes: 5 additions & 0 deletions core/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,17 @@ func NewEVMContext(msg Message, header *types.Header, chain consensus.ChainConte
// 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 {
beneficiary, _ = chain.Engine().Author(header) // Ignore error, we're past header validation
} 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.Context{
Expand All @@ -49,6 +53,7 @@ func NewEVMContext(msg Message, header *types.Header, chain consensus.ChainConte
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,
GasPrice: new(big.Int).Set(msg.GasPrice()),
Random: &random,
Expand Down
3 changes: 3 additions & 0 deletions core/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
2 changes: 1 addition & 1 deletion core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,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), header.BaseFee, balanceFee, header.Number)
if err != nil {
return nil, 0, err, false
}
Expand Down
38 changes: 29 additions & 9 deletions core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand All @@ -71,6 +74,8 @@ type Message interface {
To() *common.Address

GasPrice() *big.Int
FeeCap() *big.Int
Tip() *big.Int
Gas() uint64
Value() *big.Int

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -286,7 +302,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.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.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), effectiveTip))
}

return ret, st.gasUsed(), vmerr != nil, nil, vmerr
Expand Down
2 changes: 2 additions & 0 deletions core/token_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
Loading

0 comments on commit a082617

Please sign in to comment.