From 37eb040a99a40b61b71ea351b295eb752d690106 Mon Sep 17 00:00:00 2001 From: David Rusu Date: Thu, 31 Oct 2024 02:10:19 +0400 Subject: [PATCH] cryptarchia/ghost: common_prefix_depth returns depth of both chains --- cryptarchia/cryptarchia.py | 31 +++++++++++++---------- cryptarchia/test_fork_choice.py | 44 ++++++++++++++++----------------- 2 files changed, 40 insertions(+), 35 deletions(-) diff --git a/cryptarchia/cryptarchia.py b/cryptarchia/cryptarchia.py index a64e93f..f7ab8d1 100644 --- a/cryptarchia/cryptarchia.py +++ b/cryptarchia/cryptarchia.py @@ -2,7 +2,7 @@ from typing import TypeAlias, List, Optional, Dict from hashlib import sha256, blake2b from math import floor from copy import deepcopy -from itertools import chain +import itertools import functools from dataclasses import dataclass, field, replace import logging @@ -347,7 +347,7 @@ class LedgerState: self.nonce = h.digest() self.block = block - for proof in chain(block.orphaned_proofs, [block]): + for proof in itertools.chain(block.orphaned_proofs, [block]): self.apply_leader_proof(proof.leader_proof) def apply_leader_proof(self, proof: MockLeaderProof): @@ -722,7 +722,7 @@ class Leader: def common_prefix_depth( local_chain: Id, fork: Id, states: Dict[Id, LedgerState] -) -> int: +) -> (int, int): local_block = local_chain fork_block = fork @@ -747,7 +747,7 @@ def common_prefix_depth( if local_block in seen: # we had seen this block from the fork chain - return depth + return depth, seen[local_block] if local_block in states: seen[local_block] = depth @@ -756,7 +756,7 @@ def common_prefix_depth( if fork_block in seen: # we had seen the fork in the local chain # return the depth w.r.t to the local chain - return seen[fork_block] + return seen[fork_block], depth if fork_block in states: seen[fork_block] = depth @@ -786,21 +786,26 @@ def maxvalid_bg( k: int, s: int, ) -> Chain: + # assert type(local_chain) == Id + # assert all(type(f) == Id for f in forks) + cmax = local_chain - for chain in forks: - m = common_prefix_depth(cmax.tip_id(), chain.tip_id(), states) - if m <= k: + for fork in forks: + local_depth, fork_depth = common_prefix_depth( + cmax.tip_id(), fork.tip_id(), states + ) + if local_depth <= k: # Classic longest chain rule with parameter k - if cmax.length() < chain.length(): - cmax = chain + if local_depth < fork_depth: + cmax = fork else: # The chain is forking too much, we need to pay a bit more attention # In particular, select the chain that is the densest after the fork - forking_slot = Slot(cmax.blocks[-m].slot.absolute_slot + s) + forking_slot = Slot(cmax.blocks[-local_depth].slot.absolute_slot + s) cmax_density = chain_density(cmax, forking_slot) - candidate_density = chain_density(chain, forking_slot) + candidate_density = chain_density(fork, forking_slot) if cmax_density < candidate_density: - cmax = chain + cmax = fork return cmax diff --git a/cryptarchia/test_fork_choice.py b/cryptarchia/test_fork_choice.py index 12f6b4d..ad4ad63 100644 --- a/cryptarchia/test_fork_choice.py +++ b/cryptarchia/test_fork_choice.py @@ -44,28 +44,28 @@ class TestForkChoice(TestCase): b.id(): LedgerState(block=b) for b in [b0, b1, b2, b3, b4, b5, b6, b7] } - assert (d := common_prefix_depth(b0.id(), b0.id(), states)) == 0, d - assert (d := common_prefix_depth(b1.id(), b0.id(), states)) == 1, d - assert (d := common_prefix_depth(b0.id(), b1.id(), states)) == 0, d - assert (d := common_prefix_depth(b1.id(), b1.id(), states)) == 0, d - assert (d := common_prefix_depth(b2.id(), b0.id(), states)) == 2, d - assert (d := common_prefix_depth(b0.id(), b2.id(), states)) == 0, d - assert (d := common_prefix_depth(b3.id(), b0.id(), states)) == 3, d - assert (d := common_prefix_depth(b0.id(), b3.id(), states)) == 0, d - assert (d := common_prefix_depth(b1.id(), b4.id(), states)) == 1, d - assert (d := common_prefix_depth(b4.id(), b1.id(), states)) == 1, d - assert (d := common_prefix_depth(b1.id(), b5.id(), states)) == 1, d - assert (d := common_prefix_depth(b5.id(), b1.id(), states)) == 2, d - assert (d := common_prefix_depth(b2.id(), b5.id(), states)) == 2, d - assert (d := common_prefix_depth(b5.id(), b2.id(), states)) == 2, d - assert (d := common_prefix_depth(b3.id(), b5.id(), states)) == 3, d - assert (d := common_prefix_depth(b5.id(), b3.id(), states)) == 2, d - assert (d := common_prefix_depth(b3.id(), b6.id(), states)) == 1, d - assert (d := common_prefix_depth(b6.id(), b3.id(), states)) == 1, d - assert (d := common_prefix_depth(b3.id(), b7.id(), states)) == 1, d - assert (d := common_prefix_depth(b7.id(), b3.id(), states)) == 2, d - assert (d := common_prefix_depth(b5.id(), b7.id(), states)) == 2, d - assert (d := common_prefix_depth(b7.id(), b5.id(), states)) == 4, d + assert (d := common_prefix_depth(b0.id(), b0.id(), states)) == (0, 0), d + assert (d := common_prefix_depth(b1.id(), b0.id(), states)) == (1, 0), d + assert (d := common_prefix_depth(b0.id(), b1.id(), states)) == (0, 1), d + assert (d := common_prefix_depth(b1.id(), b1.id(), states)) == (0, 0), d + assert (d := common_prefix_depth(b2.id(), b0.id(), states)) == (2, 0), d + assert (d := common_prefix_depth(b0.id(), b2.id(), states)) == (0, 2), d + assert (d := common_prefix_depth(b3.id(), b0.id(), states)) == (3, 0), d + assert (d := common_prefix_depth(b0.id(), b3.id(), states)) == (0, 3), d + assert (d := common_prefix_depth(b1.id(), b4.id(), states)) == (1, 1), d + assert (d := common_prefix_depth(b4.id(), b1.id(), states)) == (1, 1), d + assert (d := common_prefix_depth(b1.id(), b5.id(), states)) == (1, 2), d + assert (d := common_prefix_depth(b5.id(), b1.id(), states)) == (2, 1), d + assert (d := common_prefix_depth(b2.id(), b5.id(), states)) == (2, 2), d + assert (d := common_prefix_depth(b5.id(), b2.id(), states)) == (2, 2), d + assert (d := common_prefix_depth(b3.id(), b5.id(), states)) == (3, 2), d + assert (d := common_prefix_depth(b5.id(), b3.id(), states)) == (2, 3), d + assert (d := common_prefix_depth(b3.id(), b6.id(), states)) == (1, 1), d + assert (d := common_prefix_depth(b6.id(), b3.id(), states)) == (1, 1), d + assert (d := common_prefix_depth(b3.id(), b7.id(), states)) == (1, 2), d + assert (d := common_prefix_depth(b7.id(), b3.id(), states)) == (2, 1), d + assert (d := common_prefix_depth(b5.id(), b7.id(), states)) == (2, 4), d + assert (d := common_prefix_depth(b7.id(), b5.id(), states)) == (4, 2), d def test_fork_choice_long_sparse_chain(self): # The longest chain is not dense after the fork