-
Notifications
You must be signed in to change notification settings - Fork 21k
EIP-1559: miner changes #22896
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
EIP-1559: miner changes #22896
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
ba5c2d2
core/types, miner: create TxWithMinerFee wrapper, add EIP-1559 suppor…
adietrichs 6f56820
all: rename to NewTransactionsByPriceAndNonce
lightclient 3c0579b
core/types, miner: rename to NewTransactionsByPriceAndNonce + Effecti…
adietrichs e336045
core,miner: revert naming to TransactionsByPriceAndTime
lightclient 09366af
core/types/transaction: update effective tip calculation logic
lightclient 24a7121
miner: update aleut to london
lightclient aa987c9
core/types/transaction_test: use correct signer for 1559 txs + add ba…
lightclient c1421f7
miner/worker: calculate gas target from gas limit
lightclient 3d22e9d
core, miner: fix block gas limits for 1559
holiman File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,6 +36,7 @@ var ( | |
ErrUnexpectedProtection = errors.New("transaction type does not supported EIP-155 protected signatures") | ||
ErrInvalidTxType = errors.New("transaction type not valid in this context") | ||
ErrTxTypeNotSupported = errors.New("transaction type not supported") | ||
ErrFeeCapTooLow = errors.New("fee cap less than base fee") | ||
errEmptyTypedTx = errors.New("empty typed transaction bytes") | ||
) | ||
|
||
|
@@ -299,6 +300,19 @@ func (tx *Transaction) Cost() *big.Int { | |
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. | ||
// The return values should not be modified by the caller. | ||
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) 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 | ||
// 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) Less(i, j int) bool { | ||
// If the prices are equal, use the time the transaction was first seen for | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comment is outdated |
||
// deterministic sorting | ||
cmp := s[i].GasPrice().Cmp(s[j].GasPrice()) | ||
cmp := s[i].minerFee.Cmp(s[j].minerFee) | ||
if cmp == 0 { | ||
return s[i].time.Before(s[j].time) | ||
return s[i].tx.time.Before(s[j].tx.time) | ||
} | ||
return cmp > 0 | ||
} | ||
func (s TxByPriceAndTime) Swap(i, j int) { s[i], s[j] = s[j], s[i] } | ||
|
||
func (s *TxByPriceAndTime) Push(x interface{}) { | ||
*s = append(*s, x.(*Transaction)) | ||
*s = append(*s, x.(*TxWithMinerFee)) | ||
} | ||
|
||
func (s *TxByPriceAndTime) Pop() interface{} { | ||
|
@@ -432,35 +466,39 @@ func (s *TxByPriceAndTime) Pop() interface{} { | |
// transactions in a profit-maximizing sorted order, while supporting removing | ||
// entire batches of transactions for non-executable accounts. | ||
type TransactionsByPriceAndNonce struct { | ||
txs map[common.Address]Transactions // Per account nonce-sorted list of transactions | ||
heads TxByPriceAndTime // Next transaction for each unique account (price heap) | ||
signer Signer // Signer for the set of transactions | ||
txs map[common.Address]Transactions // Per account nonce-sorted list of transactions | ||
heads TxByPriceAndTime // Next transaction for each unique account (price heap) | ||
signer Signer // Signer for the set of transactions | ||
baseFee *big.Int // Current base fee | ||
} | ||
|
||
// NewTransactionsByPriceAndNonce creates a transaction set that can retrieve | ||
// price sorted transactions in a nonce-honouring way. | ||
// | ||
// Note, the input map is reowned so the caller should not interact any more with | ||
// 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 | ||
heads := make(TxByPriceAndTime, 0, len(txs)) | ||
for from, accTxs := range txs { | ||
// Ensure the sender address is from the signer | ||
if acc, _ := Sender(signer, accTxs[0]); acc != from { | ||
acc, _ := Sender(signer, accTxs[0]) | ||
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) | ||
continue | ||
} | ||
heads = append(heads, accTxs[0]) | ||
heads = append(heads, wrapped) | ||
txs[from] = accTxs[1:] | ||
} | ||
heap.Init(&heads) | ||
|
||
// Assemble and return the transaction set | ||
return &TransactionsByPriceAndNonce{ | ||
txs: txs, | ||
heads: heads, | ||
signer: signer, | ||
txs: txs, | ||
heads: heads, | ||
signer: signer, | ||
baseFee: baseFee, | ||
} | ||
} | ||
|
||
|
@@ -469,18 +507,20 @@ func (t *TransactionsByPriceAndNonce) Peek() *Transaction { | |
if len(t.heads) == 0 { | ||
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. | ||
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 { | ||
t.heads[0], t.txs[acc] = txs[0], txs[1:] | ||
heap.Fix(&t.heads, 0) | ||
} else { | ||
heap.Pop(&t.heads) | ||
if wrapped, err := NewTxWithMinerFee(txs[0], t.baseFee); err == nil { | ||
t.heads[0], t.txs[acc] = wrapped, txs[1:] | ||
heap.Fix(&t.heads, 0) | ||
return | ||
} | ||
} | ||
heap.Pop(&t.heads) | ||
} | ||
|
||
// Pop removes the best transaction, *not* replacing it with the next one from | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is correct but I also added this function with slightly different semantics in my tx pool PR: my version does not return an error, it returns the negative value which the caller can handle as it wishes. For me this value is useful even if negative (I described the reasons in my gist). Do you think we should have two versions? Or use my version and check at the caller side when necessary? I guess you should check it for the minimum effective fee threshold anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think maybe let's start with this. We could have this method maybe wrap your method, so the 'normal' case doesn't need to handle negative tips