Aller au contenu
buybitcoinsmart

Glossaire / Référence pour développeurs

CompactSize

Aussi appelé entier de longueur variable, Compact size unsigned integer, VarInt.

Qu'est-ce que CompactSize ?
CompactSize est l'entier de longueur variable que le bitcoin utilise pour préfixer les compteurs et les longueurs dans les données sérialisées : un octet pour les valeurs inférieures à 253 et jusqu'à neuf pour les autres.

Les formats binaires de Bitcoin ne portent aucun nom de champ : un analyseur doit donc savoir combien d'entrées suivent et quelle est la longueur de chaque script. CompactSize répond en aussi peu qu'un octet : de 0 à 252, c'est cet octet seul, et les valeurs supérieures prennent un marqueur plus deux, quatre ou huit octets supplémentaires. Chaque paiement que vous envoyez en contient au moins quatre.

Comment cela fonctionne

CompactSize lit son propre premier octet pour décider de la place qui lui reste.

Un premier octet inférieur à 0xfd est la valeur elle-même : les compteurs de 0 à 252 tiennent donc sur un octet et rien d'autre. Un premier octet de 0xfd signifie que la valeur se trouve dans les deux octets suivants, 0xfe dans les quatre suivants et 0xff dans les huit suivants. Tous ces nombres suivants sont en little endian. L'encodage le plus long possible fait neuf octets et peut exprimer une valeur supérieure à 18 trillions, ce dont aucune structure réelle n'a besoin, loin de là.

Les encodages doivent être minimaux. Écrire le nombre 5 sous la forme 0xfd 0x05 0x00 est arithmétiquement identique à écrire 0x05, et Bitcoin Core le refuse en levant une erreur non canonique pendant la désérialisation. Sans cette règle, la même transaction pourrait s'écrire de plusieurs façons, chacune avec un identifiant différent, ce qui pose un problème de malléabilité et non de simple propreté.

Il existe un plafond pratique bien inférieur au plafond arithmétique. Bitcoin Core refuse d'allouer pour tout objet désérialisé qui se déclare plus grand que 0x02000000 octets, soit environ 33,5 mégaoctets, et le protocole pair à pair limite séparément un message à 4 000 000 octets. Un pair hostile ne peut donc pas faire réserver des gigaoctets de mémoire à votre nœud en annonçant une transaction avec un trillion d'entrées.

Un piège de vocabulaire mérite d'être signalé. La documentation du réseau appelle cette structure un var_int, les bibliothèques de portefeuille l'appellent généralement un VarInt, et le code source de Bitcoin Core lui-même utilise le nom VarInt pour un encodage complètement différent et sans rapport, qui n'apparaît que dans ses fichiers de base de données et de retour en arrière. En lisant du code, vérifiez duquel des deux il s'agit.

Où vous le rencontrez

CompactSize est la structure la plus fréquemment rencontrée dans le bitcoin qui ne porte aucun nom visible pour l'utilisateur.

Dans une transaction brute, elle apparaît immédiatement après les quatre octets de version, ou après le marqueur et le drapeau segwit lorsqu'ils sont présents, et contient le nombre d'entrées. Elle revient avant chaque script pour en donner la longueur, puis avant le nombre de sorties. Dans un bloc sérialisé, elle porte le nombre de transactions. Dans le protocole pair à pair, elle ouvre la charge utile des messages inv, getdata, addr et headers.

Le message headers montre l'encodage sous sa forme la plus étrange. Chaque en-tête de 80 octets est suivi d'un compteur de transactions CompactSize valant zéro : une entrée occupe donc 81 octets au lieu de 80, et un lot complet de 2 000 en-têtes représente 162 000 octets sur le réseau. Le compteur est toujours zéro parce qu'un message headers ne transporte jamais de transactions. Le champ existe pour que le même code d'analyse puisse lire un en-tête, qu'un corps de bloc le suive ou non.

Si vous décodez une transaction brute à la main et que les champs cessent d'avoir un sens en cours de route, un CompactSize mal lu en est presque toujours la cause. Consommez un octet de moins et tout ce qui suit est décalé.

Questions fréquentes

Pourquoi le bitcoin utilise-t-il un entier de longueur variable ?

Parce que presque tous les compteurs du bitcoin sont petits. Une transaction comporte généralement une ou deux entrées, et consacrer quatre ou huit octets à le dire pour chaque champ de chaque transaction jamais créée aurait ajouté un poids permanent considérable pour rien.

CompactSize est-il identique au VarInt de Bitcoin Core ?

Non, malgré le surnom partagé. CompactSize est le format réseau et disque décrit ici, tandis que la classe nommée VarInt dans Bitcoin Core est un encodage compact distinct, utilisé uniquement dans ses propres fichiers de base de données et de retour en arrière.

Termes associés

Plus de termes : Référence pour développeurs

Lire cette page en anglais