Chapter 7
Difficulty and target

Initial version: 2024-03-16
Last update: 2025-05-28

Target and difficulty are related to each other but doesn't mean the same, as current, voltage and resistance are related by Ohm's Law but means different physical properties of electricity.

In this chapter you will understand why target is indispensable part of blockchain and how it determine an even flow of time. However the topic is very general, to give precise examples I will use the Bitcoin's difficulty and target.

Table of contents


Target


In chapter 3: Data fingerprinting, section: Proof of work – solving a hash puzzle you may find an information that to mine a block (to successfully add it to a blockchain) you have to solve cryptographic puzzle. You have to find a number called nonce such that hash of a header of this block with nonce as one of its fields conforms certain criteria. I said that hash must starts with five leading zeros. It was just an example of many possibilities, simple enough so I could explained related material. From now I will change criterion for nonce: it must be a number such that hash is below a given number. This number is called a target.

For some reasons I explain you in chapter 10: Searching consensus, section: Searching Consensus Part 2: Chainwork – The heaviest chain criterion the target adjusts every 2016 blocks (roughly two weeks) to ensure that blocks are mined once every 10 minutes on average:

$$2016 \cdot 10 [\textrm{min}] = 20160 [\textrm{min}]$$

$$[\textrm{day}] = 60[\textrm{min}] \cdot 24 = 1440[\textrm{min}]$$

$$20160[\textrm{min}]/1440[\textrm{min}] = 14 [\textrm{days}] = 2 [\textrm{weeks}]$$.

It therefore creates a constant time intervals between blocks and a constant frequency of new bitcoins issuance to the network (via the block reward). Whenever I use a term session or block session I will have in mind all 2016 blocks mined for the same target value (between two target adjustments).

Difficulty


If blocks during two weeks period were being mined faster or slower than assumed 10 minutes per block, the target should be adjusted. The question is, how to select new value as a target. This is how the difficulty comes to play – it controls the target.

After every 2016 blocks added to a blockchain a time needed for this is calculated. In perfect conditions it should be equal to 20160 but in most cases it is not.

Assume blocks during this period were being mined faster than expected 10 minutes and it took 16000 minutes to add 2016 blocks. The ratio timeExpected / timeActual is equal to:


20160/16000 = 1.26
Conversely, assume blocks during this period were being mined slower than expected 10 minutes, and it took 21000 minutes to add 2016 blocks. The ratio is equal to:


20160/21000 = 0.96
If blocks during session were being mined faster than assumed 10 minutes, the ratio is greater than 1.0 so the target should be adjusted downwards to make it more difficult to get below the target for the next part of blocks.

If blocks were being mined slower than assumed 10 minutes, the ratio is lower than 1.0 so the target should be adjusted upwards to make it less difficult to get above the target for the next part of blocks.

As you can see, the higher is difficulty, the lower is target.

difficulty is the number used to calculate target:


target = targetMax / difficulty
where targetMax is the maximum value for target. Interestingly, targetMax doesn't have to be a maximum number in a given range – it is rather the "first target" set when the blockchain first run. For example in case of Bitcoin the maximum target used by SHA256 mining devices is (SHA-256 is a 256-bit digest, which is equivalent to 32 bytes equivalently 64 hexadecimal digits):


                       1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
instead of possible:


                       1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
Moreover, because Bitcoin stores the target in a compact, floating-point-like, representation (see section Target and difficulty in bitcoin below), this is limited to the value:


                       1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
0x00000000FFFF0000000000000000000000000000000000000000000000000000
The ratio timeExpected / timeActual calculated above is used to adjust difficulty:


newDifficulty  = difficulty x ratio
where initial difficulty is an arbitrary selected number (randomly or somehow precalculated) laying in range [0, targetMax].

In Bitcoin the adjustment is limited by a factor of 4, i.e. a number not greater than 4 or less than 0.25 to prevent massive changes from one target to the next.



Example of adjusting target with difficulty


In this section I present a code you can use to make some experiments how difficulty works in practice. To incorporate an unpredictable component you need to use, as it is in real Bitcoin, proof of work function (you should know it from chapter 3: Data fingerprinting, section: Solving hash puzzle):


def proofOfWork(blockOfData, target):
  targetInt = int(target, 16)
  counter = 1

  start = timer()
  while True:
    blockOfData["nonce"] = format(random.getrandbits(64), "x")
    dataString = json.dumps(blockOfData, sort_keys=True)
    dataBytes = dataString.encode('utf-8')

    hash = hashlib.sha256(dataBytes).hexdigest()
    hashInt = int(hash, 16)

    if hashInt < targetInt:
      blockOfData["hash"] = hash
      blockOfData["counter"] = counter
      end = timer()
      blockOfData["powTime"] = end-start
      break

    counter += 1
    

  return blockOfData
Now you can use above proofOfWork(blockOfData, target) function to implement testing function. My implementation takes three arguments:
  • numberOfBlocks – how many blocks I want to add during one block session.
  • averageTimePerBlock - expected average time function proofOfWork(blockOfData, target) needs to mine (and in consequence add) one block of data. Thus expected time for one block session is numberOfBlocks * averageTimePerBlock.
  • iterations – how many block sessions you want to repeat.


In every block I include the same data – it is not important because of the random nature of proofOfWork(blockOfData, target) function:

  dataJSON = {"name": "Piotr", "country": "Poland"}
  blockOfData = {"data" : dataJSON,
                 "nonce": None}
Before main loop I define all required values:

                  #                     1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
                  # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  targetMax = int("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16)
  difficultyInitial = 1.0
  timeExpected = numberOfBlocks * averageTimePerBlock

  difficulty = difficultyInitial

  target = int(targetMax / difficulty)
  if target>targetMax:
    target = targetMax
  target = hex(target)
  
  print(f"Time expected for one block session: {timeExpected}")
  print(f"Initial difficulty: {difficulty}")
  print(f"Initial target: {target}")
timeActualTotal variable accumulates the total time of computation used till current iteration, which will allow it to be averaged and determine whether it converges to the assumed average time:

  timeActualTotal = 0
The first block of code in the main loop is to complete one block session:

    timeActual = 0
    for b in range(numberOfBlocks):
      proofOfWork(blockOfData, target)
      timeActual += blockOfData['powTime']
    timeActualTotal += timeActual
Now you can calculate the ratio of expected time and actual time needed to add assumed number of blocks (actual time needed for one block session):

    ratio = timeExpected/timeActual
    
    if ratio < 0.25:
      ratio = 0.25
    elif ratio > 4:
      ratio = 4
Having ratio you can calculate new difficulty and update target:


    difficulty = difficulty * ratio

    target = int(targetMax / difficulty)
    if target>targetMax:
      target = targetMax
    target = hex(target)
Finally you can print effects of one iteration:

    print(f"Iteration: {(i+1)}, actual time in this block session: {timeActual}, average time from beginning: {timeActualTotal/(i+1)}")
    print(f"  New difficulty: {difficulty}")
    print(f"  New target: {target}")
Below I put the full code:


