zawy12 / difficulty-algorithms

See the Issues for difficulty algorithms
MIT License
107 stars 25 forks source link

Estimating Chain Work Based on Lowest Hashes #77

Open zawy12 opened 6 months ago

zawy12 commented 6 months ago

These two different ways to estimate total chain work by the lowest hashes. It doesn't require knowing any difficulties or timestamps, or even max_target in the simplest form.

Potential Uses This might be useful for "pruning the consensus layer" for "decentralized, trustless checkpoints" for things like SPV wallets and DAGs (where the number of block headers can be burdensome). "Checkpoints" including a "Proof of PoW" can be created by including all headers with the lowest hashes ever seen. The size of the proof increases logarithmically with chain work. See "Mining in Logarithmic Space".

Given the N lowest hashes ever seen:

*chain_work = (2^256 -1) (N-1) / Nth_lowest_hash** (eq 1) StdDev of the error = 1/SQRT(N-1) for N > 10 on the condition that difficulty target was never < Nth_lowest_hash

This equation comes from viewing Nth_lowest_hash as a target that was met by N-1 hashes. As a review: difficulty = (2^256-1)/target = 2^32 BTC_difficulty
Chain_work = number_of_hashes_below_target
difficulty

The StdDev equation is my guess, supported by experiment (see code below). The equation assumes all the lowest hashes ever hashed are on the blockchain as a block hash which is the case if the PoW target never fell below Nth_lowest_hash (and assuming no orphans were lower than the Nth, otherwise they need to be included in N). In other words, difficulty must not have ever been > chain_work/(N-1). Unknown hashes smaller than the Nth (such as orphans) would silently increase N which would increase the estimate. N can be large to get good accuracy: up to height/14 =~ 60,000 for today's Bitcoin.

For the case of N=1, the statistics behind above equation have no solution (small hashes greatly increase the result and you could get a divide by zero) but experiment indicates the following where the "6" could be anything from 1 to infinity in any particular million runs that calculate an average. Usually it's from 2 to 12:

chain_work = (2^256 -1) / 6 / lowest_hash
StdDev =~ 5000%

The equation can be simplified. We replace the Nth_lowest_hash target with a number of leading zeros ("u") that has M hashes below it (M = N-1). The target for u leading zeros is 2^(256-u). Eq 1 simplifies (with an error of 10^(-78)) to:

chain_work = (2^256-1) M / 2^(256-u) = M 2^u (eq 2) Stdev err = 1/sqrt(M)

As before, this equation is chain_work = M * difficulty, i.e. M hashes were found at an imaginary difficulty that has been in place since genesis. It's still on the condition that the blockchain's difficulties never exceeded 2^u, i.e. u must be > log(highest_difficulty) / log(2). Bitcoin's highest-ever difficulty is currently 85 T (times 2^32) which shows u must be > 78 to meet that condition. There are about 60,000 blocks with hashes < 2^79, which has about 0.4% expected & actual error.

It's interesting and important to note that eq 2 isn't valid if you choose M and then count the leading zeros (u). Adam Back made this error. This is because the actual u (the 2^u imaginary difficulty) for that M could have been u, u-1, u-2, but not u+1, u+2, etc. In other words, you're taking into account M's that were lucky but not the unlucky ones. This would overestimate but not underestimate the total work, so the mean of many such observations will be an overestimate (by experiment: ~10x for M=1, 3.7x for M=2, 2.2x for M=3, and 1.6x for M=4). If you use it correctly (choose u first) and expect (via knowing the actual number of hashes) a mean of M=1, many tests runs will have M=0 which reduces the mean to the correct mean.

In the notation of "Mining in Logarithmic Space" M = 2m = 6k = 36. I started working on this because I couldn't see their estimate for total chain work, just a way to determine which of two chains is longer.

If leading zeros are in hex: chain_work = M * 16^u

As of block height 826532, there are 96 block hashes with 22 or more leading zeros when expressed in hex. Current chain work is 3.17E28 and the equation gives 96 * 16^22 = 2.97E28, a 6.3% error.

Using eq 1 for Proof of PoW

