#42535 [BC-High] Garbage collecting in flight transactions can lead to spiraling network delays
Submitted on Mar 24th 2025 at 14:54:02 UTC by @HollaDieWaldfee for Attackathon | Movement Labs
Report ID: #42535
Report Type: Blockchain/DLT
Report severity: High
Target: https://github.com/immunefi-team/attackathon-movement/tree/main/protocol-units/execution/maptos/opt-executor
Impacts:
Temporary freezing of network transactions by delaying one block by 500% or more of the average block time of the preceding 24 hours beyond standard difficulty adjustments
Description
Brief/Intro
When a new transaction is submitted, it is ensured that the mempool is not full. The inflight_limit
represents the maximum amount of transactions that can be in the mempool at the same time. The transactions_in_flight
variable represents the amount of transactions currently in the mempool. This value is incremented when a new transaction is submitted and decremented when a block is executed. However, there is also a garbage collector that removes expired transactions. The purpose of garbage collection is to reduce the number of in flight transactions if the transactions get dropped and not executed. The problem is that the mechanism of garbage collecting allows submitting more transactions, increasing network delays, causing more transactions to be dropped. This creates a loop where the nework cannot recover from transaction overload.
Vulnerability Details
Let's take a closer look at how this occurs.
The transactions_in_flight
value changes at three points:
Submitting a transaction increments
transactions_in_flight
by one.Executing a block decrements the amount of
transactions_in_flight
by the number of transactions included in that block.Garbage collection decreases
transactions_in_flight
by the number of expired transactions.
Essentially, there is one way to increase transactions_in_flight
, but two ways to decrease it. However, these two decrementing mechanisms do not exclude each other, meaning that the same transaction could cause transactions_in_flight
to be decremented twice.
For example, a transactions could be included in a block that is yet to be executed. That transaction is stored in a slot which expires which means that it is going to be garbage collected and the transactions_in_flight
is decreased. However, once the block is executed, the transaction will cause the transactions_in_flight
to decrease again. As a result, the amount of transactions_in_flight
will be lower than it should be and more transactions will be allowed in the mempool than the inflight_limit
.
The additional transactions then cause further load on the network, causing further delays and garbage collection of in-progress transactions. This creates the loop where transactions_in_flight
provides no protection against network overload because the increasing load gives rise to yet more transactions.
Impact Details
Consider a scenario where a block is not executed due to some network delay. When the slots containing these transactions expire and are garbage collected, new transactions can be submitted. This causes the network delay to increase and transactions_in_flight
to be decreased. Due to this loop, the transaction load on the network increases, undermining the purpose of transactions_in_flight
, which is to limit the network load.
A possible direction to solve the problem is to let the sequencer node report when transactions get dropped and to not garbage collect without knowing whether the transaction really got dropped. This prevents double-decrementing of transactions_in_flight
and also reduces the mempool load until the full node can really be sure that the transaction got dropped.
References
(1): https://github.com/immunefi-team/attackathon-movement/blob/a2790c6ac17b7cf02a69aea172c2b38d2be8ce00/protocol-units/execution/maptos/opt-executor/src/background/transaction_pipe.rs#L295-L298
(2): https://github.com/immunefi-team/attackathon-movement/blob/a2790c6ac17b7cf02a69aea172c2b38d2be8ce00/protocol-units/sequencing/memseq/sequencer/src/lib.rs#L101-L131
(3): https://github.com/immunefi-team/attackathon-movement/blob/a2790c6ac17b7cf02a69aea172c2b38d2be8ce00/util/collections/src/garbage/counted.rs#L66-L77
(4): https://github.com/immunefi-team/attackathon-movement/blob/a2790c6ac17b7cf02a69aea172c2b38d2be8ce00/networks/movement/movement-full-node/src/node/tasks/execute_settle.rs#L153-L154
Proof of Concept
Proof of Concept
A new transaction is submitted when
transaction_pipe::submit_transaction()
is called. This increments thetransactions_in_flight
(reference (1)).A block that includes this transaction is created (reference (2)).
The block will not be executed due to some network delay and the slot containing this transaction expires. This slot is garbage collected which decreases the amount of
transactions_in_flight
. To verify this, you can take a look at reference (3). Now, new transactions can be submitted.The block is now executed which decrements the
transactions_in_flight
again (reference (4)). As a result, for every transaction, two new transactions can be submitted which further increases the network delay.This creates a loop of increasing network delays and network load.
Was this helpful?