def test(numberOfBlocks, averageTimePerBlock, iterations):
  dataJSON = {"name": "Piotr", "country": "Poland"}
  blockOfData = {"data" : dataJSON,
                 "nonce": None}
                  #                     1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
                  # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  targetMax = int("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16)
  difficultyInitial = 1.0
  timeExpected = numberOfBlocks * averageTimePerBlock

  difficulty = difficultyInitial

  target = int(targetMax / difficulty)
  if target>targetMax:
    target = targetMax
  target = hex(target)
  
  print(f"Time expected for one block session: {timeExpected}")
  print(f"Initial difficulty: {difficulty}")
  print(f"Initial target: {target}")

  timeActualTotal = 0
  
  for i in range(iterations):
    timeActual = 0
    for b in range(numberOfBlocks):
      proofOfWork(blockOfData, target)
      timeActual += blockOfData['powTime']
    timeActualTotal += timeActual

    ratio = timeExpected/timeActual
    
    if ratio < 0.25:
      ratio = 0.25
    elif ratio > 4:
      ratio = 4

    difficulty = difficulty * ratio

    target = int(targetMax / difficulty)
    if target>targetMax:
      target = targetMax
    target = hex(target)

    print(f"Iteration: {(i+1)}, actual time in this block session: {timeActual}, average time from beginning: {timeActualTotal/(i+1)}")
    print(f"  New difficulty: {difficulty}")
    print(f"  New target: {target}")
You can run it simply by:


test(10, 5, 15)
Result you will see will be similar to mine (get full test result):


Time expected for one block session: 50
Initial difficulty: 1.0
Initial target: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
Iteration: 1, actual time in this block session: 0.000549109000000006, average time from beginning: 0.000549109000000006
  New difficulty: 4.0
  New target: 0x4000000000000000000000000000000000000000000000000000000000000000
Iteration: 2, actual time in this block session: 0.0007540369999999852, average time from beginning: 0.0006515729999999956
  New difficulty: 16.0
  New target: 0x1000000000000000000000000000000000000000000000000000000000000000
Iteration: 3, actual time in this block session: 0.00249688999999996, average time from beginning: 0.0012666786666666503
  New difficulty: 64.0
  New target: 0x400000000000000000000000000000000000000000000000000000000000000
Iteration: 4, actual time in this block session: 0.010782393000000001, average time from beginning: 0.003645607249999988
  New difficulty: 256.0
  New target: 0x100000000000000000000000000000000000000000000000000000000000000
Iteration: 5, actual time in this block session: 0.030916355999999978, average time from beginning: 0.009099756999999986
  New difficulty: 1024.0
  New target: 0x40000000000000000000000000000000000000000000000000000000000000
Iteration: 6, actual time in this block session: 0.11693818699999992, average time from beginning: 0.027072828666666642
  New difficulty: 4096.0
  New target: 0x10000000000000000000000000000000000000000000000000000000000000
Iteration: 7, actual time in this block session: 0.5838842140000001, average time from beginning: 0.10661731228571428
  New difficulty: 16384.0
  New target: 0x4000000000000000000000000000000000000000000000000000000000000
Iteration: 8, actual time in this block session: 2.535226811, average time from beginning: 0.41019349962499996
  New difficulty: 65536.0
  New target: 0x1000000000000000000000000000000000000000000000000000000000000
Iteration: 9, actual time in this block session: 11.975442539, average time from beginning: 1.6952211706666667
  New difficulty: 262144.0
  New target: 0x400000000000000000000000000000000000000000000000000000000000
Iteration: 10, actual time in this block session: 35.08085456499999, average time from beginning: 5.0337845100999985
  New difficulty: 373628.29847015743
  New target: 0x2ce74b5f5cae680000000000000000000000000000000000000000000000
Iteration: 11, actual time in this block session: 49.03751475100001, average time from beginning: 9.03412362290909
  New difficulty: 380961.6987803588
  New target: 0x2c0a036e0573540000000000000000000000000000000000000000000000
Iteration: 12, actual time in this block session: 60.67007936599998, average time from beginning: 13.337119934833332
  New difficulty: 313961.7606910969
  New target: 0x356fe7df5daf4a0000000000000000000000000000000000000000000000
Iteration: 13, actual time in this block session: 33.559905265, average time from beginning: 14.892718806384615
  New difficulty: 467763.1808134619
  New target: 0x23dded442bbc560000000000000000000000000000000000000000000000
Iteration: 14, actual time in this block session: 61.357718315, average time from beginning: 18.211647342714283
  New difficulty: 381177.13114106195
  New target: 0x2c03a43f3dede00000000000000000000000000000000000000000000000
Iteration: 15, actual time in this block session: 61.685968162999956, average time from beginning: 21.109935397399997
  New difficulty: 308965.83331061096
  New target: 0x364d1b8c3026a40000000000000000000000000000000000000000000000
Iteration: 16, actual time in this block session: 52.95818687100001, average time from beginning: 23.100451114499997
  New difficulty: 291707.3370196905
  New target: 0x39838c910b7a380000000000000000000000000000000000000000000000
Iteration: 17, actual time in this block session: 30.418668168999886, average time from beginning: 23.53093447064705
  New difficulty: 479487.3585507168
  New target: 0x22fd6a42a983aa0000000000000000000000000000000000000000000000
Iteration: 18, actual time in this block session: 75.17976510800003, average time from beginning: 26.400313950499992
  New difficulty: 318893.8924336261
  New target: 0x349c53c58fec200000000000000000000000000000000000000000000000
[...]
Iteration: 21, actual time in this block session: 39.80206675300019, average time from beginning: 28.84023978647618
  New difficulty: 490483.2248725292
  New target: 0x22349a960289680000000000000000000000000000000000000000000000
Iteration: 22, actual time in this block session: 110.7451272369999, average time from beginning: 32.56318921604544
  New difficulty: 221446.86502678873
  New target: 0x4bc3062ef332900000000000000000000000000000000000000000000000
Iteration: 23, actual time in this block session: 48.87483580000003, average time from beginning: 33.27239124143477
  New difficulty: 226544.86854233954
  New target: 0x4a0e9289eea2e80000000000000000000000000000000000000000000000
Iteration: 24, actual time in this block session: 27.066515722000076, average time from beginning: 33.01381309479166
  New difficulty: 418496.5491479947
  New target: 0x2816d9977f76420000000000000000000000000000000000000000000000
Iteration: 25, actual time in this block session: 38.16597068900012, average time from beginning: 33.219899398559996
  New difficulty: 548258.7519627927
  New target: 0x1e99d526aa312f0000000000000000000000000000000000000000000000
Iteration: 26, actual time in this block session: 86.9994053769999, average time from beginning: 35.2883419361923
  New difficulty: 315093.39034387027
  New target: 0x353ec68d8d0ab20000000000000000000000000000000000000000000000
[...]
Iteration: 47, actual time in this block session: 19.789343521999854, average time from beginning: 42.62506108223402
  New difficulty: 793356.5597691704
  New target: 0x1525aa739e23bd0000000000000000000000000000000000000000000000
Iteration: 48, actual time in this block session: 89.86258693899936, average time from beginning: 43.60917620424997
  New difficulty: 441427.6212122169
  New target: 0x2601b866e75abc0000000000000000000000000000000000000000000000
