interessante, a parte che non riesco a capire che razza di notazione sarebbe questa:
[0x7e00,0x7e00,0x7e00]
[0x7e01,acd4,2dd2]
Anch'io non l'ho mai vista, mi sembra solo un modo di suddividere un numero molto grande in gruppi di 4 cifre a partire da destra per leggere meglio il numero (un po' come si fa in notazione decimale con il punto). In Python con le quadre si indicano le liste.
Io ho trovato interessante il fatto che all'inizio satoshi con l'espressione "catena più lunga" intendesse proprio "con più blocchi", e solo in un secondo momento si è passati al concetto attuale di "catena con più lavoro"
Un altro fatto interessante è che il concetto base è quello di target, non di difficulty.
Nell'header di ogni blocco c'è infatti solo il campo per il target (non per la difficulty, nè per il chainwork) come si può vedere dal
codice sorgente di Core :
class CBlockHeader
{
public:
// header
int32_t nVersion;
uint256 hashPrevBlock;
uint256 hashMerkleRoot;
uint32_t nTime;
uint32_t nBits; <-- TARGET
uint32_t nNonce;
gli altri valori (difficulty e chainwork) si ricavano dal target, che costituisce quindi l'elemento fondamentale della pow.
Il target del primo blocco è "1d00ffff" e corrisponde al valore massimo che era accettabile per i primi blocchi:
target =
0x00000000ffff0000000000000000000000000000000000000000000000000000
invece il valore massimo per un numero rappresentabile con 256 bit -> 2**256 - 1 =
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
Quindi l'hash dell'header di ciascun blocco della blockchain deve avere almeno 8 zeri iniziali **.
Il valore più alto tra gli hash presenti nella blockchain è 00000000fff9e01287736bee2fecdd88ae31b5602858c5273d43351cfadecd58 (blocco numero 32009), molto vicino al valore massimo del target iniziale. Dal blocco numero 32256 la difficoltà è aumentata (e quindi il target si è abbassato). Da notare che l'hash del primo blocco ha in realtà ben 10 zeri anzichè i 6 minimi necessari: 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
Se invece vogliamo stimare quale dovrebbe essere il valore più basso tra gli hash presenti in blockchain, una stima attendibile dovrebbe essere:
numero di tutti i possibili hash / numero tentativi effettuati finora(chainwork) =
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff / 00000000000000000000000000000000000000000262adde7b8bef7777dd191c =
00000000000000000000006b510b511d47c84885b242d50f324021701d5d4b36
che è abbastanza vicino (è più della metà) del minimo valore realmente trovato finora:
0000000000000000000000ab789f6d71d9642ae3f697975ccd00afcb98fe6bd2
nel blocco 515910.
Ora per difficoltà si intende il numero medio di tentativi necessari per colpire il target.
Se per esempio ho 100 valori possibili (da 0 a 99) e sono interessato solo ad ottenere il valore 0, in media ogni 100 tentativi otterrò 0. Si dice allora che la difficoltà è 100. Se invece mi basta ottenere un numero minore o uguale a 19, poichè ogni 5 tentativi in media otterrò uno dei venti valori accettabili, si dice che la difficoltà è 5. Più grande è il target (si può immaginare come un bersaglio) minore è la difficoltà (intesa come numero di tentativi) di colpirlo. Di fatto è semplicemente il reciproco della probabilità di soddisfare il target ad ogni tentativo. E' così ad esempio che software tipo vanitygen stimano la difficoltà di trovare un indirizzo con un certo prefisso (che formalmente è lo stesso tipo di problema di quello che devono risolvere i miner).
Quindi di per sè la difficoltà altro non è che il lavoro necessario in media per minare un blocco, ed è uguale a:
numero di tutti i possibili hash / numero valori accettabili per il target -> 2^256 / (target + 1)
come si può ben vedere da
quiarith_uint256 GetBlockProof(const CBlockIndex& block)
{
arith_uint256 bnTarget;
bool fNegative;
bool fOverflow;
bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow);
if (fNegative || fOverflow || bnTarget == 0)
return 0;
// We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256
// as it's too large for an arith_uint256. However, as 2**256 is at least as large
// as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1,
// or ~bnTarget / (bnTarget+1) + 1.
return (~bnTarget / (bnTarget + 1)) + 1;
}
questo è il contributo che sommato su tutti i blocchi da il valore del parametro "chainwork"
NOTA 1:
Se il target fosse tutto lo spazio, allora la difficoltà di per sè dovrebbe essere 1 (basterebbe un tentativo per soddisfarlo). Ma nel caso di bitcoin non aveva senso iniziare con un blocco che fosse minabile con qualsiasi hash (si sarebbero trovati troppi blocchi in pochi istanti **) quindi si è deciso di partire da un target di 0x00000000ffff0000000000000000000000000000000000000000000000000000, che corrisponde a una difficulty pari a :
dimensione(spazio di tutti i possibili hash) / dimensione (target) =
0x10000000000000000000000000000000000000000000000000000000000000000 / 0x00000000ffff0000000000000000000000000000000000000000000000000001 =
4.295.032.833
I casi possibili sono 4 milioni e rotti volte i casi accettabili, quindi la difficoltà iniziale prevedeva di dover eseguire in media 4 milioni di hash per poter minare un blocco.
A quel punto si è fissato questa difficoltà come difficoltà base, punto di riferimento, quindi quando si dice relativamente alla blockchain "difficoltà 1" si intende "4.295.032.833 tentativi", quando si dice, come nel blocco del post precedente, "difficoltà 5.178.671.069.072,251", si intende 5 mila miliardi di volte la difficoltà iniziale, e cioè "5.178.671.069.072 * 4.295.032.833 = 22.242.562.272.971.450.840.976" (ho tralasciato i decimali), ovvero oggi ci vogliono in media 22 * 10^21 (circa 2^74) tentativi per minare un blocco (inoltre 22.242.562.272.971.450.840.976 / 600 secondi = 37 EH/sec)
**NOTA 2
Usando la regtest, si possono ottenere molti blocchi con hash qualsiasi (difficoltà 1 nel vero senso della parola):
$ bitcoind -regtest
$ bitcoin-cli -regtest generate 10
[
"2c40f580288fb80446d367cba7bdcf65e1e2f286c4e035c180d7de7e96341853",
"5e8449f73b697c7f27f2a6c8e82d4ca533459f3f7c804598b971c23be920f920",
"1427aa50038a67ef9b660af10cff1a3cee1c60d541b5da368b4c1a735274001d",
"043ba499f8e331a572be9ac6f0401d3283fa86fd0b26c99b06aaffb43680e2d5",
"18326cda138a975cd8e926f47bc33cd66253387531155a1425d9df3058548477",
"643e6394a06caf557e3e72a94d2f52ffd6df2e3f39c8c0909b3e65cc941b245a",
"2a487b5a7ca93b4b3e08befc47c6ae885c3e678adcc033706d184bc0075fa577",
"3c18e578b6baa69819ea782c376723806c1d968e2aa4d78a5bfcb0b48798c75a",
"301c54360b300ce46a46e31ae3f9d9e2486e617f04889c06fb7a3ad283fb6554",
"4883d47e84e2b82a3994c80252021f36371b64227cd5093ec3556c28a599850f"
]
come si può vedere ho generato 10 blocchi (in un attimo) con hash qualsiasi, infatti il lavoro per minare ciascun blocco è stato praticamente nullo:
./bitcoin-cli -regtest getblockheader 2c40f580288fb80446d367cba7bdcf65e1e2f286c4e035c180d7de7e96341853
{
"hash": "2c40f580288fb80446d367cba7bdcf65e1e2f286c4e035c180d7de7e96341853",
"confirmations": 10,
"height": 1,
"version": 536870912,
"versionHex": "20000000",
"merkleroot": "f9706f3bc9fb2802b5af2efe431eec53c3d5767352137e16d052c07d6c72303e",
"time": 1532026224,
"mediantime": 1532026224,
"nonce": 6,
"bits": "207fffff",
"difficulty": 4.656542373906925e-10,
"chainwork": "0000000000000000000000000000000000000000000000000000000000000004",
"previousblockhash": "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206",
"nextblockhash": "5e8449f73b697c7f27f2a6c8e82d4ca533459f3f7c804598b971c23be920f920"
}