Skip to content

Block Life Cycle and Difficulty Adjustment

Lars Kuhtz edited this page May 23, 2020 · 14 revisions

The overall process of creating new blocks on a single chain is:

  createPayload   wait   mine   validate   createPayload   wait   mine   validate
|-------------->|----->|----->|--------->|-------------->|----->|----->|--------->| ...

where

  • createPaylaod is the call to pact newBlock that assembles a new payload and executes Pact on it,
  • wait indicates that the chain is waiting for the parent headers on adjacent chains to become available,
  • mine means that miners are working to resolve the POW challenge, and
  • validate is the time it takes to propagate the and validate the block in the consensus network.

In a Chainweb, adjacent chains synchronize after the wait and at the beginning of the mine phase:

     createPayload   wait   mine       validate   createPayload   wait   mine     validate
... -------------->|----->|--------->|--------->|-------------->|----->|------->|---------> ...
... --------->|---------->|----->|--------->|-------------->|--------->|--------->|---------> ...
... ------------>|------->|------->|--------->|-------------->|------->|--------->|---------> ...

The wait phase is making up for any variance in the phases.

Global Difficulty Adjustment

For the purpose of DA, we assume that createPayload and the validate phase are more or less constant across chains and we will refer to them jointly as latency:

     latency   wait   mine       latency   wait   mine     latency
... --------->|----->|--------->|-------->|----->|------->|---------> ...
... ---->|---------->|----->|-------->|--------->|--------->|--------> ...
... ------->|------->|------->|-------->|------->|------->|--------> ...

Difficulty Adjustment works by measuring the time that it takes to process a fixed number (120 on mainnet) of those block cycles, which is called an Epoch and adjusting the POW difficulty such that the expected time of an epoch matches the targeted time.[1]

When the measure epoch time is too short the new target is lower, and, conversely, when the measure epoch time is too big the target is increased. Without going into all details, the formula is roughly

newTarget = oldTarget * epochTime / targetedEpochTime

with difficulty = maxTarget / target, for a given target.

Because chains synchronize with their adjacent chains during each block cycle, the wall-clock time for an epoch is mostly the same. The difference between chains are only in the order of the differences for a single block cycles time the diameter of the network. Assuming uniform distribution over the time of the epoch, on mainet with 10 chains the expected global difference is roughly 2/120 of the expected accumulated local differences.

Any discrepancy in the hash power or the targets between different chains takes a long time to adjust. Generally, that isn't an issue, because miners have an interest in accurate difficulties and are expected to distributed their hash power accordingly. If the relative difficulty between chains is too much off, chains become blocked often which increases the number of orphans and thus decreases the efficiency of mining. Also mining on chain with too low difficulty becomes a lottery with the actual hash power being less relevant for the outcome.

Per-Chain Difficulty Adjustment

The goal of per chain difficulty adjustment is to minimize the time that chains are in the wait phase. This is achieved by allowing for larger differences in the adjustments between chains. There are two approaches to per chain adjustments:

  1. If all chains use the same hash algorithm, there is no reason why chains should have a different difficulty because hash power is automatically balanced between chains.[2]

    In this case the goal is to adjust difficulty such that (a) the target epoch time is met and (b) and the difference of the difficulty between chains is minimized.

  2. If chains use different hash algorithms Difficulty adjustment must be able to measure the time that chains are in the wait phase relative to other chains. Difficulty adjustment needs this information in order to be able to minimize the wait times.

During block creation and validation the following relevant block information is available:

  1. creation times of parent andadjacent parents,
  2. target of parent and adjacent parent,
  3. epoch start time of current chain and adjacent chains, and
  4. block height of current chain and adjacent chains.

In the first case, it is enough to compute the target using the global difficulty adjustment algorithm for the current and all adjacent chains and use the average.

The second case is more interesting and we focus on it in the following.

[TODO, more content coming soon...]


[1]

Chainweb uses a rather simple algorithm that just does an linear adjustment. There are more sophisticated approaches, like adjustments based on moving average or PID controllers. We found that the our approach works well enough and has the benefit of being simpler and more efficient.

[2]

Generally, one can think of other reason, beside the hash algorithm, why chains might be more or less efficient and should thus use different difficulties, but that does not apply to Chainweb in its current form.