Iteration: 49, actual time in this block session: 60.31378878299938, average time from beginning: 43.95008666504078
  New difficulty: 365942.53993926005
  New target: 0x2dd8b9d64c72680000000000000000000000000000000000000000000000
Iteration: 50, actual time in this block session: 101.13980477199948, average time from beginning: 45.09388102717995
  New difficulty: 180909.25761830772
  New target: 0x5cbd00dd4c51540000000000000000000000000000000000000000000000
[...]
Iteration: 67, actual time in this block session: 116.74055654799895, average time from beginning: 47.595178161701426
  New difficulty: 272525.29439780925
  New target: 0x3d8fe28e90f79a0000000000000000000000000000000000000000000000
Iteration: 68, actual time in this block session: 32.286549626000124, average time from beginning: 47.37005127147052
  New difficulty: 422041.52743894723
  New target: 0x27c0a56bbd6a7a0000000000000000000000000000000000000000000000
[...]
Iteration: 98, actual time in this block session: 27.878575578998607, average time from beginning: 49.657258545489725
  New difficulty: 583147.6488104425
  New target: 0x1cc525411ee7cb0000000000000000000000000000000000000000000000
Iteration: 99, actual time in this block session: 158.3333488119997, average time from beginning: 50.754996831010025
  New difficulty: 184151.8710953479
  New target: 0x5b1af68e4ecd680000000000000000000000000000000000000000000000
Iteration: 100, actual time in this block session: 33.470196680999834, average time from beginning: 50.582148829509926
  New difficulty: 275098.2804948471
  New target: 0x3cfc7bb63187e20000000000000000000000000000000000000000000000


Adjusting target with difficulty in our blockchain


Exactly the same approach can be applied do the difficulty I have defined earlier (see section Proof of work – solving a hash puzzle in chapter Data fingerprinting):


leadingZeros = "0" * difficulty
hash = [... CALCULATE HASH ...]
if hash.startswith(leadingZeros):
  [... YOU SOLVED HASH PUZZLE ...] 
In this case leadingZeros is a target controlled by difficulty. Let's see how this would work. I have tested few variants, non of them is perfect, mostly because with leading zeros you don't have fractional parts of leading zeros. You have for example six leading zeros (which may be to simple) or seven (which may be to hard) and nothing between, so you do very significant changes and you bounce from simple to hard while your goal is in the middle.

Test 1


First I tested the following code:


import json
import random
import hashlib
from timeit import default_timer as timer

def proofOfWork(blockOfData, target):
  leadingZeros = target
  counter = 1

  start = timer()
  while True:
    blockOfData["nonce"] = format(random.getrandbits(64), "x")
    dataString = json.dumps(blockOfData, sort_keys=True)
    dataBytes = dataString.encode('utf-8')

    hash = hashlib.sha256(dataBytes).hexdigest()
    hashInt = int(hash, 16)

    if hash.startswith(leadingZeros):
      blockOfData["hash"] = hash
      blockOfData["counter"] = counter
      end = timer()
      blockOfData["powTime"] = end-start
      break

    counter += 1
  
  return blockOfData

def test(numberOfBlocks, averageTimePerBlock, iterations):  
  dataJSON = {"name": "Piotr", "country": "Poland"}
  blockOfData = {"data" : dataJSON,
                 "nonce": None}

  difficultyInitial = 1.0
  timeExpected = numberOfBlocks * averageTimePerBlock

  difficulty = difficultyInitial
  difficulty = int(difficulty)

  target = "0" * difficulty
  if len(target)>(2*32):
    target = target[:(2*32)]
  
  print(f"Time expected for one block session: {timeExpected}")
  print(f"Initial difficulty: {difficulty}")
  print(f"Initial target: {target}")

  timeActualTotal = 0
  
  for i in range(iterations):
    timeActual = 0
    for b in range(numberOfBlocks):
      proofOfWork(blockOfData, target)
      timeActual += blockOfData['powTime']
    timeActualTotal += timeActual

    ratio = timeExpected/timeActual
    
    if ratio < 0.25:
      ratio = 0.25
    elif ratio > 4:
      ratio = 4

    if ratio > 1:
      d = +1
    elif ratio < 1:
      d = -1
    else:
      d = 0
    
    difficulty = difficulty + int(d)
    if difficulty < 1:
      difficulty = 1
    
    target = "0" * difficulty
    if len(target)>(2*32):
      target = target[:(2*32)]

    print(f"Iteration: {(i+1)}, actual time in this block session: {timeActual}, average time from beginning: {timeActualTotal/(i+1)}")
    print(f"  New difficulty: {difficulty}")
    print(f"  New target: {target}")

def main():
  test(10, 5, 100)

if __name__=="__main__":
    main()
If you run it with the same parameters as before: numberOfBlocks=10, averageTimePerBlock=5 and the number of iterations high enough to stabilize the results, you will get result similar to mine (get full test result):


Time expected for one block session: 50
Initial difficulty: 1
Initial target: 0
Iteration: 1, actual time in this block session: 0.0010572130004220526, average time from beginning: 0.0010572130004220526
  New difficulty: 2
  New target: 00
Iteration: 2, actual time in this block session: 0.02006967099805479, average time from beginning: 0.010563441999238421
  New difficulty: 3
  New target: 000
Iteration: 3, actual time in this block session: 0.269223437000619, average time from beginning: 0.09678344033303195
  New difficulty: 4
  New target: 0000
Iteration: 4, actual time in this block session: 5.570483112001057, average time from beginning: 1.4652083582500381
  New difficulty: 5
  New target: 00000
Iteration: 5, actual time in this block session: 104.4131044279984, average time from beginning: 22.05478757219971
  New difficulty: 4
  New target: 0000
Iteration: 6, actual time in this block session: 2.5865057900000465, average time from beginning: 18.8100739418331
  New difficulty: 5
  New target: 00000
Iteration: 7, actual time in this block session: 90.46350060899931, average time from beginning: 29.046277751428274
  New difficulty: 4
  New target: 0000
Iteration: 8, actual time in this block session: 4.786623541999688, average time from beginning: 26.0138209752497
  New difficulty: 5
  New target: 00000
Iteration: 9, actual time in this block session: 62.524803794001855, average time from beginning: 30.07059684399994
  New difficulty: 4
  New target: 0000
Iteration: 10, actual time in this block session: 4.082503392001854, average time from beginning: 27.471787498800133
  New difficulty: 5
  New target: 00000
Iteration: 11, actual time in this block session: 100.07455469799879, average time from beginning: 34.07203906236364
  New difficulty: 4
  New target: 0000
Iteration: 12, actual time in this block session: 7.786691377999887, average time from beginning: 31.881593421999998
  New difficulty: 5
  New target: 00000
Iteration: 13, actual time in this block session: 91.54846095800076, average time from beginning: 36.47135246323083
  New difficulty: 4
  New target: 0000
Iteration: 14, actual time in this block session: 3.238477707999664, average time from beginning: 34.09757569500003
  New difficulty: 5
  New target: 00000
