Class ForkResolver

java.lang.Object
com.privatechain.network.sync.ForkResolver

public final class ForkResolver extends Object
Resolves chain forks by selecting the canonical chain according to the longest-chain (greatest cumulative difficulty) rule (FR-NET-05).

When SyncManager discovers that a peer has a longer or heavier chain than the local chain, it uses ForkResolver to decide whether to switch to the peer's chain. Two chain comparison strategies are supported:

  • Chain length — the chain with more blocks wins (suitable for Proof-of-Work chains where each block represents equal work).
  • Cumulative difficulty — the chain whose blocks' bits values sum to the larger total wins (suitable for chains with variable difficulty e.g., after DifficultyAdjuster runs). This is the canonical Bitcoin rule.

For chains of equal weight, the local chain is retained (no switch). This "prefer local" tie-break ensures that the network stabilizes rather than oscillating between equally valid forks.

Thread safety

All methods are stateless and safe for concurrent use.

Since:
1.0.0
See Also:
  • Constructor Details

    • ForkResolver

      public ForkResolver()
      Constructs a ForkResolver. No external dependencies required.
  • Method Details

    • shouldSwitchTo

      public boolean shouldSwitchTo(List<Block> localChain, List<Block> candidateChain)
      Returns true if the candidate chain should replace the local chain.

      The comparison uses cumulative difficulty (sum of bits fields) as the primary metric, falling back to chain height if difficulties are equal. If both metrics are equal, the local chain is preferred (no switch).

      Parameters:
      localChain - the local node's current canonical chain (non-null, non-empty)
      candidateChain - the peer's chain being evaluated (non-null, non-empty)
      Returns:
      true if the candidate chain is strictly better and should be adopted
      Throws:
      NullPointerException - if either chain is null
      IllegalArgumentException - if either chain is empty
    • resolveCanonical

      public List<Block> resolveCanonical(List<Block> chainA, List<Block> chainB)
      Selects the heavier chain from two competing chains.

      Equivalent to calling shouldSwitchTo(List, List) and returning the winner. When both chains are equal, the first argument (local chain) is returned.

      Parameters:
      chainA - the first chain (typically the local chain) (non-null, non-empty)
      chainB - the second chain (typically a peer's chain) (non-null, non-empty)
      Returns:
      the heavier chain, or chainA on tie
    • cumulativeDifficulty

      public long cumulativeDifficulty(List<Block> chain)
      Computes the cumulative difficulty of a chain as the sum of all block bits values.

      In PoW chains, bits encodes the compact target difficulty. Summing these values provides the chain's total work as a proxy for cumulative hash difficulty (the Bitcoin-compatible metric for fork selection, FR-NET-05).

      Parameters:
      chain - the chain to measure (non-null, non-empty)
      Returns:
      cumulative difficulty (≥ 0)
    • heaviestBlock

      public Block heaviestBlock(List<Block> chain)
      Returns the block with the greatest bits value in the chain.

      Useful for identifying the "heaviest" individual block, e.g., when logging difficulty anomalies or debugging consensus issues.

      Parameters:
      chain - the chain to search (non-null, non-empty)
      Returns:
      the block with the maximum bits value
      Throws:
      IllegalArgumentException - if chain is empty