Les jeux de données
Un jeu de données (dataset) est le moyen le plus simple de placer des données sur ZooBC : un petit enregistrement, un nom de propriété et sa valeur, qu’un compte écrit sous un compte, généralement le sien. Chaque nœud conserve la ligne comme partie de l’état de la chaîne, si bien que n’importe quelle application peut la lire via l’API de n’importe quel nœud. Les applications s’en servent pour des profils, des réglages, des annonces de version, des factures et des icônes de jetons.
Une ligne
Une transaction SetupAccountDataset (type 3) écrit une ligne, indexée par trois éléments :
- l’auteur (setter), le compte qui envoie la transaction ;
- le destinataire, le compte sous lequel la ligne est rangée, généralement l’auteur lui-même (un destinataire vide est aussi une clé valide) ;
- la propriété, un nom de 1 à 256 octets, jamais vide.
La valeur contient jusqu’à 4 096 octets, dans un corps de transaction d’au plus 65 536 octets. Les lignes sont versionnées : écrire de nouveau la même clé remplace la ligne en vigueur, et RemoveAccountDataset (type 259) rend une ligne inactive.
Une ligne est publique : n’importe qui peut la lire, un jeu de données n’est donc pas l’endroit où mettre un secret. Ce n’est pas non plus un moyen de conserver un gros fichier. Les petits fichiers deviennent des fichiers DFS, les gros vont dans le stockage décentralisé.
L’importance de l’auteur
N’importe quel compte peut écrire une ligne sous n’importe quel destinataire, sans que celui-ci soit consulté, de même que n’importe qui peut envoyer un paiement à n’importe quelle adresse. Une ligne est donc une déclaration faite par son auteur au sujet du destinataire. La chaîne prouve qui l’a faite et quand ; elle ne peut pas savoir si la déclaration est vraie.
Un nœud liste les lignes d’un compte à GET /api/v1/accounts/<address>/datasets, avec un filtre facultatif ?property=<prefix>. La liste renvoie chaque ligne dont l’adresse est l’auteur ou le destinataire, chacune étiquetée avec son role : auteur, destinataire ou les deux. Une application qui trouve « verified = yes » sous un utilisateur ne doit l’accepter que si l’auteur est le compte auquel elle fait confiance, par exemple son propre compte de vérification, et doit répondre « non vérifié » quand aucune ligne de ce type n’existe (données de la chaîne sont des entrées non fiables).
Objets et propriétaires
Chaque ligne appartient à un objet de jeu de données, nommé par le hachage de la transaction qui l’a créé. L’objet a un propriétaire (au départ son créateur), un propriétaire en attente et un mode de gestion.
- La cession se fait en deux étapes. Le propriétaire envoie TransferDataset (type 42) en désignant le nouveau propriétaire, et la chaîne n’enregistre qu’un propriétaire en attente. La cession s’achève quand ce compte envoie AcceptDataset (type 44). Un AcceptDataset venant de quelqu’un d’autre, ou visant un objet sans propriétaire en attente, est une opération nulle payante : les frais sont prélevés et rien ne change. Ainsi, personne ne peut imposer un objet, et le loyer qui l’accompagne, à un compte qui ne l’a pas demandé, et l’ancien propriétaire reste propriétaire tant que le nouveau n’a pas accepté.
- Suppression. DeleteDataset (type 45), envoyé par le propriétaire, désactive toutes les lignes de l’objet, et le dépôt de l’objet est versé au fonds de longévité.
- Politique. SetDatasetPolicy (type 43) enregistre sur l’objet un mode de gestion (propriétaire seul, liste blanche, liste noire ou ouvert) et une liste d’accès, mais aucune règle de consensus ne les lit, si bien qu’ils ne restreignent rien.
Chaque objet possède aussi une adresse de dépôt : un compte de type 10, noté ZBS_…, dont les octets sont 0A000000 suivis de l’identifiant de l’objet. N’importe qui peut l’alimenter par un simple SendZBC, si bien qu’un groupe d’utilisateurs peut maintenir ensemble un enregistrement partagé en vie. C’est un compte approvisionné ordinaire, il paie donc aussi le loyer de compte. GET /api/v1/dataset-address/<hash or ZBS_ address> l’affiche.
Loyer
Une fois par période de facturation, soit 172 800 blocs (environ 30 jours) sur le mainnet, la chaîne facture à chaque objet les octets de ses lignes actives :
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
Le prix de départ est de 5 000 000 unités atomiques (0,05 ZBC) par Mio, et le multiplicateur de stockage vaut 1,0 au départ. Un Mio complet de lignes paie exactement 0,05 ZBC par période. Une ligne dont la propriété fait 14 octets et la valeur 300 octets, soit 314 octets en tout, paie 1 498 unités : 314 × 5 000 000 ÷ 1 048 576 donne 1 497,27, et chaque étape du calcul est arrondie vers le haut.
Le loyer est prélevé d’abord sur le dépôt, puis sur le solde du propriétaire. Si les deux ensemble ne peuvent pas payer, toutes les lignes de l’objet sont désactivées et tout dépôt restant va au fonds de longévité. Le destinataire n’est jamais facturé. Tout le loyer de jeu de données est crédité au fonds de longévité, qui verse aux nœuds une part à chaque bloc ; le ZBC n’est jamais brûlé.
La période de facturation suit l’intervalle d’instantané. Le prix est voté par les sièges et peut descendre jusqu’à une unité atomique ; il évolue une fois par cycle d’instantané, dans certaines limites, vers la moyenne des votes des sièges comptés (votes de prix).
Préfixes réservés
Quelques préfixes de propriété sont réservés, et la chaîne vérifie leurs lignes avant de les accepter. Le test compare les octets bruts au début de la propriété, donc invoice: n’est pas inv:.
| Préfixe | Règle |
|---|---|
dfs: et dfs:dir: | écrits uniquement par les trois types de transaction DFS ; une SetupAccountDataset à cet endroit est refusée (fichiers sur la chaîne (DFS)) |
tokenicon: | une image PNG ou WebP qui déclare une largeur et une hauteur de 1 à 512 pixels, longue de 16 à 4 096 octets |
inv: | un objet JSON ne contenant de nombre négatif nulle part, de sorte qu’une facture ne peut pas porter un montant négatif ; appliqué dès le bloc 0 |
L’icône d’un jeton vit donc sur la chaîne elle-même, dans la ligne, et non derrière une URL. Aucune de ces vérifications ne fait intervenir la signature de qui que ce soit : chaque nœud applique la même règle.