Iteration: 15, actual time in this block session: 34.20425574299861, average time from beginning: 34.10468769819993
  New difficulty: 6
  New target: 000000
Iteration: 16, actual time in this block session: 1486.8642987089997, average time from beginning: 124.90216338637492
  New difficulty: 5
  New target: 00000
Iteration: 17, actual time in this block session: 57.748457503998, average time from beginning: 120.95194539329393
  New difficulty: 4
  New target: 0000
[...]
Iteration: 90, actual time in this block session: 4.2855929609995655, average time from beginning: 97.14278880741101
  New difficulty: 5
  New target: 00000
Iteration: 91, actual time in this block session: 68.95519911700103, average time from beginning: 96.83303507454936
  New difficulty: 4
  New target: 0000
Iteration: 92, actual time in this block session: 5.9579472439982055, average time from beginning: 95.84526238073902
  New difficulty: 5
  New target: 00000
Iteration: 93, actual time in this block session: 61.9062072050001, average time from beginning: 95.48032630358054
  New difficulty: 4
  New target: 0000
Iteration: 94, actual time in this block session: 4.921312367001519, average time from beginning: 94.51693253829778
  New difficulty: 5
  New target: 00000
Iteration: 95, actual time in this block session: 58.02558682500239, average time from beginning: 94.13281310973677
  New difficulty: 4
  New target: 0000
Iteration: 96, actual time in this block session: 4.677892689998771, average time from beginning: 93.20099102203118
  New difficulty: 5
  New target: 00000
Iteration: 97, actual time in this block session: 55.3827635359994, average time from beginning: 92.81111238815456
  New difficulty: 4
  New target: 0000
Iteration: 98, actual time in this block session: 3.792295028002627, average time from beginning: 91.90275710896933
  New difficulty: 5
  New target: 00000
Iteration: 99, actual time in this block session: 69.30930888599869, average time from beginning: 91.67454046025246
  New difficulty: 4
  New target: 0000
Iteration: 100, actual time in this block session: 5.489559340996493, average time from beginning: 90.8126906490599
  New difficulty: 5
  New target: 00000
As you can see the discrete and limited nature of difficulty has significant influence. The ratio calculated with the code:

    if ratio < 0.25:
      ratio = 0.25
    elif ratio > 4:
      ratio = 4
has no benefit from real value of ratio as you always change difficulty by one:

    if ratio > 1:
      d = +1
    elif ratio < 1:
      d = -1
    else:
      d = 0
which in turn drastically changes time required to solve the puzzle. In consequence you bounce between two values (4 and 5). Look into iteration 15. In that case, with difficulty=5 the puzzel was solved in just 34.20 seconds, less than average for that difficulty and for this reason difficult was increased, which made all attempts to be close to target (50 seconds) even more distant (average time increased from 34.10 to 124.90). No, that was not a good choice.

Test 2


In the second approach I decided to make a step in the direction of our goal. What is our goal? Well, we want to have an average time of one block session to be equal, in our case, 50 seconds. So it is less important how long does it take to complete one single session, we should take care on average of few last sessions. Thats why I decided to change difficulty in response to an average of a few last sessions.


[... All imports as in previous case ...]

def proofOfWork(blockOfData, target):
  [... No changes in this function ...]

def test(numberOfBlocks, averageTimePerBlock, iterations):
  buffer = []
  AVG_SIZE=5
  
  dataJSON = {"name": "Piotr", "country": "Poland"}
  [... No changes ...]
  
  for i in range(iterations):
    timeActual = 0
    for b in range(numberOfBlocks):
      proofOfWork(blockOfData, target)
      timeActual += blockOfData['powTime']
    timeActualTotal += timeActual
    
    buffer.append(timeActual)
    if len(buffer)>AVG_SIZE:
        buffer.pop(0)
        
    v = sum(buffer)/len(buffer)
    
    if v < timeExpected:
      d = +1
    elif v > timeExpected:
      d = -1
    else:
      d = 0
    
    difficulty = difficulty + int(d)
    [... No changes ...]

def main():
  test(10, 5, 100)

if __name__=="__main__":
    main()
As you can notice new code related to calculating an average:

    buffer = []
    AVG_SIZE=5
    
    [... CUT ...]
    
    buffer.append(timeActual)
    if len(buffer)>AVG_SIZE:
        buffer.pop(0)
        
    v = sum(buffer)/len(buffer)
    
    if v < timeExpected:
      d = +1
    elif v > timeExpected:
      d = -1
    else:
      d = 0
Studying the results (get full test result) you see very regular, periodic behavior with difficulty changing from 1 to 6, next from 6 to 1 and again from 1 to 6 and 6 to 1 and this last infinitely:


Time expected for one block session: 50
Initial difficulty: 1
Initial target: 0
Iteration: 1, actual time in this block session: 0.0013733879968640395, average time from beginning: 0.0013733879968640395
  New difficulty: 2
  New target: 00
Iteration: 2, actual time in this block session: 0.021934310996584827, average time from beginning: 0.011653849496724433
  New difficulty: 3
  New target: 000
Iteration: 3, actual time in this block session: 0.2965027719983482, average time from beginning: 0.10660349033059902
  New difficulty: 4
  New target: 0000
Iteration: 4, actual time in this block session: 3.5178693599955295, average time from beginning: 0.9594199577468316
  New difficulty: 5
  New target: 00000
Iteration: 5, actual time in this block session: 43.03846636399976, average time from beginning: 9.375229238997417
  New difficulty: 6
  New target: 000000
Iteration: 6, actual time in this block session: 874.1050630940044, average time from beginning: 153.49686821483192
  New difficulty: 5
  New target: 00000
Iteration: 7, actual time in this block session: 83.48915244800082, average time from beginning: 143.49576596242747
  New difficulty: 4
  New target: 0000
Iteration: 8, actual time in this block session: 6.322442071992555, average time from beginning: 126.34910047612311
  New difficulty: 3
  New target: 000
Iteration: 9, actual time in this block session: 0.43789381200258504, average time from beginning: 112.35896640233194
  New difficulty: 2
  New target: 00
Iteration: 10, actual time in this block session: 0.0247005330020329, average time from beginning: 101.12553981539895
  New difficulty: 1
  New target: 0
Iteration: 11, actual time in this block session: 0.0019091480025963392, average time from beginning: 91.93248248199929
  New difficulty: 2
  New target: 00
Iteration: 12, actual time in this block session: 0.021692758000426693, average time from beginning: 84.27325000499938
  New difficulty: 3
  New target: 000
Iteration: 13, actual time in this block session: 0.25870417499754694, average time from beginning: 77.81059263346077
  New difficulty: 4
  New target: 0000
Iteration: 14, actual time in this block session: 4.944768752990058, average time from beginning: 72.60589092771286
  New difficulty: 5
  New target: 00000
Iteration: 15, actual time in this block session: 118.87579262500367, average time from beginning: 75.69055104086559
  New difficulty: 6
  New target: 000000
Iteration: 16, actual time in this block session: 1217.821633071002, average time from beginning: 147.0737436677491
  New difficulty: 5
  New target: 00000
