forked from cerc-io/plugeth
EIP-1559: miner changes (#22896)
* core/types, miner: create TxWithMinerFee wrapper, add EIP-1559 support to TransactionsByMinerFeeAndNonce miner: set base fee when creating a new header, handle gas limit, log miner fees * all: rename to NewTransactionsByPriceAndNonce * core/types, miner: rename to NewTransactionsByPriceAndNonce + EffectiveTip miner: activate 1559 for testGenerateBlockAndImport tests * core,miner: revert naming to TransactionsByPriceAndTime * core/types/transaction: update effective tip calculation logic * miner: update aleut to london * core/types/transaction_test: use correct signer for 1559 txs + add back sender check * miner/worker: calculate gas target from gas limit * core, miner: fix block gas limits for 1559 Co-authored-by: Ansgar Dietrichs <adietrichs@gmail.com> Co-authored-by: lightclient@protonmail.com <lightclient@protonmail.com>
This commit is contained in:
parent
16bc57438b
commit
a6c462781f
@ -112,7 +112,7 @@ func genTxRing(naccounts int) func(int, *BlockGen) {
|
|||||||
from := 0
|
from := 0
|
||||||
return func(i int, gen *BlockGen) {
|
return func(i int, gen *BlockGen) {
|
||||||
block := gen.PrevBlock(i - 1)
|
block := gen.PrevBlock(i - 1)
|
||||||
gas := CalcGasLimit(block, block.GasLimit(), block.GasLimit())
|
gas := block.GasLimit()
|
||||||
for {
|
for {
|
||||||
gas -= params.TxGas
|
gas -= params.TxGas
|
||||||
if gas < params.TxGas {
|
if gas < params.TxGas {
|
||||||
|
@ -106,12 +106,12 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
|
|||||||
// to keep the baseline gas above the provided floor, and increase it towards the
|
// to keep the baseline gas above the provided floor, and increase it towards the
|
||||||
// ceil if the blocks are full. If the ceil is exceeded, it will always decrease
|
// ceil if the blocks are full. If the ceil is exceeded, it will always decrease
|
||||||
// the gas allowance.
|
// the gas allowance.
|
||||||
func CalcGasLimit(parent *types.Block, gasFloor, gasCeil uint64) uint64 {
|
func CalcGasLimit(parentGasUsed, parentGasLimit, gasFloor, gasCeil uint64) uint64 {
|
||||||
// contrib = (parentGasUsed * 3 / 2) / 1024
|
// contrib = (parentGasUsed * 3 / 2) / 1024
|
||||||
contrib := (parent.GasUsed() + parent.GasUsed()/2) / params.GasLimitBoundDivisor
|
contrib := (parentGasUsed + parentGasUsed/2) / params.GasLimitBoundDivisor
|
||||||
|
|
||||||
// decay = parentGasLimit / 1024 -1
|
// decay = parentGasLimit / 1024 -1
|
||||||
decay := parent.GasLimit()/params.GasLimitBoundDivisor - 1
|
decay := parentGasLimit/params.GasLimitBoundDivisor - 1
|
||||||
|
|
||||||
/*
|
/*
|
||||||
strategy: gasLimit of block-to-mine is set based on parent's
|
strategy: gasLimit of block-to-mine is set based on parent's
|
||||||
@ -120,21 +120,45 @@ func CalcGasLimit(parent *types.Block, gasFloor, gasCeil uint64) uint64 {
|
|||||||
at that usage) the amount increased/decreased depends on how far away
|
at that usage) the amount increased/decreased depends on how far away
|
||||||
from parentGasLimit * (2/3) parentGasUsed is.
|
from parentGasLimit * (2/3) parentGasUsed is.
|
||||||
*/
|
*/
|
||||||
limit := parent.GasLimit() - decay + contrib
|
limit := parentGasLimit - decay + contrib
|
||||||
if limit < params.MinGasLimit {
|
if limit < params.MinGasLimit {
|
||||||
limit = params.MinGasLimit
|
limit = params.MinGasLimit
|
||||||
}
|
}
|
||||||
// If we're outside our allowed gas range, we try to hone towards them
|
// If we're outside our allowed gas range, we try to hone towards them
|
||||||
if limit < gasFloor {
|
if limit < gasFloor {
|
||||||
limit = parent.GasLimit() + decay
|
limit = parentGasLimit + decay
|
||||||
if limit > gasFloor {
|
if limit > gasFloor {
|
||||||
limit = gasFloor
|
limit = gasFloor
|
||||||
}
|
}
|
||||||
} else if limit > gasCeil {
|
} else if limit > gasCeil {
|
||||||
limit = parent.GasLimit() - decay
|
limit = parentGasLimit - decay
|
||||||
if limit < gasCeil {
|
if limit < gasCeil {
|
||||||
limit = gasCeil
|
limit = gasCeil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return limit
|
return limit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CalcGasLimit1559 calculates the next block gas limit under 1559 rules.
|
||||||
|
func CalcGasLimit1559(parentGasLimit, desiredLimit uint64) uint64 {
|
||||||
|
delta := parentGasLimit/params.GasLimitBoundDivisor - 1
|
||||||
|
limit := parentGasLimit
|
||||||
|
if desiredLimit < params.MinGasLimit {
|
||||||
|
desiredLimit = params.MinGasLimit
|
||||||
|
}
|
||||||
|
// If we're outside our allowed gas range, we try to hone towards them
|
||||||
|
if limit < desiredLimit {
|
||||||
|
limit = parentGasLimit + delta
|
||||||
|
if limit > desiredLimit {
|
||||||
|
limit = desiredLimit
|
||||||
|
}
|
||||||
|
return limit
|
||||||
|
}
|
||||||
|
if limit > desiredLimit {
|
||||||
|
limit = parentGasLimit - delta
|
||||||
|
if limit < desiredLimit {
|
||||||
|
limit = desiredLimit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return limit
|
||||||
|
}
|
||||||
|
@ -197,3 +197,36 @@ func testHeaderConcurrentAbortion(t *testing.T, threads int) {
|
|||||||
t.Errorf("verification count too large: have %d, want below %d", verified, 2*threads)
|
t.Errorf("verification count too large: have %d, want below %d", verified, 2*threads)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCalcGasLimit1559(t *testing.T) {
|
||||||
|
|
||||||
|
for i, tc := range []struct {
|
||||||
|
pGasLimit uint64
|
||||||
|
max uint64
|
||||||
|
min uint64
|
||||||
|
}{
|
||||||
|
{20000000, 20019530, 19980470},
|
||||||
|
{40000000, 40039061, 39960939},
|
||||||
|
} {
|
||||||
|
// Increase
|
||||||
|
if have, want := CalcGasLimit1559(tc.pGasLimit, 2*tc.pGasLimit), tc.max; have != want {
|
||||||
|
t.Errorf("test %d: have %d want <%d", i, have, want)
|
||||||
|
}
|
||||||
|
// Decrease
|
||||||
|
if have, want := CalcGasLimit1559(tc.pGasLimit, 0), tc.min; have != want {
|
||||||
|
t.Errorf("test %d: have %d want >%d", i, have, want)
|
||||||
|
}
|
||||||
|
// Small decrease
|
||||||
|
if have, want := CalcGasLimit1559(tc.pGasLimit, tc.pGasLimit-1), tc.pGasLimit-1; have != want {
|
||||||
|
t.Errorf("test %d: have %d want %d", i, have, want)
|
||||||
|
}
|
||||||
|
// Small increase
|
||||||
|
if have, want := CalcGasLimit1559(tc.pGasLimit, tc.pGasLimit+1), tc.pGasLimit+1; have != want {
|
||||||
|
t.Errorf("test %d: have %d want %d", i, have, want)
|
||||||
|
}
|
||||||
|
// No change
|
||||||
|
if have, want := CalcGasLimit1559(tc.pGasLimit, tc.pGasLimit), tc.pGasLimit; have != want {
|
||||||
|
t.Errorf("test %d: have %d want %d", i, have, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -263,7 +263,7 @@ func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.S
|
|||||||
Difficulty: parent.Difficulty(),
|
Difficulty: parent.Difficulty(),
|
||||||
UncleHash: parent.UncleHash(),
|
UncleHash: parent.UncleHash(),
|
||||||
}),
|
}),
|
||||||
GasLimit: CalcGasLimit(parent, parent.GasLimit(), parent.GasLimit()),
|
GasLimit: parent.GasLimit(),
|
||||||
Number: new(big.Int).Add(parent.Number(), common.Big1),
|
Number: new(big.Int).Add(parent.Number(), common.Big1),
|
||||||
Time: time,
|
Time: time,
|
||||||
}
|
}
|
||||||
|
@ -223,7 +223,7 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr
|
|||||||
Difficulty: parent.Difficulty(),
|
Difficulty: parent.Difficulty(),
|
||||||
UncleHash: parent.UncleHash(),
|
UncleHash: parent.UncleHash(),
|
||||||
}),
|
}),
|
||||||
GasLimit: CalcGasLimit(parent, parent.GasLimit(), parent.GasLimit()),
|
GasLimit: parent.GasLimit(),
|
||||||
Number: new(big.Int).Add(parent.Number(), common.Big1),
|
Number: new(big.Int).Add(parent.Number(), common.Big1),
|
||||||
Time: parent.Time() + 10,
|
Time: parent.Time() + 10,
|
||||||
UncleHash: types.EmptyUncleHash,
|
UncleHash: types.EmptyUncleHash,
|
||||||
|
@ -36,6 +36,7 @@ var (
|
|||||||
ErrUnexpectedProtection = errors.New("transaction type does not supported EIP-155 protected signatures")
|
ErrUnexpectedProtection = errors.New("transaction type does not supported EIP-155 protected signatures")
|
||||||
ErrInvalidTxType = errors.New("transaction type not valid in this context")
|
ErrInvalidTxType = errors.New("transaction type not valid in this context")
|
||||||
ErrTxTypeNotSupported = errors.New("transaction type not supported")
|
ErrTxTypeNotSupported = errors.New("transaction type not supported")
|
||||||
|
ErrFeeCapTooLow = errors.New("fee cap less than base fee")
|
||||||
errEmptyTypedTx = errors.New("empty typed transaction bytes")
|
errEmptyTypedTx = errors.New("empty typed transaction bytes")
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -299,6 +300,19 @@ func (tx *Transaction) Cost() *big.Int {
|
|||||||
return total
|
return total
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EffectiveTip returns the effective miner tip for the given base fee.
|
||||||
|
// Returns error in case of a negative effective miner tip.
|
||||||
|
func (tx *Transaction) EffectiveTip(baseFee *big.Int) (*big.Int, error) {
|
||||||
|
if baseFee == nil {
|
||||||
|
return tx.Tip(), nil
|
||||||
|
}
|
||||||
|
feeCap := tx.FeeCap()
|
||||||
|
if feeCap.Cmp(baseFee) == -1 {
|
||||||
|
return nil, ErrFeeCapTooLow
|
||||||
|
}
|
||||||
|
return math.BigMin(tx.Tip(), feeCap.Sub(feeCap, baseFee)), nil
|
||||||
|
}
|
||||||
|
|
||||||
// RawSignatureValues returns the V, R, S signature values of the transaction.
|
// RawSignatureValues returns the V, R, S signature values of the transaction.
|
||||||
// The return values should not be modified by the caller.
|
// The return values should not be modified by the caller.
|
||||||
func (tx *Transaction) RawSignatureValues() (v, r, s *big.Int) {
|
func (tx *Transaction) RawSignatureValues() (v, r, s *big.Int) {
|
||||||
@ -400,24 +414,44 @@ func (s TxByNonce) Len() int { return len(s) }
|
|||||||
func (s TxByNonce) Less(i, j int) bool { return s[i].Nonce() < s[j].Nonce() }
|
func (s TxByNonce) Less(i, j int) bool { return s[i].Nonce() < s[j].Nonce() }
|
||||||
func (s TxByNonce) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
func (s TxByNonce) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
|
||||||
|
// TxWithMinerFee wraps a transaction with its gas price or effective miner tip
|
||||||
|
type TxWithMinerFee struct {
|
||||||
|
tx *Transaction
|
||||||
|
minerFee *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTxWithMinerFee creates a wrapped transaction, calculating the effective
|
||||||
|
// miner tip if a base fee is provided.
|
||||||
|
// Returns error in case of a negative effective miner tip.
|
||||||
|
func NewTxWithMinerFee(tx *Transaction, baseFee *big.Int) (*TxWithMinerFee, error) {
|
||||||
|
minerFee, err := tx.EffectiveTip(baseFee)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &TxWithMinerFee{
|
||||||
|
tx: tx,
|
||||||
|
minerFee: minerFee,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// TxByPriceAndTime implements both the sort and the heap interface, making it useful
|
// TxByPriceAndTime implements both the sort and the heap interface, making it useful
|
||||||
// for all at once sorting as well as individually adding and removing elements.
|
// for all at once sorting as well as individually adding and removing elements.
|
||||||
type TxByPriceAndTime Transactions
|
type TxByPriceAndTime []*TxWithMinerFee
|
||||||
|
|
||||||
func (s TxByPriceAndTime) Len() int { return len(s) }
|
func (s TxByPriceAndTime) Len() int { return len(s) }
|
||||||
func (s TxByPriceAndTime) Less(i, j int) bool {
|
func (s TxByPriceAndTime) Less(i, j int) bool {
|
||||||
// If the prices are equal, use the time the transaction was first seen for
|
// If the prices are equal, use the time the transaction was first seen for
|
||||||
// deterministic sorting
|
// deterministic sorting
|
||||||
cmp := s[i].GasPrice().Cmp(s[j].GasPrice())
|
cmp := s[i].minerFee.Cmp(s[j].minerFee)
|
||||||
if cmp == 0 {
|
if cmp == 0 {
|
||||||
return s[i].time.Before(s[j].time)
|
return s[i].tx.time.Before(s[j].tx.time)
|
||||||
}
|
}
|
||||||
return cmp > 0
|
return cmp > 0
|
||||||
}
|
}
|
||||||
func (s TxByPriceAndTime) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
func (s TxByPriceAndTime) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
|
||||||
func (s *TxByPriceAndTime) Push(x interface{}) {
|
func (s *TxByPriceAndTime) Push(x interface{}) {
|
||||||
*s = append(*s, x.(*Transaction))
|
*s = append(*s, x.(*TxWithMinerFee))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TxByPriceAndTime) Pop() interface{} {
|
func (s *TxByPriceAndTime) Pop() interface{} {
|
||||||
@ -435,6 +469,7 @@ type TransactionsByPriceAndNonce struct {
|
|||||||
txs map[common.Address]Transactions // Per account nonce-sorted list of transactions
|
txs map[common.Address]Transactions // Per account nonce-sorted list of transactions
|
||||||
heads TxByPriceAndTime // Next transaction for each unique account (price heap)
|
heads TxByPriceAndTime // Next transaction for each unique account (price heap)
|
||||||
signer Signer // Signer for the set of transactions
|
signer Signer // Signer for the set of transactions
|
||||||
|
baseFee *big.Int // Current base fee
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTransactionsByPriceAndNonce creates a transaction set that can retrieve
|
// NewTransactionsByPriceAndNonce creates a transaction set that can retrieve
|
||||||
@ -442,16 +477,18 @@ type TransactionsByPriceAndNonce struct {
|
|||||||
//
|
//
|
||||||
// Note, the input map is reowned so the caller should not interact any more with
|
// Note, the input map is reowned so the caller should not interact any more with
|
||||||
// if after providing it to the constructor.
|
// if after providing it to the constructor.
|
||||||
func NewTransactionsByPriceAndNonce(signer Signer, txs map[common.Address]Transactions) *TransactionsByPriceAndNonce {
|
func NewTransactionsByPriceAndNonce(signer Signer, txs map[common.Address]Transactions, baseFee *big.Int) *TransactionsByPriceAndNonce {
|
||||||
// Initialize a price and received time based heap with the head transactions
|
// Initialize a price and received time based heap with the head transactions
|
||||||
heads := make(TxByPriceAndTime, 0, len(txs))
|
heads := make(TxByPriceAndTime, 0, len(txs))
|
||||||
for from, accTxs := range txs {
|
for from, accTxs := range txs {
|
||||||
// Ensure the sender address is from the signer
|
acc, _ := Sender(signer, accTxs[0])
|
||||||
if acc, _ := Sender(signer, accTxs[0]); acc != from {
|
wrapped, err := NewTxWithMinerFee(accTxs[0], baseFee)
|
||||||
|
// Remove transaction if sender doesn't match from, or if wrapping fails.
|
||||||
|
if acc != from || err != nil {
|
||||||
delete(txs, from)
|
delete(txs, from)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
heads = append(heads, accTxs[0])
|
heads = append(heads, wrapped)
|
||||||
txs[from] = accTxs[1:]
|
txs[from] = accTxs[1:]
|
||||||
}
|
}
|
||||||
heap.Init(&heads)
|
heap.Init(&heads)
|
||||||
@ -461,6 +498,7 @@ func NewTransactionsByPriceAndNonce(signer Signer, txs map[common.Address]Transa
|
|||||||
txs: txs,
|
txs: txs,
|
||||||
heads: heads,
|
heads: heads,
|
||||||
signer: signer,
|
signer: signer,
|
||||||
|
baseFee: baseFee,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -469,19 +507,21 @@ func (t *TransactionsByPriceAndNonce) Peek() *Transaction {
|
|||||||
if len(t.heads) == 0 {
|
if len(t.heads) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return t.heads[0]
|
return t.heads[0].tx
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shift replaces the current best head with the next one from the same account.
|
// Shift replaces the current best head with the next one from the same account.
|
||||||
func (t *TransactionsByPriceAndNonce) Shift() {
|
func (t *TransactionsByPriceAndNonce) Shift() {
|
||||||
acc, _ := Sender(t.signer, t.heads[0])
|
acc, _ := Sender(t.signer, t.heads[0].tx)
|
||||||
if txs, ok := t.txs[acc]; ok && len(txs) > 0 {
|
if txs, ok := t.txs[acc]; ok && len(txs) > 0 {
|
||||||
t.heads[0], t.txs[acc] = txs[0], txs[1:]
|
if wrapped, err := NewTxWithMinerFee(txs[0], t.baseFee); err == nil {
|
||||||
|
t.heads[0], t.txs[acc] = wrapped, txs[1:]
|
||||||
heap.Fix(&t.heads, 0)
|
heap.Fix(&t.heads, 0)
|
||||||
} else {
|
return
|
||||||
heap.Pop(&t.heads)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
heap.Pop(&t.heads)
|
||||||
|
}
|
||||||
|
|
||||||
// Pop removes the best transaction, *not* replacing it with the next one from
|
// Pop removes the best transaction, *not* replacing it with the next one from
|
||||||
// the same account. This should be used when a transaction cannot be executed
|
// the same account. This should be used when a transaction cannot be executed
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"math/rand"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@ -258,36 +259,77 @@ func TestRecipientNormal(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTransactionPriceNonceSortLegacy(t *testing.T) {
|
||||||
|
testTransactionPriceNonceSort(t, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTransactionPriceNonceSort1559(t *testing.T) {
|
||||||
|
testTransactionPriceNonceSort(t, big.NewInt(0))
|
||||||
|
testTransactionPriceNonceSort(t, big.NewInt(5))
|
||||||
|
testTransactionPriceNonceSort(t, big.NewInt(50))
|
||||||
|
}
|
||||||
|
|
||||||
// Tests that transactions can be correctly sorted according to their price in
|
// Tests that transactions can be correctly sorted according to their price in
|
||||||
// decreasing order, but at the same time with increasing nonces when issued by
|
// decreasing order, but at the same time with increasing nonces when issued by
|
||||||
// the same account.
|
// the same account.
|
||||||
func TestTransactionPriceNonceSort(t *testing.T) {
|
func testTransactionPriceNonceSort(t *testing.T, baseFee *big.Int) {
|
||||||
// Generate a batch of accounts to start with
|
// Generate a batch of accounts to start with
|
||||||
keys := make([]*ecdsa.PrivateKey, 25)
|
keys := make([]*ecdsa.PrivateKey, 25)
|
||||||
for i := 0; i < len(keys); i++ {
|
for i := 0; i < len(keys); i++ {
|
||||||
keys[i], _ = crypto.GenerateKey()
|
keys[i], _ = crypto.GenerateKey()
|
||||||
}
|
}
|
||||||
signer := HomesteadSigner{}
|
signer := LatestSignerForChainID(common.Big1)
|
||||||
|
|
||||||
// Generate a batch of transactions with overlapping values, but shifted nonces
|
// Generate a batch of transactions with overlapping values, but shifted nonces
|
||||||
groups := map[common.Address]Transactions{}
|
groups := map[common.Address]Transactions{}
|
||||||
|
expectedCount := 0
|
||||||
for start, key := range keys {
|
for start, key := range keys {
|
||||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
count := 25
|
||||||
for i := 0; i < 25; i++ {
|
for i := 0; i < 25; i++ {
|
||||||
tx, _ := SignTx(NewTransaction(uint64(start+i), common.Address{}, big.NewInt(100), 100, big.NewInt(int64(start+i)), nil), signer, key)
|
var tx *Transaction
|
||||||
|
feeCap := rand.Intn(50)
|
||||||
|
if baseFee == nil {
|
||||||
|
tx = NewTx(&LegacyTx{
|
||||||
|
Nonce: uint64(start + i),
|
||||||
|
To: &common.Address{},
|
||||||
|
Value: big.NewInt(100),
|
||||||
|
Gas: 100,
|
||||||
|
GasPrice: big.NewInt(int64(feeCap)),
|
||||||
|
Data: nil,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
tx = NewTx(&DynamicFeeTx{
|
||||||
|
Nonce: uint64(start + i),
|
||||||
|
To: &common.Address{},
|
||||||
|
Value: big.NewInt(100),
|
||||||
|
Gas: 100,
|
||||||
|
FeeCap: big.NewInt(int64(feeCap)),
|
||||||
|
Tip: big.NewInt(int64(rand.Intn(feeCap + 1))),
|
||||||
|
Data: nil,
|
||||||
|
})
|
||||||
|
if count == 25 && int64(feeCap) < baseFee.Int64() {
|
||||||
|
count = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tx, err := SignTx(tx, signer, key)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to sign tx: %s", err)
|
||||||
|
}
|
||||||
groups[addr] = append(groups[addr], tx)
|
groups[addr] = append(groups[addr], tx)
|
||||||
}
|
}
|
||||||
|
expectedCount += count
|
||||||
}
|
}
|
||||||
// Sort the transactions and cross check the nonce ordering
|
// Sort the transactions and cross check the nonce ordering
|
||||||
txset := NewTransactionsByPriceAndNonce(signer, groups)
|
txset := NewTransactionsByPriceAndNonce(signer, groups, baseFee)
|
||||||
|
|
||||||
txs := Transactions{}
|
txs := Transactions{}
|
||||||
for tx := txset.Peek(); tx != nil; tx = txset.Peek() {
|
for tx := txset.Peek(); tx != nil; tx = txset.Peek() {
|
||||||
txs = append(txs, tx)
|
txs = append(txs, tx)
|
||||||
txset.Shift()
|
txset.Shift()
|
||||||
}
|
}
|
||||||
if len(txs) != 25*25 {
|
if len(txs) != expectedCount {
|
||||||
t.Errorf("expected %d transactions, found %d", 25*25, len(txs))
|
t.Errorf("expected %d transactions, found %d", expectedCount, len(txs))
|
||||||
}
|
}
|
||||||
for i, txi := range txs {
|
for i, txi := range txs {
|
||||||
fromi, _ := Sender(signer, txi)
|
fromi, _ := Sender(signer, txi)
|
||||||
@ -303,7 +345,12 @@ func TestTransactionPriceNonceSort(t *testing.T) {
|
|||||||
if i+1 < len(txs) {
|
if i+1 < len(txs) {
|
||||||
next := txs[i+1]
|
next := txs[i+1]
|
||||||
fromNext, _ := Sender(signer, next)
|
fromNext, _ := Sender(signer, next)
|
||||||
if fromi != fromNext && txi.GasPrice().Cmp(next.GasPrice()) < 0 {
|
tip, err := txi.EffectiveTip(baseFee)
|
||||||
|
nextTip, nextErr := next.EffectiveTip(baseFee)
|
||||||
|
if err != nil || nextErr != nil {
|
||||||
|
t.Errorf("error calculating effective tip")
|
||||||
|
}
|
||||||
|
if fromi != fromNext && tip.Cmp(nextTip) < 0 {
|
||||||
t.Errorf("invalid gasprice ordering: tx #%d (A=%x P=%v) < tx #%d (A=%x P=%v)", i, fromi[:4], txi.GasPrice(), i+1, fromNext[:4], next.GasPrice())
|
t.Errorf("invalid gasprice ordering: tx #%d (A=%x P=%v) < tx #%d (A=%x P=%v)", i, fromi[:4], txi.GasPrice(), i+1, fromNext[:4], next.GasPrice())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -331,7 +378,7 @@ func TestTransactionTimeSort(t *testing.T) {
|
|||||||
groups[addr] = append(groups[addr], tx)
|
groups[addr] = append(groups[addr], tx)
|
||||||
}
|
}
|
||||||
// Sort the transactions and cross check the nonce ordering
|
// Sort the transactions and cross check the nonce ordering
|
||||||
txset := NewTransactionsByPriceAndNonce(signer, groups)
|
txset := NewTransactionsByPriceAndNonce(signer, groups, nil)
|
||||||
|
|
||||||
txs := Transactions{}
|
txs := Transactions{}
|
||||||
for tx := txset.Peek(); tx != nil; tx = txset.Peek() {
|
for tx := txset.Peek(); tx != nil; tx = txset.Peek() {
|
||||||
|
@ -155,7 +155,7 @@ func (api *consensusAPI) AssembleBlock(params assembleBlockParams) (*executableD
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
signer = types.MakeSigner(bc.Config(), header.Number)
|
signer = types.MakeSigner(bc.Config(), header.Number)
|
||||||
txHeap = types.NewTransactionsByPriceAndNonce(signer, pending)
|
txHeap = types.NewTransactionsByPriceAndNonce(signer, pending, nil)
|
||||||
transactions []*types.Transaction
|
transactions []*types.Transaction
|
||||||
)
|
)
|
||||||
for {
|
for {
|
||||||
|
@ -499,7 +499,7 @@ func (w *worker) mainLoop() {
|
|||||||
acc, _ := types.Sender(w.current.signer, tx)
|
acc, _ := types.Sender(w.current.signer, tx)
|
||||||
txs[acc] = append(txs[acc], tx)
|
txs[acc] = append(txs[acc], tx)
|
||||||
}
|
}
|
||||||
txset := types.NewTransactionsByPriceAndNonce(w.current.signer, txs)
|
txset := types.NewTransactionsByPriceAndNonce(w.current.signer, txs, w.current.header.BaseFee)
|
||||||
tcount := w.current.tcount
|
tcount := w.current.tcount
|
||||||
w.commitTransactions(txset, coinbase, nil)
|
w.commitTransactions(txset, coinbase, nil)
|
||||||
// Only update the snapshot if any new transactons were added
|
// Only update the snapshot if any new transactons were added
|
||||||
@ -753,8 +753,9 @@ func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coin
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gasLimit := w.current.header.GasLimit
|
||||||
if w.current.gasPool == nil {
|
if w.current.gasPool == nil {
|
||||||
w.current.gasPool = new(core.GasPool).AddGas(w.current.header.GasLimit)
|
w.current.gasPool = new(core.GasPool).AddGas(gasLimit)
|
||||||
}
|
}
|
||||||
|
|
||||||
var coalescedLogs []*types.Log
|
var coalescedLogs []*types.Log
|
||||||
@ -769,7 +770,7 @@ func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coin
|
|||||||
if interrupt != nil && atomic.LoadInt32(interrupt) != commitInterruptNone {
|
if interrupt != nil && atomic.LoadInt32(interrupt) != commitInterruptNone {
|
||||||
// Notify resubmit loop to increase resubmitting interval due to too frequent commits.
|
// Notify resubmit loop to increase resubmitting interval due to too frequent commits.
|
||||||
if atomic.LoadInt32(interrupt) == commitInterruptResubmit {
|
if atomic.LoadInt32(interrupt) == commitInterruptResubmit {
|
||||||
ratio := float64(w.current.header.GasLimit-w.current.gasPool.Gas()) / float64(w.current.header.GasLimit)
|
ratio := float64(gasLimit-w.current.gasPool.Gas()) / float64(gasLimit)
|
||||||
if ratio < 0.1 {
|
if ratio < 0.1 {
|
||||||
ratio = 0.1
|
ratio = 0.1
|
||||||
}
|
}
|
||||||
@ -880,10 +881,20 @@ func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64)
|
|||||||
header := &types.Header{
|
header := &types.Header{
|
||||||
ParentHash: parent.Hash(),
|
ParentHash: parent.Hash(),
|
||||||
Number: num.Add(num, common.Big1),
|
Number: num.Add(num, common.Big1),
|
||||||
GasLimit: core.CalcGasLimit(parent, w.config.GasFloor, w.config.GasCeil),
|
GasLimit: core.CalcGasLimit(parent.GasUsed(), parent.GasLimit(), w.config.GasFloor, w.config.GasCeil),
|
||||||
Extra: w.extra,
|
Extra: w.extra,
|
||||||
Time: uint64(timestamp),
|
Time: uint64(timestamp),
|
||||||
}
|
}
|
||||||
|
// Set baseFee and GasLimit if we are on an EIP-1559 chain
|
||||||
|
if w.chainConfig.IsLondon(header.Number) {
|
||||||
|
header.BaseFee = misc.CalcBaseFee(w.chainConfig, parent.Header())
|
||||||
|
parentGasLimit := parent.GasLimit()
|
||||||
|
if !w.chainConfig.IsLondon(parent.Number()) {
|
||||||
|
// Bump by 2x
|
||||||
|
parentGasLimit = parent.GasLimit() * params.ElasticityMultiplier
|
||||||
|
}
|
||||||
|
header.GasLimit = core.CalcGasLimit1559(parentGasLimit, w.config.GasCeil)
|
||||||
|
}
|
||||||
// Only set the coinbase if our consensus engine is running (avoid spurious block rewards)
|
// Only set the coinbase if our consensus engine is running (avoid spurious block rewards)
|
||||||
if w.isRunning() {
|
if w.isRunning() {
|
||||||
if w.coinbase == (common.Address{}) {
|
if w.coinbase == (common.Address{}) {
|
||||||
@ -973,13 +984,13 @@ func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(localTxs) > 0 {
|
if len(localTxs) > 0 {
|
||||||
txs := types.NewTransactionsByPriceAndNonce(w.current.signer, localTxs)
|
txs := types.NewTransactionsByPriceAndNonce(w.current.signer, localTxs, header.BaseFee)
|
||||||
if w.commitTransactions(txs, w.coinbase, interrupt) {
|
if w.commitTransactions(txs, w.coinbase, interrupt) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(remoteTxs) > 0 {
|
if len(remoteTxs) > 0 {
|
||||||
txs := types.NewTransactionsByPriceAndNonce(w.current.signer, remoteTxs)
|
txs := types.NewTransactionsByPriceAndNonce(w.current.signer, remoteTxs, header.BaseFee)
|
||||||
if w.commitTransactions(txs, w.coinbase, interrupt) {
|
if w.commitTransactions(txs, w.coinbase, interrupt) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1037,11 +1048,12 @@ func (w *worker) postSideBlock(event core.ChainSideEvent) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// totalFees computes total consumed fees in ETH. Block transactions and receipts have to have the same order.
|
// totalFees computes total consumed miner fees in ETH. Block transactions and receipts have to have the same order.
|
||||||
func totalFees(block *types.Block, receipts []*types.Receipt) *big.Float {
|
func totalFees(block *types.Block, receipts []*types.Receipt) *big.Float {
|
||||||
feesWei := new(big.Int)
|
feesWei := new(big.Int)
|
||||||
for i, tx := range block.Transactions() {
|
for i, tx := range block.Transactions() {
|
||||||
feesWei.Add(feesWei, new(big.Int).Mul(new(big.Int).SetUint64(receipts[i].GasUsed), tx.GasPrice()))
|
minerFee, _ := tx.EffectiveTip(block.BaseFee())
|
||||||
|
feesWei.Add(feesWei, new(big.Int).Mul(new(big.Int).SetUint64(receipts[i].GasUsed), minerFee))
|
||||||
}
|
}
|
||||||
return new(big.Float).Quo(new(big.Float).SetInt(feesWei), new(big.Float).SetInt(big.NewInt(params.Ether)))
|
return new(big.Float).Quo(new(big.Float).SetInt(feesWei), new(big.Float).SetInt(big.NewInt(params.Ether)))
|
||||||
}
|
}
|
||||||
|
@ -182,10 +182,11 @@ func (b *testWorkerBackend) newRandomUncle() *types.Block {
|
|||||||
|
|
||||||
func (b *testWorkerBackend) newRandomTx(creation bool) *types.Transaction {
|
func (b *testWorkerBackend) newRandomTx(creation bool) *types.Transaction {
|
||||||
var tx *types.Transaction
|
var tx *types.Transaction
|
||||||
|
gasPrice := big.NewInt(10 * params.InitialBaseFee)
|
||||||
if creation {
|
if creation {
|
||||||
tx, _ = types.SignTx(types.NewContractCreation(b.txPool.Nonce(testBankAddress), big.NewInt(0), testGas, nil, common.FromHex(testCode)), types.HomesteadSigner{}, testBankKey)
|
tx, _ = types.SignTx(types.NewContractCreation(b.txPool.Nonce(testBankAddress), big.NewInt(0), testGas, gasPrice, common.FromHex(testCode)), types.HomesteadSigner{}, testBankKey)
|
||||||
} else {
|
} else {
|
||||||
tx, _ = types.SignTx(types.NewTransaction(b.txPool.Nonce(testBankAddress), testUserAddress, big.NewInt(1000), params.TxGas, nil, nil), types.HomesteadSigner{}, testBankKey)
|
tx, _ = types.SignTx(types.NewTransaction(b.txPool.Nonce(testBankAddress), testUserAddress, big.NewInt(1000), params.TxGas, gasPrice, nil), types.HomesteadSigner{}, testBankKey)
|
||||||
}
|
}
|
||||||
return tx
|
return tx
|
||||||
}
|
}
|
||||||
@ -221,6 +222,7 @@ func testGenerateBlockAndImport(t *testing.T, isClique bool) {
|
|||||||
engine = ethash.NewFaker()
|
engine = ethash.NewFaker()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chainConfig.LondonBlock = big.NewInt(0)
|
||||||
w, b := newTestWorker(t, chainConfig, engine, db, 0)
|
w, b := newTestWorker(t, chainConfig, engine, db, 0)
|
||||||
defer w.close()
|
defer w.close()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user