Skip to content
Lars Kuhtz edited this page Feb 17, 2024 · 1 revision

This page documents the computation of various values related to block difficulty on the current Kadena Mainnet network.

Values for some historic Mainnet blocks or other Chainweb networks (like development or test networks) may be computed differently.

Special cases related to genesis blocks of newly introduced chains are omitted.

Difficulty

The difficulty of a block is computed from the hash target of a block as follows:

targetToDifficulty :: Word256 -> Word256
targetToDifficulty target = (2^256 - 1) `div` target

Hash Target

The hash target of a new block is computed as follows:

-- The current window width on mainnet is 120.
--
_WINDOW_WIDTH_ :: Rational
_WINDOW_WIDTH_ = 120

-- The targeted block delay on mainnet is 30 seconds.
--
_BLOCK_DELAY_ :: Rational
_BLOCK_DELAY_ = 30_000_000

-- | Compute the POW target for a new BlockHeader.
--
-- The target is an unsigned 256 bit integer value. Calculations are done
-- using (infinite precision) rational arithmetic.
--
powTarget :: ParentHeader -> HM.HashMap ChainId ParentHeader -> Word256
powTarget p@(ParentHeader ph) as =
    | isLastInEpoch -> avgTarget $ adjusted <$> (p : HM.elems as)
    | otherwise -> _blockTarget ph
  where
    isLastInEpoch = (asRational (_blockHeight ph) + 1) `mod` _WINDOW_WIDTH_ == 0

    avgTarget ps = asWord256 
        $ floor 
        $ (sum $ asRational . _hashTarget <$> ps) / asRational (length ps)

    adjusted (ParentHeader a) = min maxTarget
        $ asWord256
        $ ceiling
        $ (actualTime / targetedTime) * oldTarget
      where
        oldTarget = asRational (_blockTarget a)
        actualTime = asRational (_blockCreationTime a - _blockEpochStart a)
        targetedTime = _WINDOW_WIDTH_ * _BLOCK_DELAY_

Epoch Start

The epoch start value of a new block is computed as follows:

epochStart :: ParentHeader -> Word64
epochStart (ParentHeader ph)
    -- (special cases that apply during chain graph transitions are omitted)
    | isLastInEpoch = _blockCreationTime ph
    | otherwise = _blockEpochStart ph
  where
    isLastInEpoch = (_blockHeight ph + 1) `mod` _WINDOW_WIDTH_ == 0

Weight

The total weight of a new block is computed as follows:

weight :: ParentHeader -> HM.HashMap ChainId ParentHeader -> Word256
weight p@(ParentHeader ph) =
    _blockWeight ph + targetToDifficulty (powTarget p adj t)