Iteration: 17, actual time in this block session: 32.89284715600297, average time from beginning: 140.35722034352875
  New difficulty: 4
  New target: 0000
Iteration: 18, actual time in this block session: 4.142021196003043, average time from beginning: 132.78970927977733
  New difficulty: 3
  New target: 000
Iteration: 19, actual time in this block session: 0.09811214999717777, average time from beginning: 125.8059410097889
  New difficulty: 2
  New target: 00
Iteration: 20, actual time in this block session: 0.02328724800099735, average time from beginning: 119.5168083216995
  New difficulty: 1
  New target: 0
Iteration: 21, actual time in this block session: 0.0016333409985236358, average time from beginning: 113.82560951309469
  New difficulty: 2
  New target: 00
Iteration: 22, actual time in this block session: 0.0171389220013225, average time from beginning: 108.65249721349954
  New difficulty: 3
  New target: 000
Iteration: 23, actual time in this block session: 0.33479873000032967, average time from beginning: 103.94303206204305
  New difficulty: 4
  New target: 0000
Iteration: 24, actual time in this block session: 4.347456918996613, average time from beginning: 99.79321643108278
  New difficulty: 5
  New target: 00000
Iteration: 25, actual time in this block session: 66.89345664199573, average time from beginning: 98.4772260395193
  New difficulty: 6
  New target: 000000
Iteration: 26, actual time in this block session: 1119.5109250960013, average time from beginning: 137.74775292630707
  New difficulty: 5
  New target: 00000
Iteration: 27, actual time in this block session: 93.2792503290002, average time from beginning: 136.10077134862902
  New difficulty: 4
  New target: 0000
[...]


Test 3


In the third test I checked longer buffer: instead AVG_SIZE=5 I took AVG_SIZE=20. Results were a little bit better, closer to the 50 seconds but not to much and again there was a periodic behavior but with longer sequence of 1s (get full test result):

Time expected for one block session: 50
Initial difficulty: 1
Initial target: 0
Iteration: 1, actual time in this block session: 0.0008473330017295666, average time from beginning: 0.0008473330017295666
  New difficulty: 2
  New target: 00
Iteration: 2, actual time in this block session: 0.011123863005195744, average time from beginning: 0.0059855980034626555
  New difficulty: 3
  New target: 000
Iteration: 3, actual time in this block session: 0.23029862100520404, average time from beginning: 0.08075660567070979
  New difficulty: 4
  New target: 0000
Iteration: 4, actual time in this block session: 7.143883028998971, average time from beginning: 1.846538211502775
  New difficulty: 5
  New target: 00000
Iteration: 5, actual time in this block session: 70.78438413099866, average time from beginning: 15.634107395401951
  New difficulty: 6
  New target: 000000
Iteration: 6, actual time in this block session: 822.982649090005, average time from beginning: 150.1921976778358
  New difficulty: 5
  New target: 00000
Iteration: 7, actual time in this block session: 73.58211055999345, average time from beginning: 139.24789951814404
  New difficulty: 4
  New target: 0000
Iteration: 8, actual time in this block session: 5.9023566039977595, average time from beginning: 122.57970665387575
  New difficulty: 3
  New target: 000
Iteration: 9, actual time in this block session: 0.24668137700064108, average time from beginning: 108.98714828977852
  New difficulty: 2
  New target: 00
Iteration: 10, actual time in this block session: 0.03010028899370809, average time from beginning: 98.09144348970003
  New difficulty: 1
  New target: 0
Iteration: 11, actual time in this block session: 0.0007694569976592902, average time from beginning: 89.17410948672709
  New difficulty: 1
  New target: 0
Iteration: 12, actual time in this block session: 0.001436733997252304, average time from beginning: 81.7430534239996
  New difficulty: 1
  New target: 0
Iteration: 13, actual time in this block session: 0.0011056109942728654, average time from beginning: 75.45521128453765
  New difficulty: 1
  New target: 0
Iteration: 14, actual time in this block session: 0.0008242829972004984, average time from beginning: 70.06561221299906
  New difficulty: 1
  New target: 0
Iteration: 15, actual time in this block session: 0.0009261160121241119, average time from beginning: 65.39463313986658
  New difficulty: 1
  New target: 0
Iteration: 16, actual time in this block session: 0.0008106659988698084, average time from beginning: 61.307519235249856
  New difficulty: 1
  New target: 0
Iteration: 17, actual time in this block session: 0.001714709993393626, average time from beginning: 57.701295439646536
  New difficulty: 1
  New target: 0
Iteration: 18, actual time in this block session: 0.0009492339959251694, average time from beginning: 54.49572065044372
  New difficulty: 1
  New target: 0
Iteration: 19, actual time in this block session: 0.0013766689990006853, average time from beginning: 51.62759728299926
  New difficulty: 1
  New target: 0
Iteration: 20, actual time in this block session: 0.0009627829931559972, average time from beginning: 49.04626555799896
  New difficulty: 2
  New target: 00
Iteration: 21, actual time in this block session: 0.010819625007570721, average time from beginning: 46.711244323094604
  New difficulty: 3
  New target: 000
Iteration: 22, actual time in this block session: 0.19661408599858987, average time from beginning: 44.59694294868115
  New difficulty: 4
  New target: 0000
Iteration: 23, actual time in this block session: 4.39537139100139, average time from beginning: 42.84904853312986
  New difficulty: 5
  New target: 00000
Iteration: 24, actual time in this block session: 78.79725923799924, average time from beginning: 44.34689064583275
  New difficulty: 4
  New target: 0000
Iteration: 25, actual time in this block session: 4.237956083001336, average time from beginning: 42.742533263319494
  New difficulty: 5
  New target: 00000
Iteration: 26, actual time in this block session: 120.4229515160041, average time from beginning: 45.730241657653515
  New difficulty: 6
  New target: 000000
Iteration: 27, actual time in this block session: 2144.451469672993, average time from beginning: 123.46065751007349
  New difficulty: 5
  New target: 00000
Iteration: 28, actual time in this block session: 82.4085827700037, average time from beginning: 121.99451198364243
  New difficulty: 4
  New target: 0000
Iteration: 29, actual time in this block session: 7.088480192011048, average time from beginning: 118.03223502531031
  New difficulty: 3
  New target: 000
Iteration: 30, actual time in this block session: 0.32278788200346753, average time from beginning: 114.10858678720008
  New difficulty: 2
  New target: 00
Iteration: 31, actual time in this block session: 0.015473107989237178, average time from beginning: 110.42816376529007
  New difficulty: 1
  New target: 0
Iteration: 32, actual time in this block session: 0.001170495008409489, average time from beginning: 106.97732022559376
  New difficulty: 1
  New target: 0
Iteration: 33, actual time in this block session: 0.0012659739804803394, average time from beginning: 103.73562161190851
  New difficulty: 1
  New target: 0
Iteration: 34, actual time in this block session: 0.0006614820085815154, average time from beginning: 100.6845933727938
  New difficulty: 1
  New target: 0
Iteration: 35, actual time in this block session: 0.0013456619999487884, average time from beginning: 97.80792915248541
  New difficulty: 1
  New target: 0
