ethereum / go-ethereum

Go implementation of the Ethereum protocol
https://geth.ethereum.org
GNU Lesser General Public License v3.0
47.51k stars 20.11k forks source link

Combat "hammer" eviction attack #21460

Open wjmelements opened 4 years ago

wjmelements commented 4 years ago

It's currently fairly easy to evict most pending transactions from most of the network by issuing many high gas limit transactions from a handful of accounts and then cancel them all cheaply. The high gas limits ensure that few of the transactions will confirm before the cancel step. The cancel step replaces only the first unconfirmed transaction of each account with a transaction that drains the account, thereby evicting all subsequent transactions. Those subsequent transactions can thus evict a large number of competitor transactions quickly and cheaply. It is believed that a similar strategy was used against makerdao collateral on Black Thursday.

holiman commented 4 years ago

Any solution to this problem would either make replacement txs impossible or very expensive. So it's basically UX versus security. If we make replacements very expensive (say, replace only accepted if it's worth more than 100% of the original one), then a user who submits a tx with wrong (very high) gasprice is screwed.

I guess we may have to revise the limits at some point, to prevent these types of shenanigans.

wjmelements commented 4 years ago

Could we reduce the limit on pending transactions per-account to make this more expensive?

karalabe commented 3 years ago

My proposal is option 4, whereby a transaction replacement also takes into consideration the subsequent transactions getting invalidated. (Important to note, the only way to invalidate a tx is to run out of balance.). What we can do, is to check if a replacement tx lowers the remaining balance compared to the original transaction, and if it does, whether the balance gets lowered enough to kick out subsequent txs. If yes, the replacement should be rejected.

This proposal does not interfere with normal users using Ethereum, but it ensures that once a tx with a certain nonce enters the pool it stays there.


Yes, it could still be kicked out using another account, but that should outbid the original ones. We could add a new rule to txpool so that higher fee txs from other accounts would need to be 10% more expensive to kick out old txs already pooled... but this might backfire with fee spikes, so not sure if it's a good idea.

fjl commented 3 years ago

Here's some more info about the proposal @karalabe outlined above. I'm adding this because I got confused initially and didn't understand how it could work.

In Ethereum, all TXs must originate in an EOA and contracts can never 'take value' out of an EOA. This means the balance of an EOA can never decrease unless it sends a TX, i.e. if it has balance V at the head block, and we have some TXs Ta, Tb, Tc spending value Va, Vb, Vc, we know that the remaining balance will be at least V-Va-Vb-Vc. It might be higher (due to incoming transfers), but that doesn't really matter because we're looking for a worst-case prediction of balance here.

To implement this proposal, we'd basically just start tracking the 'expected minimum balance' of all accounts in the pool, just like we already track the 'expected nonce' in the txNoncer. Then, when inserting transactions, we could easily check whether any TX replacement will lower the expected balance and potentially reject the replacement as @karalabe wrote.

fjl commented 3 years ago

The benefit of this scheme is that cancelling TXs will still work for most people, as long as they're not piling up future transactions. This is very good. Thinking about it more, this 'expected minimum balance' is also generally useful for deciding whether TXs should be pooled. Right now, it's actually possible to pile up TXs where all but the first one spend non-existing balance. This change would allow us to prevent pooling of such transactions.