#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:

  1. Submitting a transaction increments transactions_in_flight by one.

  2. Executing a block decrements the amount of transactions_in_flight by the number of transactions included in that block.

  3. 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

  1. A new transaction is submitted when transaction_pipe::submit_transaction() is called. This increments the transactions_in_flight (reference (1)).

  2. A block that includes this transaction is created (reference (2)).

  3. 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.

  4. 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.

  5. This creates a loop of increasing network delays and network load.

Was this helpful?