Iteration: 36, actual time in this block session: 0.0011202770110685378, average time from beginning: 95.0910733503889
  New difficulty: 1
  New target: 0
Iteration: 37, actual time in this block session: 0.001109313998313155, average time from beginning: 92.52107432237834
  New difficulty: 1
  New target: 0
Iteration: 38, actual time in this block session: 0.001492470022640191, average time from beginning: 90.08634848415845
  New difficulty: 1
  New target: 0
Iteration: 39, actual time in this block session: 0.0013962289885967039, average time from beginning: 87.77647791351308
  New difficulty: 1
  New target: 0
Iteration: 40, actual time in this block session: 0.0016892839994397946, average time from beginning: 85.58210819777523
  New difficulty: 1
  New target: 0
Iteration: 41, actual time in this block session: 0.0010298320048605092, average time from beginning: 83.49476482300035
  New difficulty: 1
  New target: 0
Iteration: 42, actual time in this block session: 0.0010815860077855177, average time from beginning: 81.50681998402433
  New difficulty: 1
  New target: 0
Iteration: 43, actual time in this block session: 0.0017287490045418963, average time from beginning: 79.61135274600062
  New difficulty: 1
  New target: 0
Iteration: 44, actual time in this block session: 0.0013874269934603944, average time from beginning: 77.80203535238682
  New difficulty: 1
  New target: 0
Iteration: 45, actual time in this block session: 0.0009098409936996177, average time from beginning: 76.07312145213363
  New difficulty: 1
  New target: 0
Iteration: 46, actual time in this block session: 0.0007116970082279295, average time from beginning: 74.41937341397873
  New difficulty: 1
  New target: 0
Iteration: 47, actual time in this block session: 0.0011911690089618787, average time from beginning: 72.83600783429853
  New difficulty: 2
  New target: 00
Iteration: 48, actual time in this block session: 0.01770458400278585, average time from beginning: 71.31895984991736
  New difficulty: 3
  New target: 000
Iteration: 49, actual time in this block session: 0.3016881000075955, average time from beginning: 69.8696277733886
  New difficulty: 4
  New target: 0000
Iteration: 50, actual time in this block session: 2.5134192319819704, average time from beginning: 68.52250360256046
  New difficulty: 5
  New target: 00000
Iteration: 51, actual time in this block session: 113.24100577100762, average time from beginning: 69.39933697841236
  New difficulty: 6
  New target: 000000
Iteration: 52, actual time in this block session: 1504.1232085039883, average time from beginning: 96.99018066159653
  New difficulty: 5
  New target: 00000
Iteration: 53, actual time in this block session: 82.64287953899475, average time from beginning: 96.71947686683045
  New difficulty: 4
  New target: 0000
Iteration: 54, actual time in this block session: 6.377737554983469, average time from beginning: 95.04648169438885
  New difficulty: 3
  New target: 000
Iteration: 55, actual time in this block session: 0.31096615399292205, average time from beginning: 93.32401777547256
[...]


Test 4


In the fourth test I ask myself: What is my goal? Do I want to have an average of a few last sessions (5 or 20) or rather average session in the whole history should be close to 50? That is why I decided to take into account a total time needed for solving all puzzles:


[... All imports as in previous case ...]

def proofOfWork(blockOfData, target):
  [... No changes in this function ...]

def test(numberOfBlocks, averageTimePerBlock, iterations):  
  dataJSON = {"name": "Piotr", "country": "Poland"}
  [... No changes ...]
  
  for i in range(iterations):
    timeActual = 0
    for b in range(numberOfBlocks):
      proofOfWork(blockOfData, target)
      timeActual += blockOfData['powTime']
    timeActualTotal += timeActual
    
    v = timeActualTotal/(i+1)
    
    if v < 0.9*timeExpected:
      d = +1
    elif v > 1.1*timeExpected:
      d = -1
    else:
      d = 0
    
    difficulty = difficulty + int(d)
    [... No changes ...]

def main():
  test(10, 5, 100)

if __name__=="__main__":
    main()
Because I did not want to be to sensitive I added a margin +/-10% of timeExpected. With that change results was close to 50 seconds (get full test result):

Time expected for one block session: 50
Initial difficulty: 1
Initial target: 0
Iteration: 1, actual time in this block session: 0.0007073659871821292, average time from beginning: 0.0007073659871821292
  New difficulty: 2
  New target: 00
Iteration: 2, actual time in this block session: 0.019158029994287062, average time from beginning: 0.009932697990734596
  New difficulty: 3
  New target: 000
Iteration: 3, actual time in this block session: 0.3371423659918946, average time from beginning: 0.11900258732445461
  New difficulty: 4
  New target: 0000
Iteration: 4, actual time in this block session: 5.39044728299632, average time from beginning: 1.4368637612424209
  New difficulty: 5
  New target: 00000
Iteration: 5, actual time in this block session: 54.133834399995976, average time from beginning: 11.976257888993132
  New difficulty: 6
  New target: 000000
Iteration: 6, actual time in this block session: 1591.906396348997, average time from beginning: 275.2979476323271
  New difficulty: 5
  New target: 00000
Iteration: 7, actual time in this block session: 101.15358611400734, average time from beginning: 250.42018170113857
  New difficulty: 4
  New target: 0000
Iteration: 8, actual time in this block session: 4.246326195003348, average time from beginning: 219.64844976287168
  New difficulty: 3
  New target: 000
Iteration: 9, actual time in this block session: 0.3598079739967943, average time from beginning: 195.28304511966337
  New difficulty: 2
  New target: 00
Iteration: 10, actual time in this block session: 0.02401075699890498, average time from beginning: 175.75714168339692
  New difficulty: 1
  New target: 0
Iteration: 11, actual time in this block session: 0.001134524994995445, average time from beginning: 159.7793228508149
  New difficulty: 1
  New target: 0
Iteration: 12, actual time in this block session: 0.0012136589793954045, average time from beginning: 146.46448041816197
  New difficulty: 1
  New target: 0
Iteration: 13, actual time in this block session: 0.0009199720079777762, average time from beginning: 135.19805269153474
  New difficulty: 1
  New target: 0
Iteration: 14, actual time in this block session: 0.0006686050037387758, average time from beginning: 125.54109668535395
  New difficulty: 1
  New target: 0
Iteration: 15, actual time in this block session: 0.0021323710097931325, average time from beginning: 117.171832397731
  New difficulty: 1
  New target: 0
Iteration: 16, actual time in this block session: 0.0012575889923027717, average time from beginning: 109.84867147218483
  New difficulty: 1
  New target: 0
Iteration: 17, actual time in this block session: 0.0016607900033704937, average time from beginning: 103.3870826085271
  New difficulty: 1
  New target: 0
Iteration: 18, actual time in this block session: 0.0013249200128484517, average time from beginning: 97.64342940360964
  New difficulty: 1
  New target: 0
Iteration: 19, actual time in this block session: 0.0010178179945796728, average time from beginning: 92.5043551096299
  New difficulty: 1
  New target: 0
Iteration: 20, actual time in this block session: 0.0007381690011243336, average time from beginning: 87.87917426259847
  New difficulty: 1
  New target: 0
