Current Status
- 14th Feb: Nethermind team will patch and issue new version
- 13th Feb: Nethermind team informed and ascertained non-threatening
- 12th Feb: Sebastian from HOPR disclosed possible bug that could result in DOS attack on Gnosis Chain
Summary
- Nethermind clients currently accept EIP transactions with cumulative cost (value + maximal fees) that exceed balance
- Accepted into mempool, but will never get confirmed
- At the time of report, believed to be potential as a DOS vector for mempools
- Nethermind mempools are 2048 txns by default
- Unknown how Nethermind prunes transactions from mempool
- If mempools prune lowest-fee transactions, a DOS attack could be formed specifically with high-fee transactions
- Nethermind clarified that mempool sorting is done using “gas bottleneck”
- Invalid txns would be first-to-evict in case of a full mempool
- “Gas bottleneck” = (
balance
- value
) / gasLimit
and is balance-aware
- So this is a cosmetic bug that will not have actual impact
- Nethermind will be implementing simple fix in next version
- Fix:
TooExpensiveTxFilter.cs
to check cumulative cost
Details
- Example invalid transaction:
- Nethermind’s mempool sorting algorithm
- Marcin: We are sorting transactions in the pool using concept of "gas bottleneck". It is the lowest fee paid by transaction from the sender address which is pending and must be processed before newly added tx (e.g. if address A has pending txs with nonces 5, 6 and 7 and gas prices accordingly 5gwei, 2 gwei, 200 gwei, bottlenecks would be 5, 2, 2). This way this tx with 200 gwei will be evicted from the pool if we would have full tx pool and new incoming tx with fee >2gwei
- These txs would be added until TxPool would be full (by default 2048 txs). After that, every newcoming tx must be better than worst tx already being in the pool, so all the rest would be rejected https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.TxPool/Filters/FeeTooLowFilter.cs#L41
- In general, transactions which you described would be always first-to-evict and will not replace better transactions - it's covered by sorting in our pool. When adding transaction, we are checking cummulative cost here: https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.TxPool/Filters/TooExpensiveTxFilter.cs
For every already pending tx we count effective gas price. For the incoming one we require to cover only value, with assumption that 1)base fee is changing, tx can be fine in the future 2)if tx pool would be full, it would be rejected as first one
But there is edge case if tx is able to pay value but remains 0 for fee payment. We are discussing it internally and most likely we will change logic to require 1) effective gas price (like in already pending txs), or 2) coverage of MaxFeePerGas or 3)at least some minimal base fee
- No mater how high fee does "spam" transactions have, in our pool it will be sorted by fee which it can pay. If balance is lower than value+baseFee+priorityFee, their gas bottleneck is (balance - value)/gasLimit. And it competes with other users txs. If "spam" tx has balance only for paying value and nothing remains for fee, it's gas bottleneck is 0. If users send txs with balance enough to cover value+basefee+priorityfee, gas bottleneck is higher and they are higher in our TxPool order
- I think that such transaction would be just executed.
In 1559 there are MaxFee and MaxPriorityFee. MaxFee must be >= MaxPriorityFee:
https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Consensus/Validators/TxValidator.cs#L70
otherwise we reject tx at earlier stage of filtering.
And notice that it is MAX priority fee. Transaction is still valid if cannot pay it fully. We might build a block using priority fee lower than MaxPriorityFee:
https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Core/TransactionExtensions.cs#L26
I can't find a place in the code where we adjust priority fee for scenario when MaxFee > account balance. I need to consult it with a team.
Anyway, looks like refactoring TooExpensiveTxFilter to count MaxFee instead of effective/affordable when calculating cumulative cost would be a good and quick solution