PIP: 66
Title: Allow early block announcements
Author: Jerry Chen, Manav Darji
Description: Allow primary block producers to announce block early for better block propagation.
Discussion: TODO
status: Draft
Type: Core
Date: 2025-05-21
Abstract
This proposal seeks to implement an optimisation to the consensus rules to allow the primary block producers in the network to announce their block early (as soon as it’s built) for better block propagation and reducing the chance of reorgs.
Motivation
Currently, all block producers follow a fixed block time enforced by the consensus rules (2s for primary block producers), during which transactions are executed and the next block is assembled. With current hardware validators are able to create a full block in roughly 500ms (average case scenario) but have to wait for full 2s
before announcing the block to rest of the network, as shown below:
The field header.Time
for primary validators is parent.Time + 2s
. The line below in consensus.Seal
function uses the header time to wait.
delay = time.Until(time.Unix(int64(header.Time), 0)) // Wait until we reach header time
This introduces unnecessary idle time in the network. Moreover, it leads to delayed block propagation affecting critical applications and also increases the chance of reorgs as a backup block is announced by the secondary validator if the block from primary isn’t seen on time. Allowing early announcement
(if the block is ready) before it’s expected time improves the propagation by a great factor.
Specification
This proposal requires changes in the bor consensus rules to allow primary validators to announce blocks as soon as it’s ready instead of waiting. This proposal also introduces changes in header verification logic in consensus allowing the rest of the network to import and process early blocks and reject maliciously sent headers.
The proposal won’t change the announcement timings for non-primary validators as malicious actors could cause 1 block reorgs if allowed the same.
The current workflow is as below:
The miner
module triggers a new block production and sends the block to be signed to the consensus engine under certain conditions mentioned below:
- The block is full (i.e. the transactions included in the block fully occupy the gas limit of that block).
- The block building time (2s for primary) has been completed. During the block building loop (when it tries to execute as many transactions as possible), if the window is completed, it interrupts the execution and sends the partially built block to consensus for sealing and signing.
- There are no more valid transactions to execute.
All the transactions which arrive after the block has been submitted to consensus will be picked up in the next block.
Note that the validators still get the same time to build the block and can utilise it fully before announcing the block. Transactions arriving after block has been signed will be continue to be included in next block.
Timings of block propagation
Consensus changes
- Once the block is built, it’s sent to
consensus.Seal
function for signing. This function waits until the header time is reached and is responsible for timing the release of the block.
+delay = time.Until(time.Unix(int64(header.Time), 0)) // Wait until we reach header time for non-primary validators
+if successionNumber == 0 {
+ // For primary producers, set the delay to `header.Time - block time` instead of `header.Time`
+ // for early block announcement instead of waiting for full block time.
+ delay = time.Until(time.Unix(int64(header.Time-c.config.CalculatePeriod(number)), 0))
+}
-delay = time.Until(time.Unix(int64(header.Time), 0)) // Wait until we reach header time
verifyHeader
function is then is responsible for block validation (including validating the header time and the time at which we received a block).
+if header.Time-c.config.CalculatePeriod(number) > uint64(time.Now().Unix()) {
+ return consensus.ErrFutureBlock
+}
-if header.Time > uint64(time.Now().Unix()) {
- return consensus.ErrFutureBlock
-}
The above check leaves a slight window for non-primary validators to act maliciously so we also need to handle it later once we know the succession of the validator in verifySeal
+if succession != 0 {
+ if header.Time > uint64(time.Now().Unix()) {
+ return consensus.ErrFutureBlock
+ }
+}
Backwards Compatibility
This change modifies the consensus rules and hence will require a hardfork.
Security Considerations
This change does not introduce new security risks. The adjustment while altering consensus rules stays fair for all validators and doesn’t allow anyone to act maliciously affecting the network badly.
Copyright
All copyrights and related rights in this work are waived under CCO 1.0 Universal.