Skip to main content

Communication Layer: Congestion Control, Block Creation, and Processing

This article describes how network congestion in IOTA 2.0 is handled. Specifically, we describe the scheduling policy for incoming blocks and how to set the cost in Mana of a new block. We refer to our solution as IOTA Congestion Control Algorithm (ICCA).

Introduction

High-level Description

Every network has to deal with its intrinsic limited resources in terms of bandwidth and node capabilities (processing power, storage). Hence, it is important to introduce a mechanism that regulates the issuance of blocks in the network. The approach described in this article is based on the amount of Mana per block that any block issuer has to expend and a set of rules to manage the scheduling buffer allowing fair throughput allocation and small dissemination latency while enabling predictable guarantees for block issuers. Furthermore, our approach satisfies the following requirements:

  • Consistency. If a block is issued by an honest user, it shall be booked by all honest nodes within some delay bound.
  • Fairness. Block issuers can access a share of the available throughput proportionally to their Mana.
  • Security. Malicious users shall be unable to interfere with either of the above requirements.

Our approach permits to use the Mana generated by the transaction outputs to pay for its block creation. More precisely, such Mana will be deducted to the issuer's account at the same time as the generated Mana gets credited to it. The amount to be burned varies over time depending on the recent congestion level inferred by the number of blocks included in recent slot commitments. We highlight that this is an objective value. Burning Mana acts as an anti-spam mechanism and it is useful to deal with sporadic usage in low-traffic periods. In ICCA, costs of block issuance are determined by the protocol based on objective measurements of network traffic. Furthermore, instead of a priority tip mechanism, we use a round-robin scheduler to iterate through all active block issuers and share the available bandwidth proportionally to issuers' Mana holdings. Our approach brings the following features:

  • Mana is a consumable resource that gets burned for block issuance.
  • Mana generated by accounts holding tokens can be used to issue blocks.
  • Artificially inflating the value of Mana through spam is not economically feasible due to the Mana expenditures.
  • The system permits predictable performance guarantees to users who are aware of the allowed throughput associated with their accounts, and the maximum propagation delay of their blocks through the network.

Mana balances are updated once the block is included in a slot commitment, rather than when the block is received. This implies that the protocol does not take any action against overspending Mana until the slot commitment is issued. While this allows issuers to go temporarily into Mana debt, attackers cannot affect honest users' throughput since the congestion control guarantees their fair share of bandwidth. Furthermore, issuers are required to lock a small IOTA token issuer depositA small amount of IOTA tokens required to be locked by an account to deal with storage consumption and to enforce dust protection. as a collateral with a special unlocking condition that requires the account to have a non-negative Mana balance.

Overview of the Solution

The data flow for ICCA at a given node is shown in the figure below:

Data Flow for ICCA

For the sake of simplicity, we will split the description of this article into (i) block creation and (ii) block processing. Upon (i) block creation, it is possible to identify the following modules:

  • Mana Burn Calculator suggests the issuer the amount of Mana to be burned for creating a block in a given slot.
  • Mana Updater updates Mana balances upon commitment: the Mana burned by blocks is subtracted and the Mana allotted by transactions is added.
  • Account Output registers the block issuer on the ledger and deposits IOTA tokens as collateral for potential misbehavior.

As for (ii), a received block triggers the following modules:

  • Filter Checks verify whether incoming blocks burn enough Mana and are issued by valid accounts.
  • Scheduler keeps individual queues for every block issuer and schedules blocks to be gossiped from them. Furthermore, it keeps access control in place and decides what information to drop in case of a full buffer.

Scheduled blocks will be added to the tip pool and gossiped to all neighbors through flooding.

Definitions

Before describing each of the above components in detail, we introduce some important terminology that will be used throughout this Wiki.

Maximum Committable Age. This parameter, denoted by MCA, places a hard limit on how far in the past a slot can be committed to. MCA is measured in the number of slots. For example, if MCA is set to 1010 and a block is in slot 4747, then such a block cannot commit to a slot any less than 3737 (i.e., over 1010 slots in the past). This parameter allows us to ensure that everyone can use an objective past committed slot as a reference point; more recent commitments are not suitable for our solution as they are subjective. As described in the following sections, MCA is used to compute the Reference Mana Cost, apply unlock conditions to the issuer deposit, and filter out negative Mana balances, for which we require an objective view of the Mana balances.

