## Keyboard shortcuts

Press `←` or `→` to navigate between chapters

Press `S` or `/` to search in the book

Press `?` to show this help

Press `Esc` to hide this help

- Auto
- Light
- Dark

# Algorand Specifications

The TxPool is responsible for populating the `payset` of a block, a process referred to as `BlockAssembly`.

The `BlockAssembly` is a time-bound algorithm that manages the flow of transactions into the pending BlockEvaluator and stops ingestion once timing constraints are reached.

It also handles possible desynchronizations between the TxPool.round (the current round as perceived by the TxPool) and the actual round being assembled by the pending BlockEvaluator. This discrepancy arises based on how often the `Update` function has been invoked.

The following pseudocode outlines a high-level view of how `BlockAssembly` operates:

---

Algorithm 5: Block Assembly

1: function AssembleBlock(r)  
2: if TxPool.round < r−2 then  
3: return AssembleBlock.emptyBlock(r)  
4: endif  
5: if r < TxPool.round then  
6: return nil  
7: endif  
8: assemblyDeadline ← round.startTime() + δassemblyDeadline  
9: Wait until assemblyDeadline ∨ (TxPool.round = r ∧ BlockEvaluator is done)  
10: if ¬BlockEvaluator.done() then  
11: if TxPool.round > r then  
12: return nil (r is behind TxPool.round)  
13: endif  
14: assemblyDeadline ← assemblyDeadline + ϵassemblyWait  
15: Wait until assemblyDeadline ∨ (TxPool.round = r ∧ BlockEvaluator is done)  
16: if ¬BlockEvaluator.done() then  
17: return AssembleBlock.emptyBlock(r) (Ran out of time)  
18: endif  
19: if TxPool.round > r then  
20: return nil (Requested round is behind transaction pool round)  
21: elseif TxPool.round = r−1 then  
22: return AssembleBlock.emptyBlock(r)  
23: elseif TxPool.round < r then  
24: return nil  
25: endif  
26: endif  
27: return BlockEvaluator.block  
28: end function

---

> Important  
> **IMPLEMENTATION:**  
> Block assembly [reference implementation](https://github.com/algorand/go-algorand/blob/b6e5bcadf0ad3861d4805c51cbf3f695c38a93b7/data/pools/transactionPool.go#L860).

This algorithm begins by taking a target round `r`, for which a new block is to be assembled.

It first checks the round currently perceived by the TxPool, which matches the round being handled by the pending BlockEvaluator.

- If the TxPool.round is significantly behind `r`: an _empty block_ is immediately assembled and returned, as there’s no time to catch up.

- If the TxPool is already ahead of `r`: no action is needed, as TxPool is simply ahead of the network’s current state.

Next, the algorithm waits for the assembly deadline `δassemblyDeadline`. During this time, the pending BlockEvaluator is expected to notify the completed block assembly in the background via the `Ingestion` function, and that it is caught up to the round `r`.

If this doesn’t happen by the deadline, the algorithm performs another round of checks:

- If the TxPool.round is now ahead of `r`: the process is aborted, waiting for the network to catch up. This should rarely happen.

- Otherwise, if the TxPool is still behind: an additional wait period `ϵassemblyWait` is introduced.

After this extra wait, similar checks are repeated:

- If the TxPool is still too far behind: there is no more time to wait, and the algorithm exits.

- Otherwise: the algorithm proceeds.

If all checks pass and timing constraints are met without returning early (an _empty_ block or a nil value), the pending BlockEvaluator finally provides the fully _assembled block_ for round `r`.
