La catena spine
Ogni nodo ZooBC mantiene due catene. La catena principale produce un blocco ogni 15 secondi e contiene le transazioni. Accanto a essa corre la spine: un blocco al giorno su mainnet, senza alcuna transazione. Un blocco spine registra ciò di cui il registro nel suo insieme si fa garante, cioè un checkpoint della catena principale, le chiavi dei nodi entrate o uscite e i manifest degli snapshot più recenti, e richiede le firme di due terzi dei seggi. Questo fa della spine l'ancora della finalità e il punto di partenza di ogni nuovo nodo.
Che cosa contiene un blocco spine
- Un checkpoint. Ogni blocco spine indica un blocco di riferimento della catena principale abbastanza profondo da essere consolidato: 760 blocchi (3 ore e 10 minuti) sotto la punta della catena principale al momento in cui il blocco spine viene prodotto, e mai più in basso del riferimento del blocco spine precedente. Ne copia la radice di Merkle, e il suo hash del contenuto si impegna sull'hash e sulla difficoltà cumulativa del blocco di riferimento stesso, quindi il checkpoint fissa un blocco esatto, non solo un'altezza.
- Cambi delle chiavi pubbliche. Le chiavi dei nodi aggiunte al registro o rimosse da esso dal blocco spine precedente.
- Manifest degli snapshot. Per ogni snapshot recente dello stato della catena principale: l'hash del file intero, l'hash di ogni porzione, l'altezza di riferimento, una scadenza e l'hash genesi della catena principale (vedi snapshot e fast sync).
La spine produce un blocco per spine_smithing_period: 86.400 secondi, uno al giorno, su mainnet e testnet, e 3.600 secondi, uno all'ora, su devnet, dove la profondità del checkpoint è di 80 blocchi (20 minuti).
Co-firmato da due terzi dei seggi
Un blocco spine contiene una firma aggregata: un conteggio di 4 byte seguito, per ogni firmatario, dalla sua chiave del nodo di 32 byte e dalla sua firma Ed25519 di 64 byte, tutte sugli stessi 204 byte di intestazione. L'hash del blocco è lo SHA3-256 dei byte di intestazione e dell'intero campo delle firme.
Il numero di firme richiesto è:
required = max(spine_min_signatures, ceil(n × 67 / 100))
dove n è la dimensione della lista dei firmatari. Con 11 seggi, 11 × 67 / 100 = 7,37, arrotondato per eccesso a 8. L'arrotondamento per eccesso è voluto: 7 sarebbe meno di due terzi di 11.
La spine conta ogni seggio della sua lista dei firmatari, sospeso o no. È l'unico conteggio dei due terzi in cui i seggi sospesi contano ancora, così un checkpoint parla sempre a nome di due terzi di tutti i seggi (vedi regole dei due terzi).
Se troppi seggi vengono a mancare e la spine si blocca, la soglia si allenta in un solo passo: dopo 3 periodi della spine senza alcun blocco spine memorizzato (3 giorni su mainnet), basta più della metà, 6 su 11. Nessuna delle due soglie può scendere sotto spine_min_signatures, che vale 5 su ogni catena. Richiedere tutte e 11 le firme permetterebbe a un solo seggio mancante di fermare la spine.
I firmatari verificano prima di firmare
Un seggio non firma mai alla cieca. Prima di co-firmare una proposta, ogni firmatario verifica che:
- i cambi di chiavi siano uguali ai cambi nel proprio registro sullo stesso intervallo;
- ogni manifest per la sua catena sia uguale al proprio snapshot, hash per hash; un firmatario senza lo snapshot si astiene;
- il blocco di riferimento sia abbastanza profondo e non torni indietro;
- non abbia già co-firmato un blocco diverso a quell'altezza della spine.
Quando un nodo memorizza un blocco spine, ne verifica di nuovo il contenuto, insieme all'estrazione del produttore e alla difficoltà del blocco.
Chi propone, e quando
Il produttore della spine viene estratto dalla lista dei firmatari: il firmatario all'indice LE64(SHA3-256(seed ‖ "spine" ‖ round)) mod n, dove il seed è il seed del blocco principale all'altezza di riferimento del blocco spine precedente, così ogni validatore può ripetere l'estrazione. Su mainnet un round della spine dura 100 secondi, la finestra di creazione è di 300 secondi e la tolleranza di 150 secondi; un firmatario rifiuta una proposta più vecchia della sua finestra di raccolta di 60 secondi. Un blocco spine che arriva prima del precedente più il periodo, meno la tolleranza, viene rifiutato.
I blocchi spine non sono mai vuoti. Tra spine in concorrenza vince quella con più firme. Un nodo pesa una spine concorrente prima di fare qualsiasi rollback, non fa mai rollback della propria spine sotto il pin della release e ripristina la propria spine se l'altra non riesce ad applicarsi.
A che cosa serve la spine
- Finalità. Nessun nodo riorganizza la catena principale sotto l'ultimo checkpoint della spine memorizzato (vedi finalità e rollback).
- Fast sync. Un nuovo nodo sincronizza per prima la spine: i suoi manifest dicono quale snapshot scaricare, e i suoi cambi di chiavi dicono di quali chiavi dei nodi fidarsi (vedi snapshot e fast sync).
- L'archivio. L'archiviazione decentralizzata, non ogni nodo, conserva ogni snapshot dal blocco zero, così chiunque può ripercorrere la spine fino a qualsiasi snapshot passato e ricostruire lo stato di quel momento (vedi archivio e la lettura del passato).
La spine è mantenuta da ogni nodo, non dalla Foundation, e su di essa non si scambia nulla.