Mana and Block Issuance Credit. Mana is a quantity computed as a function of the UTXOs holding IOTA tokens and the time held. Our Mana Wiki Page explains how Mana is generated and the distinction between Potential and Stored Mana. In this article, we refer to Mana as the sum of Potential and Stored Mana. Since ICCA works at the block level (and not at the UTXO level), it is necessary to introduce another quantity, the Block Issuance Credit (BIC), to represent account balances. BIC is used as a spam protection for the IOTA network. Unlike Mana, BIC is not directly exposed to users in the wallet.

Block Creation

Mana Burn Calculator

Every block issuer must consume a certain amount of Mana during the creation of a new block. Consumed Mana is not reassigned to other users; instead, Mana gets burned. We require blocks to burn a certain amount of Mana to be considered valid. The amount of Mana to burn for block bb, denoted by burnTarget(b)burnTarget(b), is a function of the following quantities:

  • Reference Mana Cost. This value, denoted by RMC, is updated over time according to the real-time traffic conditions and is analogous to the technique applied by Ethereum in EIP-1559 in which the number of transactions in a block is used to determine the base fee.
  • Work Score. This is assigned to each block to capture the amount of resources required from nodes to process that block. The work score is affected by a number of block characteristics, such as payload size (to account for propagation through the network) and signature in the block (to account for the computational burden). Hence, the scheduling rate and associated variables in the scheduler are measured in units of work.

RMC is computed according to an algorithm based on recent traffic activity, where we count the number of blocks in the slot which is MCA slots in the past compared to the block's timestamps. In this way, all nodes use the same past slot index to calculate RMC for a given block and apply the same RMC value (given they share the same past history of the Tangle). In the computation of the RMC, the protocol only takes into account the blocks issued by accounts that are not in debt after commitment (more details below) to avoid Mana cost manipulations by malicious actors. Please note that blocks from issuers with negative balances are excluded with respect to the RMC calculation, but they do make part of the slot commitment with the resulting Mana reduction.

Let the number of blocks issued by accounts not in debt at slot ii-MCA be niMCAn_{i-MCA}. Hence, if niMCAn_{i-MCA} is lower than a given threshold TlowT_{low}, then RMC decreases; otherwise, if niMCAn_{i-MCA} is larger than a threshold ThighT_{high}, then RMC increases. The value RMC at slot ii is calculated as:

