Skip to content

Commit c064db8

Browse files
committed
Document how fork choice actually works
1 parent 3d0d436 commit c064db8

File tree

1 file changed

+26
-2
lines changed

1 file changed

+26
-2
lines changed

crates/sc-consensus-subspace/src/block_import.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,7 @@ where
638638
}
639639

640640
let parent_weight = if block_number.is_one() {
641+
// The genesis block is given a zero weight.
641642
0
642643
} else {
643644
// Parent block weight might be missing in special sync modes where block is imported in
@@ -646,6 +647,10 @@ where
646647
.unwrap_or_default()
647648
};
648649

650+
// We prioritise smaller solution ranges numerically, using a solution weight of
651+
// ~`2^64 - range` per block. Solution ranges can be up to ~`2^64`, so it is unlikely
652+
// (but not impossible) that the total extrinsic weight exceeds the total solution weight
653+
// (the maximum block extrinsic weight is ~2^41).
649654
let added_weight = calculate_block_weight(subspace_digest_items.solution_range);
650655
let total_weight = parent_weight.saturating_add(added_weight);
651656

@@ -672,8 +677,27 @@ where
672677
}
673678
}
674679

675-
// The fork choice rule is that we pick the heaviest chain (i.e. smallest solution range),
676-
// if there's a tie we go with the longest chain
680+
// The fork choice rule is that we pick the largest total "chain weight".
681+
// This almost always prioritises:
682+
// - the longest chain (the largest number of solutions), and if there is a tie
683+
// - the strictest solutions (the numerically smallest solution ranges),
684+
// and if there is a tie
685+
// - the highest total extrinsic weight.
686+
//
687+
// If the totals are equal:
688+
// - each node keeps the block it already chose (the one that it processed first).
689+
//
690+
// This check is performed using a single integer for the chain weight, so these priorities
691+
// are not perfectly enforced. Unusually large solution ranges, large weights, or long forks
692+
// can temporarily change the priority order above. But this is very unlikely to persist
693+
// beyond a single block, particularly in networks with lots of storage, because the
694+
// solution "weight" per block is much larger than any other factor.
695+
//
696+
// Solution ranges only change at the end of each epoch, but different block times can make
697+
// the range in each fork different. This can lead to an edge case where one fork accepts a
698+
// solution, but another does not. But this would also be resolved with very high
699+
// probability after a few blocks. (And farmers are not incentivised to vote on multiple
700+
// forks, because they have very limited time to vote and audit.)
677701
let fork_choice = {
678702
let info = self.client.info();
679703

0 commit comments

Comments
 (0)