The estimation might be used to prune the proof of work in the following scheme: If a block finds one of the N=100 lowest hashes ever seen, then the block that mines on top of him declares himself the newest checkpoint and includes the 100 headers that have the lowest hashes ever seen. He gets the other 99 from the prior checkpoint. Then every block after his will reference his block hash & height as the most recent checkpoint that everyone must store. Total chain work is the work implied in the headers in the most recent checkpoint as determined by equation 1 plus the sum of difficulties (times 2^32 if used in BTC) after the checkpoint. This prevents the need to refer to earlier checkpoints to get PoPoW. An attacker would need to mine about 1/N the total chain work to subvert the most recent checkpoint. The number of blocks back to the most recent checkpoint increase as total work increases if N is a constant. Increasing N with chain work to prevent this "increase back to prior checkpoint" requires knowing none of the N hashes were ever above the lowest target (which may require removing some of the earliest N's) and making an assumption about (or an enforcement of) how much difficulty changes between checkpoints. An attacker may find a new low hash and not disclose it for a while, enabling double-spending, so the majority of hashrate needs to be honest and to stay online since the most recent checkpoint to ignore new checkpoints that don't include all blocks since the previous checkpoint.

Bitcoin Observations Real world example for the 1st equation: 10th lowest hash for BTC as of height 720,441 (when chainwork was 1.23E28) was in block 696,345 who's hash was 8.8E49. 000000000000000000036a76070bdfc971182b2a7430b1cbd99297fc9a6b513f chain_work = (2^256-1) * (10-1) / 8.8E49 = 1.3E28 (6% error).

A more complete example from this data. The data is also at the end of this article.

image

Here's an example of using eq 2 as of January 24, 2024.

image

The above M values was collected using the following SQL after registering at dune.com. The example below is for 20 leading hex zeros (80 in binary) because it's 19 hex zeros following by "1". Change the 1 to 2 for 79 leading binary zeros, and change the 1 to 80 for 81 leading binary zeros (the 0 after the 8 is needed due to a quirk in their SQL wanting an even number of characters).

SELECT
  COUNT(*)
FROM bitcoin.blocks
WHERE
hash < 0x00000000000000000001

The following is experimental tests to show 1st equation is correct.

# equation 1, chain_work =  (2^256 -1) * (N-1) / Nth_lowest_hash
import random
import statistics
runs=100 # number of times to do the experiment
hashes=100000 # number of hashes to do in each experiment
N=5 # number of lowest hashes to use in the calculation
max_target = pow(2,256)
avg_max = 0
max_all = []
for i in range(1, runs):
    # generate hash targets with values 0 to max_target. 
    hash_list = [random.randint(1,max_target) for _ in range(hashes)]
    lowest_hashes = sorted(hash_list)[:N]
    max_of_low_hashes = max(lowest_hashes)      
    if N==1:
        max_all.append(max_target/6/max_of_low_hashes)
        avg_max = avg_max + max_target/6/max_of_low_hashes/runs
    else:
        max_all.append(max_target*(N-1)/max_of_low_hashes) 
        avg_max = avg_max + max_target*(N-1)/max_of_low_hashes/runs

print("N = " + str(N))
print("actual chain work (hashes) = " + str(hashes))
print(f"Estimated CW, avg of runs = max_target * (N-1) / max_of_N_lowest_targets: {avg_max:,.0f}")
print(f"Stdev: {statistics.stdev(max_all):,.0f}")
Output to supports the 1st equation: Total hashes (actual chain work): 10,000 Runs: 30,000 N Mean Est of Work Stdev
3 10,000 10,000
5 10,000 6,000
10 10,000 3,500
20 10,000 2,350
100 10,000 1,000
200 10,000 720

Lowest 12 block hashes as of 773048. Chain work as of then was 1.93E28.

Block 756951 ([0000000000000000000000005d6f06154c8685146aa7bc3dc9843876c9cefd0f](https://mempool.space/block/0000000000000000000000005d6f06154c8685146aa7bc3dc9843876c9cefd0f))
Block 742035 ([000000000000000000000000fcb36c64b8a99acde151e61c933c6f7a57271db3](https://mempool.space/block/000000000000000000000000fcb36c64b8a99acde151e61c933c6f7a57271db3))
Block 768824 ([00000000000000000000000351eae66e03ae45aad1be8f94d1ca5d6fe98b6efa](https://mempool.space/block/00000000000000000000000351eae66e03ae45aad1be8f94d1ca5d6fe98b6efa))
Block 634842 ([000000000000000000000003681c2df35533c9578fb6aace040b0dfe0d446413](https://mempool.space/block/000000000000000000000003681c2df35533c9578fb6aace040b0dfe0d446413))
Block 585774 ([000000000000000000000019b43763eb4519f4fe65eae9be90fe73117b89026d](https://mempool.space/block/000000000000000000000019b43763eb4519f4fe65eae9be90fe73117b89026d))
Block 675600 ([00000000000000000000001a9bf725a1f7d019440a04f39706c083751b62974d](https://mempool.space/block/00000000000000000000001a9bf725a1f7d019440a04f39706c083751b62974d))
Block 733234 ([00000000000000000000001c79ed1fce45cf47b145fc4564a979731765a0aeca](https://mempool.space/block/00000000000000000000001c79ed1fce45cf47b145fc4564a979731765a0aeca))
Block 658771 ([00000000000000000000001e9590a06c8452a3ce553834b2bab3daebf62f8b79](https://mempool.space/block/00000000000000000000001e9590a06c8452a3ce553834b2bab3daebf62f8b79))
Block 679468 ([0000000000000000000000250fae6b97e3241d86c65fb5be489875c49032b25b](https://mempool.space/block/0000000000000000000000250fae6b97e3241d86c65fb5be489875c49032b25b))
Block 738031 ([000000000000000000000027ecac06b57e047cf42357d584ffe5bae94ae29a5b](https://mempool.space/block/000000000000000000000027ecac06b57e047cf42357d584ffe5bae94ae29a5b))
Block 724691 ([00000000000000000000002a2a53d24ef9e2f8eb8dd628e603bfcac472aeffc3](https://mempool.space/block/00000000000000000000002a2a53d24ef9e2f8eb8dd628e603bfcac472aeffc3))
Block 679848 ([00000000000000000000002d142973ed07a220bf571360b70b90f4f0a1e739ce](https://mempool.space/block/00000000000000000000002d142973ed07a220bf571360b70b90f4f0a1e739ce))

Here's the code for the leadings zeros method for measuring chain work (identical to the other method, but in a different math route).

# equation 2, chain_work = M * 2^leading_zeros
import random
import statistics
runs = 1000 # number of times to do the experiment
hashes = 10000 # number of hashes to do in each experiment
u = 13
difficulty = pow(2,u)
max_target = pow(2,256)
all_run_counts = []
for i in range(1, runs+1):
    count=0
    for j in range(1,hashes+1):
        hash=max_target*random.random()
        if hash < max_target/difficulty:
            count+=1
    all_run_counts.append(count)
print(f"Selected u-level (leading zeros): {u:,.0f}")
print(f"{hashes:,.0f} hashes in each of {runs:,.0f} runs.")
print(f"Mean  of estimated hashes: {statistics.mean(all_run_counts)*difficulty:,.0f}")
print(f"Stdev of estimated hashes: {statistics.stdev(all_run_counts)*difficulty:,.0f}")
print(f"Mean  of hashes below 2^(256-u): {statistics.mean(all_run_counts):,.2f}")
print(f"Stdev of hashes below 2^(256-u): {statistics.stdev(all_run_counts):,.2f}")

Lowest 100 hashes as of bitcoin block height 826532 (chain work 3.17E28). To get these, I registered at dune.com and asked it's A.I. "What are the 100 lowest block hashes?"

0000000000000000000000005d6f06154c8685146aa7bc3dc9843876c9cefd0f
000000000000000000000000fcb36c64b8a99acde151e61c933c6f7a57271db3
00000000000000000000000351eae66e03ae45aad1be8f94d1ca5d6fe98b6efa
000000000000000000000003681c2df35533c9578fb6aace040b0dfe0d446413
000000000000000000000018f3ab29c4c0e4a99d6850ccdedd2acd94e39b6ea6
000000000000000000000019b43763eb4519f4fe65eae9be90fe73117b89026d
00000000000000000000001a9bf725a1f7d019440a04f39706c083751b62974d
00000000000000000000001c79ed1fce45cf47b145fc4564a979731765a0aeca
00000000000000000000001e9590a06c8452a3ce553834b2bab3daebf62f8b79
00000000000000000000002095eb0263fe9ff393ad4b6cac66f27bcdf3f56b06
000000000000000000000020b1bdc17cfeb6560d4ae534325d6e07b6bd30e49a
0000000000000000000000250fae6b97e3241d86c65fb5be489875c49032b25b
000000000000000000000027ecac06b57e047cf42357d584ffe5bae94ae29a5b
00000000000000000000002a2a53d24ef9e2f8eb8dd628e603bfcac472aeffc3
00000000000000000000002d142973ed07a220bf571360b70b90f4f0a1e739ce
00000000000000000000002d99f38e592520813d7e7b7b205c5db2880669ef05
00000000000000000000002eda7fb2798a843b5b251161648090593cf17d0890
000000000000000000000030f8cf8e0a76db53525aff8d56dcfdf4c74fc7878c
000000000000000000000031a10e42c80137b3c3ad3e15c5dfb4ea213c83e497
000000000000000000000031bf126ebcb4915fb443a360f9c25cf19cb3dff669
000000000000000000000032ad53b18dadb72800d883f8e1188ceaa566b9a222
000000000000000000000032c706e8f67ae02adf7693354a336b027b20c347bc
00000000000000000000003316783795fea92381b0fea5943c557f1d2f6e8cff
000000000000000000000037794ea9d56b1ba4a618b528d756f499eb1fa603bd
000000000000000000000037d7bb7e41021b1521414211625613e4a659f1d342
000000000000000000000038efd88be72dca654e1bfef2b7186efbcd53de3a3f
00000000000000000000003c5c9269d93153a4eb8fabef76318d849a2ec2b29e
00000000000000000000003df99e3bb8a167c6f4c37d21ad3453f188d010f095
00000000000000000000003e27723c907f8d3cf2a8ec8ce1c96381da02ec83b2
000000000000000000000040d07ecd61c03c87fa6c7b911986a874ea4ce18bbc
000000000000000000000043c81703f5a38817c2d3d766a06af1cb36d973c2b6
000000000000000000000044c68767c0ae776f2b57934fc08df313acf0e08149
000000000000000000000047a2be7521efc7cae552f49da07eb90b25fe00e369
00000000000000000000004940fbfab5c53bb1280fb61634fdb97596758159d5
0000000000000000000000510235407e9348ae570405cc646f81a14359fa0878
00000000000000000000005bd08c9d7691c94c85885985a268b9612491789f96
00000000000000000000005d2ebe6b2d44ae4114db92f8afc4126f06af829a2a
00000000000000000000005ef5322ffefb3cd51f5fbcd818f04d50ac2e308adf
00000000000000000000005fa3a83f9e727c795bae4a7048918bad5515752cd2
000000000000000000000063bb1d8713477cc87fd5cb8748803e25124e86097c
00000000000000000000006778a1bd9554fdf39c5ba7a36d01481fdeafa35acc
0000000000000000000000685308287fb3d0de0a7e4136f29b01b499b5147368
000000000000000000000069f1b863743ddcdc52ad1db175bb0a7852450453cb
0000000000000000000000705ea4a5b31b366c9919c38933ba162fcfec3c73ef
0000000000000000000000777b2ce70e001fd788734fea4b7c84b1184dabb97a
00000000000000000000007a11881ac7f2b67cb9684ddb86b6d3091a8294c490
00000000000000000000007c0b2ffb45514fd4f30883cec495275bf37013443a
00000000000000000000007df8f6ec224abe764c14e4192c8b9e80057e0f575d
000000000000000000000082bd248e332be398836e10ea5de3ad796983f1ca56
000000000000000000000084dc46d0da1c920a9b1ce16d91159655cfe1055482
00000000000000000000008af49708ed309e0b670d140ac9c85ec48c177ae400
00000000000000000000008b80d0529bc20ac2c580f85acd2aed0baf5b82bdf5
00000000000000000000008ff10f4ef190438ddcd6fa62a24108ce762f19b3b5
00000000000000000000009108ce927075bd263aa1a2448b6f3a762bcd2fd90a
000000000000000000000093172f61f0327ff9ca6bedd1605432de858960a8bc
00000000000000000000009d53abf331117bebe4dd88954e7df3689b0b7548fa
00000000000000000000009e4e0460432431268c28b94bc650b914a2824c7c03
0000000000000000000000a51e64f61ef271a1ab42592972cd13122a9933f8d3
0000000000000000000000a6779a0013b17e1513ce0828bc04c757232633b770
0000000000000000000000a773ce38733b4f36cf2e52581e055e3a4216291256
0000000000000000000000aafe45a63d97c580f2b1f0de258b3260661bd337de
0000000000000000000000ab789f6d71d9642ae3f697975ccd00afcb98fe6bd2
0000000000000000000000b3043c79c2e84cea7e4344ed7b549c91d000802d2e
0000000000000000000000b593467ce4246d4855dcf4d5222a54184e6fa6df96
0000000000000000000000b8c09dd61797ab1f7da1ab0159b2401354f23ccb25
0000000000000000000000ba72a3d45f86691ecd753cd76e9f5fe76d6aa0016a
0000000000000000000000bb0ffadb199d2278f071cc6d419552c70d4333f0c5
0000000000000000000000bb5b432a764ad6c7acf677dcd99161abfdf68e698e
0000000000000000000000befb5a97a29ea51ab3c576ec3d119266522692b2b3
0000000000000000000000bffaeeea2df36a7ecbd0c5f4e25faa8a55d589f159
0000000000000000000000c324b021bb5d741b28a78422282d18aa585c66e8e6
0000000000000000000000c64394ec858f9b0e15c386e8de28d5662ce8d803a8
0000000000000000000000c76c58ebac180989673fd6d237b40e66ed5c976ec3
0000000000000000000000c87731a1d688f3671d44ef862fe0ee2e74e1a845df
0000000000000000000000c919845e3367f5963e22cc850b354334b4fd703b37
0000000000000000000000c9258156bc997e1682a4eebee7d79e20d2e081775e
0000000000000000000000ce3e3d62bb5575c1dccfca1ab635412b2c7818b3b8
0000000000000000000000d0dc5c7e6b5de835f33170326b1df3c963d8d8bdb5
0000000000000000000000d3be4f881d0940292671ffa5c2095bc019283aec63
0000000000000000000000d3d08a1ebdc54f4aa79d148f8f5b4b1d2445ad2ecb
0000000000000000000000db2867af8040293a4a38db547883a053e0852d85f3
0000000000000000000000dfeee5b2a66cfa09a0daf3ecf641c45ca54f8cf9db
0000000000000000000000e01e08da62547d48615684ec70bdeb2e185f3dd012
0000000000000000000000e08adbe3f65aede63ab05e71be4948065ba4c0590b
0000000000000000000000e485cca75b9e9a48a6b532d21582ebfb2ebd87470a
0000000000000000000000e4f4e1ebe93f66e36622b3c72c76b090afbdb94c34
0000000000000000000000eb502db6b128d84c1f65943d55b31dc17871528ff9
0000000000000000000000f3c07c18949f337fd5dafc908d3b72bd55684b08d2
0000000000000000000000f4785d6f53ad5adccb7e4cfe31f4b207cf3b5b6329
0000000000000000000000f49bbadfa72df245095ee84c5ffb5d8eaa6625d335
0000000000000000000000f5fbf360acbc188ee6d6b8ad89e4b413d4d255c16d
0000000000000000000000f7d5945585ece049d8d82bcadd396bbc101f3c8b77
0000000000000000000000f9794a504f24ef5a8376bd71999f5c1be0cb030178
0000000000000000000000fa42dc4b10b4d4a505dca5e5f3c5bd7f0d77f71f08
0000000000000000000000fbcdecde38ecaf99cc5edaaf202f84a7cd813a3488
0000000000000000000000ff6bab98b41622e952e2134a522c306850f2708492
000000000000000000000101446bd06c8510033c1b6b87775b9a6936fd486d84
000000000000000000000101903ffbd533942d68cfefb0b8559f7d8e1358c502
000000000000000000000103b3ce7c49083c6a2532e0725dfa3f332f4d474fec
00000000000000000000010959f66e4dce3ebd3339d9fdb6d93fdb3bdb3402d9