RMCi={min(RMCi1+α;RMCmax)if niMCA>Thighmax(RMCi1β;RMCmin)if niMCA<TlowRMCi1otherwiseRMC_i = \begin{cases} \min(RMC_{i-1} + \alpha; RMC_{max}) &\text{if $n_{i-MCA}>T_{high}$}\\ \max(RMC_{i-1} - \beta; RMC_{min}) &\text{if $n_{i-MCA}<T_{low}$}\\ RMC_{i-1} &\text{otherwise} \end{cases}

where α(0,1)\alpha \in (0,1), β(1,)\beta \in (1, \infty). Furthermore, please note that we added two optional lower and upper bounds on RMC, respectively RMCminRMC_{min} and RMCmaxRMC_{max}, with the goal of not making block creation too cheap or too expensive. Furthermore, the parameters TlowT_{low} and ThighT_{high} specify a desirable range for the number of blocks within a slot. Let ss be the slot time and suppose that we schedule blocks every μ\mu seconds; then, if we choose Tlow=μs/2T_{low}=\mu\cdot s/2 and Thigh=3μs/4T_{high}=3\mu\cdot s/4, the RMC should keep congestion levels between 50%50\% and 75%75\% most of the time. In this case, the cost increase would only really begin to take effect when there is a significant increase in demand. To be more precise, in order to limit fluctuations in RMC, we update its value every RMCupdate slot; hence, nin_i represents the number of blocks issued by account not in debt at slot ii during the latest RMCupdate slots by users up to slot ii.

Mana Updater

The Mana updater permits linking Mana (which exists on UTXOs) with the related accounts and is crucial for detecting malicious actions from users trying to overspend their Mana. When a transaction is created, the Mana generated by the UTXO will be allotted to pay for the creation of the related block according to the cost computed by the Mana Burn Calculator. Since the input UTXO Mana may be larger than the Mana cost of the block, the exceeding Mana is stored in an output. In case the input UTXO is smaller than the Mana cost, the user can use some pre-alloted BIC balance (see below), wait some time such that the token held will generate enough Mana, or contact a third-party service if any is available.

Each commitment stores the information related to Mana allotment and burning on a dedicated vector, called BIC (definition in the Tokenomics Wiki Page). While Mana is linked to an address, the BIC is per account and is updated upon commitment for all issuers whose BIC balance has changed in said commitment: for each block, the Mana burned is subtracted and the Mana allotted by the transaction is added to the BIC balance. While we expect the BIC balance to be 00 for most issuers, a user may decide to allot additional Mana to the BIC, beyond the amount burned by their block. This is useful, for instance, to accumulate credits to issue blocks that do not generate Mana (e.g., data messages).

Account Output

Block issuers are required to have an account output that registers their details on the ledger and holds IOTA tokens, to account for the additional burden they bring for nodes and to act as collateral for overspending Mana. The account output of a block issuer also has a field containing the public keys which can be used to verify the block issuer's signature on its blocks and an expiry slot. In order to allow the protocol to take countermeasures against misbehaving issuers, the block issuer cannot issue blocks at any time after the expiry slot specified in its account output.

Recall that every commitment includes the BIC of every account. In order to modify or destroy an account output, or to unlock any of its funds, a commitment must be referenced, and the following conditions must be satisfied:

  1. The BIC of the account in the specified commitment must be greater than or equal to zero.
  2. The slot index of the specified commitment must be strictly greater than the expiry slot of the block issuer's account as registered in the commitment.

The above conditions ensure that the issuer deposit is locked until a specified time and that it cannot be unlocked if the account has a negative BIC balance. The mechanics of the issuer deposit unlock mechanism are similar to that of staked tokens of a validator. For the sake of simplicity, an issuer may also set the expiry of their issuer deposit to infinity. In this case, a two-step procedure is required to unlock the deposit. Namely, if a commitment is provided from slot nn, an issuer may transition the issuer deposit to expire in any slot after n+n+MCA.

Tip Selection Algorithm

Upon block creation, the act of selecting blocks to be referenced is a key component of the consensus mechanism as it determines both the Witness WeightMeasure of approval of each block using the voting power of the validation blocks" issuer. of blocks and the Approval WeightMeasure of approval of each conflicting transaction using the voting power of the validation blocks "issuer". of transactions. This selection is called tip selection algorithm (TSA), where a tipA block that is not referenced by any other block in the node"s local perception. is a block not referenced by any other block in the node's local perception. Each node maintains a list of eligible blocks, and, when issuing a new block, selects tips at random from this list. Additional time conditions are added to speed up confirmation times and to limit malicious behavior (see the Consensus Wiki Page).

We want to clarify here that, ultimately, the TSA is a free procedure not enforced by the protocol. Therefore each node may, if it sees fit, select its approvals manually or by following another algorithm of its preference. The suggested standard TSA for a new block issued by users is called Restricted Uniform Random Tip Selection (Consensus Wiki Page).

Block Processing

Mana Check

The first step after the arrival of the block in the Block Inbox is parsing, which consists of interpreting the bytes received and translating them to information that a node can process. While the complete list of parser checks has been outlined in the Data Flow Wiki Page, here we discuss the Mana check. For a block bb belonging to slot nn to be considered valid, it must satisfy all of the three following conditions:

  1. Negative Mana filter. The issuer account has a non-negative BIC balance in the specified commitment.
  2. Account output not expired. The expiry slot of the block issuer's account output in the block's commitment is greater than or equal to nn.
  3. Mana burn check. The amount of Mana burned is equal (or larger) than burnTarget(b)burnTarget(b) (see above for details).

Note that these filters do not take into account the BIC balance at slot nn. Hence, the protocol is able to deal efficiently with potential Mana overspend because the filtering decision is based on the BIC of the committed slot as provided in the block where there are no pending conflicts or overspends and it is objective as agreed by all nodes.

Since the Negative Mana filter acts according to the block's commitment, it is possible for a block issuer to overspend its Mana between slots nn-MCA and nn having a negative BIC balance. However, the DRR scheduler (see next section) prevents the attacker from using the throughput of honest block issuers. Furthermore, if the BIC balance is negative, the IOTA tokens deposited on its account output, and all assets owned by the account will be locked until the balance becomes positive again. In this case, issuers can acquire stored Mana to repay the debt. The blocks containing allotting transactions need to be issued by a third party as the issuer's account is still locked. As soon as the transaction allotting Mana to the issuer is committed, the issuer can resume using their account.

Scheduler

Once the block has successfully passed the filter checks and is solid, it is enqueued into the outbox for scheduling. The scheduler allocates to each issuer a throughput proportional to its Mana holdings. In ICCA, this is done through a lightweight scheduler based on Deficit Round Robin (DRR).

The outbox is logically split into several issuer queues, each one corresponding to a different block issuer account. Blocks within each issuer queue are sorted by their timestamp in increasing order, with the oldest block at the head of the queue. We have empirically proven that sorting blocks by timestamp guarantees consistency across nodes even during highly congested periods. Furthermore, each queue is assigned a priority counter value, called deficit, which is used to guarantee throughput to issuers and protect the available bandwidth from malicious actors.

The DRR scheduler iterates over all issuer queues in sequence and increments its deficit according to a quantum, which is a value proportional to the account's Mana and BIC (note that we only consider the Mana in the account's output; any other address associated to the account will not alter the quantum). The deficit value represents the maximum amount of bytes that can be sent per issuer at a given turn: if the deficit counter is greater than the work score of the block at the head of the queue, this block will be scheduled and the value of the counter is decremented by the block's work score. ICCA schedules blocks at a maximum scheduling rate μ\mu: this rate is computed in work -- see above -- per second implying that the time between the scheduling of two consecutive blocks is equal to the work score of the first scheduled block times μ\mu. To keep the network latency bounded, we add a cap maxDeficitmaxDeficit on the maximum deficit that an account can accumulate. Furthermore, blocks can only be scheduled when they are ready, meaning that all parents are either scheduled or accepted. Below is an approximate piece of pseudocode illustrating how the DRR scheduler operates.

