I didn't know the answer to your questions but I took a look to the code to understand it and here is what I found out, don't hesitate if you see some code that contradicts what I'm going to summarize below.
1 - What happens when the gas prices are the same (maxFee and
maxPriority) ? >How does geth queues those transactions ? (It would be
great that someone could send the github source for the algorithm.)
Just as a reminder :
- Base Fee - Defined by the network, must be paid and is burned.
- (Max) Priority Fee - Defined by the user, can be paid and is forwarded to the miner
- Max Fee - Defined by the user, Maximum to be paid in any circumstances
So if a tx is sent with Max Fee == (Max) Priority Fee, the effective gasTip will be computed here where :
if gasFeeCap.Cmp(baseFee) == -1 {
err = ErrGasFeeCapTooLow
}
returns an error if Max Fee is lower than Base Fee (not enough gas provided to pay what must be paid) and :
return math.BigMin(tx.GasTipCap(), gasFeeCap.Sub(gasFeeCap, baseFee)), err
returns the minimum value between (Max) Priority Fee and Max Fee - Base Fee. So if Max Fee == (Max) Priority Fee, and Base Fee is non zero / positive, the minimum value must be Max Fee - Base Fee, ensuring that your tx can proceed and that you won't pay more than Max Fee in total. The returned value is what is left as a tip.
Now for the ordering, the original EIP-1559 states that :
Transaction Ordering
With most people not competing on priority fees
and instead using a baseline fee to get included, transaction ordering
now depends on individual client internal implementation details such
as how they store the transactions in memory. It is recommended that
transactions with the same priority fee be sorted by time the
transaction was received to protect the network from spamming attacks
where the attacker throws a bunch of transactions into the pending
pool in order to ensure that at least one lands in a favorable
position. Miners should still prefer higher gas premium transactions
over those with a lower gas premium, purely from a selfish mining
perspective.
From my understanding, geth orders them by price and account, the ordering itself is done here, called here in the miner logic, returning the following structure :
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
baseFee *big.Int // Current base fee
}
The important fields are of course txs and heads. When selecting transactions the best candidate will be taken from heads (highest price) if any error happens it is popped and we also flush from that structure all remaining transactions from the same account (to respect nonce ordering / avoid nonce gap), and move to the next best price candidate.
Now in case no error happens, geth moves to the next transaction from the same account which as per my understanding might be a suboptimal selection strategy if the aim is to maximize the fees, but maybe I got it wrong ? that process code can be found here.
2 - Sometimes even though the max gas price is less than the second
transaction, for some reason the first one gets mined first and second
gets after the first in the block. How that could happen ?
Not 100% sure but from the code it really seems like the worker is polling the available txs and keeps pushing the higher priced one in the block while it still can, thus if you receive a very highly priced tx at any point you can take advantage of it and include it in the block, not necessarily respecting a perfectly increasing gas price order in the block. I'm pretty sure that miners are more concerned about maximizing their gains rather than creating a perfectly increasing set of transaction fees though...
I hope that answers your question.