Skip to content

Commit

Permalink
feat(consensus): final updates to remove block ties
Browse files Browse the repository at this point in the history
  • Loading branch information
jansegre committed Jan 9, 2025
1 parent ae3be3b commit 4bf80a4
Showing 1 changed file with 14 additions and 46 deletions.
60 changes: 14 additions & 46 deletions hathor/consensus/block_consensus.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# limitations under the License.

from itertools import chain
from typing import TYPE_CHECKING, Any, Iterable, Optional, cast
from typing import TYPE_CHECKING, Any, Iterable, Optional

from structlog import get_logger

Expand Down Expand Up @@ -161,16 +161,9 @@ def update_voided_info(self, block: Block) -> None:
self.mark_as_voided(block, skip_remove_first_block_markers=True)

# Get the score of the best chains.
heads = [cast(Block, storage.get_transaction(h)) for h in storage.get_best_block_tips()]
best_score: int | None = None
for head in heads:
head_meta = head.get_metadata(force_reload=True)
if best_score is None:
best_score = head_meta.score
else:
# All heads must have the same score.
assert best_score == head_meta.score
assert best_score is not None
head = storage.get_best_block()
head_meta = head.get_metadata(force_reload=True)
best_score = head_meta.score

# Calculate the score.
# We cannot calculate score before getting the heads.
Expand All @@ -185,10 +178,8 @@ def update_voided_info(self, block: Block) -> None:
# Either eveyone has the same score or there is a winner.

valid_heads = []
for head in heads:
meta = head.get_metadata()
if not meta.voided_by:
valid_heads.append(head)
if not head_meta.voided_by:
valid_heads.append(head)

# We must have at most one valid head.
# Either we have a single best chain or all chains have already been voided.
Expand All @@ -200,13 +191,13 @@ def update_voided_info(self, block: Block) -> None:
if score > best_score:
winner = True
else:
min_hash: bytes = min(blk.hash for blk in heads)
min_hash: bytes = head.hash
if block.hash < min_hash:
winner = True

if winner:
# Add voided_by to all heads.
self.add_voided_by_to_multiple_chains(block, heads, common_block)
self.add_voided_by_to_multiple_chains(block, [head], common_block)

# We have a new winner candidate.
self.update_score_and_mark_as_the_best_chain_if_possible(block)
Expand All @@ -220,13 +211,8 @@ def update_voided_info(self, block: Block) -> None:
storage.indexes.height.update_new_chain(height, block)
storage.update_best_block_tips_cache([block.hash])
# It is only a re-org if common_block not in heads
if common_block not in heads:
if common_block != head:
self.context.mark_as_reorg(common_block)
else:
best_block_tips = [blk.hash for blk in heads]
best_block_tips.append(block.hash)
best_block_tip = min(best_block_tips)
storage.update_best_block_tips_cache([best_block_tip])

def union_voided_by_from_parents(self, block: Block) -> set[bytes]:
"""Return the union of the voided_by of block's parents.
Expand Down Expand Up @@ -294,31 +280,13 @@ def update_score_and_mark_as_the_best_chain_if_possible(self, block: Block) -> N
self.update_score_and_mark_as_the_best_chain(block)
self.remove_voided_by_from_chain(block)

best_score: int
if self.update_voided_by_from_parents(block):
storage = block.storage
heads = [cast(Block, storage.get_transaction(h)) for h in storage.get_best_block_tips()]
best_score = 0
best_heads: list[Block]
for head in heads:
head_meta = head.get_metadata(force_reload=True)
if head_meta.score < best_score:
continue

if head_meta.score > best_score:
best_heads = [head]
best_score = head_meta.score
else:
assert best_score == head_meta.score
best_heads.append(head)
assert isinstance(best_score, int) and best_score > 0

assert len(best_heads) > 0
first_block = self._find_first_parent_in_best_chain(best_heads[0])
self.add_voided_by_to_multiple_chains(best_heads[0], [block], first_block)
if len(best_heads) == 1:
assert best_heads[0].hash != block.hash
self.update_score_and_mark_as_the_best_chain_if_possible(best_heads[0])
head = storage.get_best_block()
first_block = self._find_first_parent_in_best_chain(head)
self.add_voided_by_to_multiple_chains(head, [block], first_block)
assert head.hash != block.hash
self.update_score_and_mark_as_the_best_chain_if_possible(head)

def update_score_and_mark_as_the_best_chain(self, block: Block) -> None:
""" Update score and mark the chain as the best chain.
Expand Down

0 comments on commit 4bf80a4

Please sign in to comment.