Dataset
Un dataset è il modo più semplice per mettere dati su ZooBC: un piccolo record, il nome di una proprietà e il suo valore, che un account scrive sotto un account, di solito il proprio. Ogni nodo detiene la riga come parte dello stato della catena, quindi qualsiasi app può leggerla tramite l'API di qualsiasi nodo. Le app usano le righe per profili, impostazioni, avvisi di release, fatture e icone dei token.
Una riga
Una transazione SetupAccountDataset (tipo 3) scrive una riga, identificata da tre elementi:
- chi la imposta, l'account che invia la transazione;
- il destinatario, l'account sotto cui si trova la riga, di solito lo stesso account che la imposta (anche un destinatario vuoto è una chiave valida);
- la proprietà, un nome da 1 a 256 byte, mai vuoto.
Il valore contiene fino a 4.096 byte, all'interno di un corpo della transazione di al massimo 65.536 byte. Le righe sono versionate: scrivere di nuovo la stessa chiave sostituisce la riga attuale, e RemoveAccountDataset (tipo 259) rende una riga inattiva.
Una riga è pubblica: chiunque può leggerla, quindi un dataset non è il posto per un segreto. E non è nemmeno un modo per conservare un file grande. I file piccoli vanno nei file DFS, quelli grandi nel pool di archiviazione.
Conta chi l'ha scritta
Qualsiasi account può scrivere una riga sotto qualsiasi destinatario, e al destinatario non viene chiesto nulla, allo stesso modo in cui chiunque può inviare un pagamento a qualsiasi indirizzo. Una riga è quindi una dichiarazione fatta da chi la imposta a proposito del destinatario. La catena dimostra chi l'ha detto e quando; non può sapere se la dichiarazione è vera.
Un nodo elenca le righe di un account su GET /api/v1/accounts/<address>/datasets, con un filtro facoltativo ?property=<prefix>. L'elenco restituisce ogni riga in cui l'indirizzo è chi imposta o il destinatario, ciascuna etichettata con il suo role: setter, recipient o both. Un'app che trova «verified = yes» sotto un utente deve accettarlo solo quando chi ha impostato la riga è l'account di cui si fida, come il proprio account di verifica, e deve rispondere «non verificato» quando una riga del genere non esiste (dati della catena sono input non attendibile).
Oggetti e proprietari
Ogni riga appartiene a un oggetto dataset, indicato dall'hash della transazione che lo ha creato. L'oggetto ha un proprietario (all'inizio il suo creatore), un proprietario in attesa e una modalità di gestione.
- La cessione avviene in due passi. Il proprietario invia TransferDataset (tipo 42) indicando il nuovo proprietario, e la catena registra solo un proprietario in attesa. La cessione si completa quando quell'account invia AcceptDataset (tipo 44). Un AcceptDataset di chiunque altro, o per un oggetto senza proprietario in attesa, è una no-op pagata: la commissione viene addebitata e non cambia nulla. Così nessuno può scaricare un oggetto, e il canone che ne deriva, su un account che non l'ha chiesto, e il vecchio proprietario resta tale finché il nuovo non accetta.
- La cancellazione. DeleteDataset (tipo 45), inviato dal proprietario, disattiva ogni riga dell'oggetto, e il deposito dell'oggetto viene trasferito al pool di longevità.
- La politica. SetDatasetPolicy (tipo 43) memorizza sull'oggetto una modalità di gestione (solo il proprietario, whitelist, blacklist o aperta) e una lista di accesso, ma nessuna regola di consenso le legge, quindi non limitano nulla.
Ogni oggetto ha anche un indirizzo di deposito: un account di tipo 10, scritto ZBS_…, i cui byte sono 0A000000 seguiti dall'id dell'oggetto. Chiunque può finanziarlo con un semplice SendZBC, così un gruppo di utenti può tenere in vita insieme un record condiviso. È un normale account con fondi, quindi paga anche il canone degli account. GET /api/v1/dataset-address/<hash or ZBS_ address> lo mostra.
Canone
Una volta per periodo di fatturazione, 172.800 blocchi (circa 30 giorni) su mainnet, la catena addebita a ogni oggetto i byte delle sue righe attive:
bytes = sum of (property + value) over the object's active rows
rent = ceil(bytes × price per MiB ÷ 1,048,576), then × storage multiplier, rounded up
Il prezzo iniziale è di 5.000.000 di unità atomiche (0,05 ZBC) per MiB, e il moltiplicatore di archiviazione parte da 1,0. Un MiB intero di righe paga esattamente 0,05 ZBC per periodo. Una riga con una proprietà di 14 byte e un valore di 300 byte, 314 byte in tutto, paga 1.498 unità: 314 × 5.000.000 ÷ 1.048.576 fa 1.497,27, e ogni fase dell'addebito arrotonda per eccesso.
Il canone viene prelevato prima dal deposito, poi dal saldo del proprietario. Se insieme non riescono a pagare, ogni riga dell'oggetto viene disattivata e l'eventuale deposito rimasto va al pool di longevità. Al destinatario non viene mai addebitato nulla. Tutto il canone dei dataset viene accreditato al pool di longevità, che paga ai nodi una fetta in ogni blocco; ZBC non viene mai bruciato.
Il periodo di fatturazione segue l'intervallo degli snapshot. Il prezzo viene votato dai seggi e può scendere fino a un'unità atomica; si muove una volta per ciclo di snapshot, entro limiti, verso la media dei voti dei seggi conteggiati (voti sui prezzi).
Prefissi riservati
Alcuni prefissi di proprietà sono riservati, e la catena verifica le loro righe prima di accettarle. Il controllo confronta i byte grezzi all'inizio della proprietà, quindi invoice: non è inv:.
| Prefisso | Regola |
|---|---|
dfs: e dfs:dir: | scritti solo dai tre tipi di transazione DFS; un SetupAccountDataset lì viene rifiutato (file sulla catena (DFS)) |
tokenicon: | un'immagine PNG o WebP che dichiara larghezza e altezza da 1 a 512 pixel, lunga da 16 a 4.096 byte |
inv: | un oggetto JSON senza alcun numero negativo, così una fattura non può contenere un importo negativo; applicato dal blocco 0 |
L'icona di un token vive quindi sulla catena, dentro la riga, non dietro un URL. Nessuno di questi controlli coinvolge la firma di qualcuno: ogni nodo applica la stessa regola.