Iteration: 21, actual time in this block session: 0.0013525039830710739, average time from beginning: 83.69451608361678
  New difficulty: 1
  New target: 0
Iteration: 22, actual time in this block session: 0.001664494011492934, average time from beginning: 79.89029555681654
  New difficulty: 1
  New target: 0
Iteration: 23, actual time in this block session: 0.0005619560251943767, average time from beginning: 76.41682887852126
  New difficulty: 1
  New target: 0
Iteration: 24, actual time in this block session: 0.0014818529962212779, average time from beginning: 73.23285608579106
  New difficulty: 1
  New target: 0
Iteration: 25, actual time in this block session: 0.0011747520038625225, average time from beginning: 70.30358883243956
  New difficulty: 1
  New target: 0
Iteration: 26, actual time in this block session: 0.0008059849860728718, average time from beginning: 67.59963564599904
  New difficulty: 1
  New target: 0
Iteration: 27, actual time in this block session: 0.001001966003968846, average time from beginning: 65.09598254673996
  New difficulty: 1
  New target: 0
Iteration: 28, actual time in this block session: 0.0014708889939356595, average time from beginning: 62.77117855896332
  New difficulty: 1
  New target: 0
Iteration: 29, actual time in this block session: 0.0017285370049648918, average time from beginning: 60.606714765102694
  New difficulty: 1
  New target: 0
Iteration: 30, actual time in this block session: 0.0011418599970056675, average time from beginning: 58.58652900159917
  New difficulty: 1
  New target: 0
Iteration: 31, actual time in this block session: 0.0008955259982030839, average time from beginning: 56.69666985722494
  New difficulty: 1
  New target: 0
Iteration: 32, actual time in this block session: 0.0012429210109985434, average time from beginning: 54.92493776546826
  New difficulty: 1
  New target: 0
Iteration: 33, actual time in this block session: 0.0015098579970072024, average time from beginning: 53.26059146524186
  New difficulty: 1
  New target: 0
Iteration: 34, actual time in this block session: 0.0009735359999467619, average time from beginning: 51.6941321143818
  New difficulty: 1
  New target: 0
Iteration: 35, actual time in this block session: 0.0007953690219437703, average time from beginning: 50.21717963594295
  New difficulty: 1
  New target: 0
Iteration: 36, actual time in this block session: 0.0017853930112323724, average time from beginning: 48.822307573639286
  New difficulty: 1
  New target: 0
Iteration: 37, actual time in this block session: 0.0016964810056379065, average time from beginning: 47.5028315981627
  New difficulty: 1
  New target: 0
Iteration: 38, actual time in this block session: 0.00177498201810522, average time from beginning: 46.25280379247469
  New difficulty: 1
  New target: 0
Iteration: 39, actual time in this block session: 0.0012587750097736716, average time from beginning: 45.06686674074482
  New difficulty: 1
  New target: 0
Iteration: 40, actual time in this block session: 0.0006702819955535233, average time from beginning: 43.94021182927609
  New difficulty: 2
  New target: 00
Iteration: 41, actual time in this block session: 0.01707928100222489, average time from beginning: 42.86891591346453
  New difficulty: 3
  New target: 000
Iteration: 42, actual time in this block session: 0.2777844760057633, average time from beginning: 41.8548413554298
  New difficulty: 4
  New target: 0000
Iteration: 43, actual time in this block session: 5.314759725006297, average time from beginning: 41.00507201518739
  New difficulty: 5
  New target: 00000
Iteration: 44, actual time in this block session: 103.1780660160075, average time from beginning: 42.41809460611512
  New difficulty: 6
  New target: 000000
Iteration: 45, actual time in this block session: 1062.9671913070197, average time from beginning: 65.09696342169077
  New difficulty: 5
  New target: 00000
Iteration: 46, actual time in this block session: 55.84555622699554, average time from beginning: 64.89584587398001
  New difficulty: 4
  New target: 0000
Iteration: 47, actual time in this block session: 4.798752638991573, average time from beginning: 63.61718431578877
  New difficulty: 3
  New target: 000
Iteration: 48, actual time in this block session: 0.2716985910083167, average time from beginning: 62.297486696522505
  New difficulty: 2
  New target: 00
Iteration: 49, actual time in this block session: 0.009874090981611516, average time from beginning: 61.02631092906249
  New difficulty: 1
  New target: 0
Iteration: 50, actual time in this block session: 0.0016299890048685484, average time from beginning: 59.80581731026134
[...]


Test 5


In my last attempt I have tested last case but without 10% sensitivity margin:

[... All imports as in previous case ...]

def proofOfWork(blockOfData, target):
  [... No changes in this function ...]

def test(numberOfBlocks, averageTimePerBlock, iterations):  
  dataJSON = {"name": "Piotr", "country": "Poland"}
  [... No changes ...]
  
  for i in range(iterations):
    timeActual = 0
    for b in range(numberOfBlocks):
      proofOfWork(blockOfData, target)
      timeActual += blockOfData['powTime']
    timeActualTotal += timeActual
    
    v = timeActualTotal/(i+1)
    
    if v < timeExpected:
      d = +1
    elif v > timeExpected:
      d = -1
    else:
      d = 0
    
    difficulty = difficulty + int(d)
    [... No changes ...]

def main():
  test(10, 5, 100)

if __name__=="__main__":
    main()
In my personal opinion that results was better than previous (get full test result):


Time expected for one block session: 50
Initial difficulty: 1
Initial target: 0
Iteration: 1, actual time in this block session: 0.0009722109971335158, average time from beginning: 0.0009722109971335158
  New difficulty: 2
  New target: 00
Iteration: 2, actual time in this block session: 0.02295075199799612, average time from beginning: 0.011961481497564819
  New difficulty: 3
  New target: 000
Iteration: 3, actual time in this block session: 0.2787051940031233, average time from beginning: 0.10087605233275099
  New difficulty: 4
  New target: 0000
Iteration: 4, actual time in this block session: 3.7423888179910136, average time from beginning: 1.0112542437473167
  New difficulty: 5
  New target: 00000
Iteration: 5, actual time in this block session: 72.24244248400646, average time from beginning: 15.257491891799145
  New difficulty: 6
  New target: 000000
Iteration: 6, actual time in this block session: 999.094253951007, average time from beginning: 179.23028556833378
  New difficulty: 5
  New target: 00000
Iteration: 7, actual time in this block session: 98.64153173900559, average time from beginning: 167.71760644985832
  New difficulty: 4
  New target: 0000
Iteration: 8, actual time in this block session: 3.5787798250094056, average time from beginning: 147.2002531217522
  New difficulty: 3
  New target: 000
Iteration: 9, actual time in this block session: 0.4243360680047772, average time from beginning: 130.89181789355806
  New difficulty: 2
  New target: 00
Iteration: 10, actual time in this block session: 0.019377715994778555, average time from beginning: 117.80457387580172
  New difficulty: 1
  New target: 0
Iteration: 11, actual time in this block session: 0.0010464509978191927, average time from beginning: 107.09516229172864
  New difficulty: 1
  New target: 0