FOR ID in round robin over all accounts
ID.deficit += ID.quantum
IF ID.deficit > maxDeficit
ID.deficit = maxDeficit
IF Len(outbox[ID]) > 0
b = outbox[ID].head
IF ID.deficit >= b.workScore AND (parents(b) scheduled OR accepted)
ID.deficit -= b.workScore
schedule(b)
pause(mu*b.workScore)

In order to provide a high-performance system, each validator issues a fixed number of special blocks per slot, called validation blocksValidation Blocks is a special type of blocks that are issued by members of the Validator Committee. These block allows to reach consensus in the network., which receive special treatment during scheduling and do not burn any Mana. A second scheduling buffer, reserved for validation blocks only, includes a set of queues, one for each validator, in which blocks are scheduled in the order they are received. If a validator issues more validation blocks than its allowance, the validator will not receive rewards for the given epoch, and its Mana balance will be decreased by an amount proportional to its stake.

ICCA During High-traffic Periods

In certain circumstances, such as network congestion or ongoing attacks, the number of blocks in the scheduling buffer may hit its maximum capacity. In this case, nodes shall drop a block from the tail of the issuer queue with the largest ratio between the sum of the work score of blocks in the queue and the account's Mana if the total number of bytes in the scheduling buffer exceeds a certain threshold maxBuffermaxBuffer. With the aforementioned block drop policy, we guarantee that attackers will not be able to enforce the dropping of honest users if they use the rate setter described below.

We provide block issuers an optional tool to self-regulate the rate at which new blocks are created, which we call deficit-based rate setter. This parameter-free mechanism requires the issuer to use a polling approach contacting a node, periodically checking if it has enough deficit to issue a certain block. The query to the rate setter works as follows:

IF outbox is empty OR deficit(issuerID) - sum(work_score(issuerID)) >= b.work_score
RETURN TRUE
ELSE
RETURN FALSE

If the function above returns TRUE, the issuer can issue a new block; if the function returns FALSE, the issuer should wait some time and query again. Optionally, the rate setter can provide a time estimate of when the function will return TRUE based on current traffic. Finally, we highlight that block issuers may ignore the rate setter suggestion and create blocks anyway; however, if the deficit is not sufficient, the related block would suffer propagation delays. Please note that such delays do not affect blocks issued by users following the rate setter. For this reason, our suggestion is to make use of the deficit-based rate setter to have a smooth and enjoyable user experience.