Iteration: 12, actual time in this block session: 0.0015601479899487458, average time from beginning: 98.17069544641708
  New difficulty: 1
  New target: 0
Iteration: 13, actual time in this block session: 0.0010126500128535554, average time from beginning: 90.61918138515522
  New difficulty: 1
  New target: 0
Iteration: 14, actual time in this block session: 0.001615180997760035, average time from beginning: 84.14649808485827
  New difficulty: 1
  New target: 0
Iteration: 15, actual time in this block session: 0.001489256988861598, average time from beginning: 78.53683082966697
  New difficulty: 1
  New target: 0
Iteration: 16, actual time in this block session: 0.0011605780018726364, average time from beginning: 73.6283514389379
  New difficulty: 1
  New target: 0
Iteration: 17, actual time in this block session: 0.0016043559953686781, average time from beginning: 69.29736631641187
  New difficulty: 1
  New target: 0
Iteration: 18, actual time in this block session: 0.0009787070084712468, average time from beginning: 65.44756700477835
  New difficulty: 1
  New target: 0
Iteration: 19, actual time in this block session: 0.0008642329994472675, average time from beginning: 62.00300370100051
  New difficulty: 1
  New target: 0
Iteration: 20, actual time in this block session: 0.0010681060084607452, average time from beginning: 58.9029069212509
  New difficulty: 1
  New target: 0
Iteration: 21, actual time in this block session: 0.0008165289837052114, average time from beginning: 56.09804547400009
  New difficulty: 1
  New target: 0
Iteration: 22, actual time in this block session: 0.000983384990831837, average time from beginning: 53.548179015408756
  New difficulty: 1
  New target: 0
Iteration: 23, actual time in this block session: 0.0017145689926110208, average time from beginning: 51.22007186556458
  New difficulty: 1
  New target: 0
Iteration: 24, actual time in this block session: 0.002563157002441585, average time from beginning: 49.08600900270782
  New difficulty: 2
  New target: 00
Iteration: 25, actual time in this block session: 0.015341991012974177, average time from beginning: 47.12318232224003
  New difficulty: 3
  New target: 000
Iteration: 26, actual time in this block session: 0.3237317339880974, average time from beginning: 45.323203453461105
  New difficulty: 4
  New target: 0000
Iteration: 27, actual time in this block session: 3.6816858960009995, average time from beginning: 43.78092502540703
  New difficulty: 5
  New target: 00000
Iteration: 28, actual time in this block session: 98.48804580501019, average time from beginning: 45.734750767535715
  New difficulty: 6
  New target: 000000
Iteration: 29, actual time in this block session: 960.3462498250083, average time from beginning: 77.27307832124167
  New difficulty: 5
  New target: 00000
Iteration: 30, actual time in this block session: 82.11634316900745, average time from beginning: 77.43452048283386
  New difficulty: 4
  New target: 0000
Iteration: 31, actual time in this block session: 5.1479088550040615, average time from beginning: 75.10269430129095
  New difficulty: 3
  New target: 000
Iteration: 32, actual time in this block session: 0.23889145200519124, average time from beginning: 72.76320046225078
  New difficulty: 2
  New target: 00
Iteration: 33, actual time in this block session: 0.018000645985011943, average time from beginning: 70.55880046781849
  New difficulty: 1
  New target: 0
Iteration: 34, actual time in this block session: 0.0011132930085295811, average time from beginning: 68.48357437444172
  New difficulty: 1
  New target: 0
Iteration: 35, actual time in this block session: 0.0012155420045019127, average time from beginning: 66.5269355506578
  New difficulty: 1
  New target: 0
Iteration: 36, actual time in this block session: 0.0011693080014083534, average time from beginning: 64.6789975994729
  New difficulty: 1
  New target: 0
Iteration: 37, actual time in this block session: 0.0019762020237976685, average time from beginning: 62.93096999413644
  New difficulty: 1
  New target: 0
Iteration: 38, actual time in this block session: 0.0017945409927051514, average time from beginning: 61.27493906115897
  New difficulty: 1
  New target: 0
Iteration: 39, actual time in this block session: 0.0012429240086930804, average time from beginning: 59.70381864738589
  New difficulty: 1
  New target: 0
Iteration: 40, actual time in this block session: 0.0012324479976086877, average time from beginning: 58.21125399240118
  New difficulty: 1
  New target: 0
Iteration: 41, actual time in this block session: 0.0011047049993067048, average time from beginning: 56.791494253684064
  New difficulty: 1
  New target: 0
Iteration: 42, actual time in this block session: 0.001545759972941596, average time from beginning: 55.439352622881415
  New difficulty: 1
  New target: 0
Iteration: 43, actual time in this block session: 0.002248727992991917, average time from beginning: 54.150117648581684
  New difficulty: 1
  New target: 0
Iteration: 44, actual time in this block session: 0.001076415996067226, average time from beginning: 52.91945762056837
[...]
To be honest, again the difficulty is very predictable with one high difficulty (difficulty=6) followed by the long series of difficulty=1. Enough for toy example to understand fundamentals.

Summary of tests


To be concise: with simple and easy to understand difficulty of the number of leading zeros in the hash of block I recommend to use total time needed to add all blocks:


    v = timeActualTotal/(i+1)
    
    if v < timeExpected:
      d = +1
    elif v > timeExpected:
      d = -1
    else:
      d = 0
    
    difficulty = difficulty + int(d)
Because of very periodic nature of this approach it is good for didactic purposes but not for production code.

Target and difficulty in bitcoin


In case of Bitcoin in the block header of every block you can find the difficulty field and the bits field which is a way of storing the target in compact representation.

bits field always takes 4 bytes, 8 hexadecimal digits, divided in two parts:

  • exponent (1 byte length): this gives you the length of the target in bytes (without leading zeros).
  • coefficient (3 bytes length): this gives you the initial 3 bytes of the target.


For example, if bits are:


bits: 0x051ABCD6
then after splitting it into two parts you obtain:


exponent: 05
coefficient: 1ABCD6
This codes the following target:

target: 0x1ABCD60000 which in full size form (32 bytes length) with leading zeros takes the following value:


                                                    coefficient (1ABCD6)
                                                              ------
target: 0000000000000000000000000000000000000000000000000000001ABCD60000
                                                              <---------
                                               exponent (0x05 = 5 bytes)


The value for targetMax in compact representation is 1D00FFFF. After splitting it into two parts you obtain:


exponent: 1D (16) = 29 (10)
coefficient: 00FFFF
In full size form (32 bytes length) with leading zeros it looks like I have mentioned earlier:


        coefficient (00FFFF)
        ------
0x00000000FFFF0000000000000000000000000000000000000000000000000000
  -----><---------------------------------------------------------
    |   exponent (0x1D = 29 = 3 coefficient bytes + 26 zero bytes)
    |
    leading zeros


Summary


In this chapter you have learned how difficulty controls target which in turn influence the speed at which you add new blocks (session blocks) to the blockchain. This control is indispensable part of blockchain as it limit the number of blocks you can add in time interval. This way bad people can't forge past block as they would have to catch up and overtake the newest block. Because of difficulty they can't do this faster than assumed, constant time which causes them to be unable to outrun the newest block.