Publication
Partagez vos connaissances.

L'encodage BCS dans Sui : qu'est-ce que c'est et pourquoi c'est important
Si vous vous basez sur Sui ou que vous bricolez avec Move, vous avez probablement entendu le terme BCS circuler. C'est l'abréviation de la machine de formatage de sérialisation canonique binaire conçue à l'origine pour la blockchain Diem, et qui constitue désormais la pierre angulaire des écosystèmes basés sur Move tels que Sui, Aptos, Starcoin et 0L.
Alors oui, tu ferais mieux de t'y mettre à l'aise si tu veux vraiment construire dans cet espace.
Qu'est-ce que BCS ?
La sérialisation canonique binaire (BCS) est un format utilisé pour sérialiser (encoder) et désérialiser (décoder) des données structurées en octets.
Vous le verrez utilisé lorsque :
- Encodage des transactions avant de les signer.
- Émettre ou analyser des événements depuis la blockchain.
- Interagir avec les contrats intelligents Move off-chain via JavaScript.
Mais BCS n'inclut pas d'informations de type dans les octets. Cela signifie que vous devez connaître la structure à l'avance lors du décodage, contrairement aux formats tels que JSON ou Protocol Buffers, qui sont plus autodescriptifs.
Principales caractéristiques de BCS
Aucune métadonnée de type
La sortie sérialisée ne contient aucune indication sur les types de champs. Vous devez savoir à quoi vous avez affaire lorsque vous décodez.
Sérialisation dépendante de l'ordre
Les structures sont codées dans l'ordre exact de leurs champs. Modifiez l'ordre et votre désérialisation s'interrompt. C'est pourquoi les fonctions peel_* de Move doivent correspondre à la disposition 1:1. de la structure.
Type générique
Dans une structure comme :
struct BCSObject<T> has drop, copy {
id: ID,
owner: address,
meta: Metadata,
generic: T
}
Vous ne pouvez désérialiser de manière fiable que jusqu'au champ méta. Les types génériques perturbent l'analyse BCS, alors mettez-les toujours en dernier si vous voulez que vos données soient décodées en toute sécurité.
Utilisation de BCS en JavaScript
Grâce à la bibliothèque @mysten /bcs, vous pouvez travailler avec BCS dans JS comme un pro.
npm i @mysten/bcs
et exemple de base :
import { BCS, getSuiMoveConfig } from "@mysten/bcs";
const bcs = new BCS(getSuiMoveConfig());
const ser = bcs.ser(BCS.U16, 10);
console.log(ser.toBytes()); // [0x0a, 0x00]
const des = bcs.de(BCS.U16, ser.toBytes());
console.log(des); // 10
Vous pouvez également sérialiser des vecteurs et des chaînes :
bcs.ser("vector<u8>", [1, 2, 3, 4]); // 04 01 02 03 04
bcs.ser(BCS.STRING, "test string"); // 0b7465737420737472696e67
Enregistrement de types personnalisés
Supposons que vous ayez les structures Move suivantes :
struct Metadata has drop, copy {
name: std::ascii::String
}
struct BCSObject has drop, copy {
id: ID,
owner: address,
meta: Metadata
}
Vous pouvez les enregistrer comme ceci dans JS :
bcs.registerStructType("Metadata", {
name: BCS.STRING,
});
bcs.registerStructType("BCSObject", {
id: BCS.ADDRESS,
owner: BCS.ADDRESS,
meta: "Metadata",
});
Exemple de sérialisation et de désérialisation
Sérialisation JavaScript :
const bytes = bcs
.ser("BCSObject", {
id: "0x0000000000000000000000000000000000000005",
owner: "0x000000000000000000000000000000000000000a",
meta: { name: "aaa" }
})
.toString("hex");
console.log("Hex:", bytes);
La sortie peut être :
0x0000000000000000000000000000000000000005000000000000000000000000000000000000000a03616161
Cela peut désormais être transféré dans un contrat Move ou même testé manuellement dans Sui CLI.
Le BCS peut sembler de bas niveau et riche en octets, mais une fois que vous aurez compris comment il code les données, vous pourrez mieux comprendre comment fonctionnent réellement les contrats intelligents Move et comment relier en toute sécurité les systèmes hors chaîne on-chain ↔.
Et si vous déboguez des octets BCS sur Sui Explorer (comme celui ci-dessous) :
Encodage BCS La sérialisation canonique binaire, ou BCS, est un format de sérialisation développé dans le contexte de la blockchain Diem et est désormais largement utilisé dans la plupart des blockchains basées sur Move (Sui, Starcoin, Aptos, 0L). Le BCS n'est pas seulement utilisé dans la machine virtuelle Move, mais également dans le codage des transactions et des événements, comme la sérialisation des transactions avant la signature ou l'analyse des données d'événements.
Il est essentiel de connaître le fonctionnement de BCS si vous souhaitez comprendre le fonctionnement de Move à un niveau plus approfondi et devenir un expert de Move. Allons-y.
Spécifications et propriétés du BCS Il convient de garder à l'esprit certaines propriétés de haut niveau du codage BCS au cours de la suite de la leçon :
Le BCS est un format de sérialisation de données dans lequel les octets de sortie résultants ne contiennent aucune information de type ; de ce fait, la partie recevant les octets codés devra savoir comment désérialiser les données
Il n'y a pas de structures dans BCS (puisqu'il n'y a pas de types) ; la structure définit simplement l'ordre dans lequel les champs sont sérialisés
Les types de wrapper sont ignorés, donc OuterType et UnnestedType auront la même représentation BCS :
structure OuterType { propriétaire : InnerType } structure innerType { adresse : adresse } structure UnnestedType { adresse : adresse } Les types contenant les champs de type générique peuvent être analysés jusqu'au premier champ de type générique. Il est donc recommandé de placer le ou les champs de type générique en dernier s'il s'agit d'un type personnalisé qui sera utilisé/supprimé.
la structure BCSobject
Les types primitifs tels que les entiers non signés sont codés au format Little Endian
Le vecteur est sérialisé sous la forme d'une longueur ULEB128 (avec une longueur maximale allant jusqu'à u32) suivie du contenu du vecteur.
La spécification BCS complète se trouve dans le référentiel BCS.
Utilisation de la bibliothèque JavaScript @mysten /bcs Installation La bibliothèque que vous devrez installer pour cette partie est la bibliothèque @mysten /bcs. Vous pouvez l'installer en saisissant dans le répertoire racine d'un projet de nœud :
npm dans @mysten /bcs Exemple de base Utilisons d'abord la bibliothèque JavaScript pour sérialiser et désérialiser certains types de données simples :
import {BCS, GetSuiMoveConfig} depuis « @mysten /bcs » ;
//initialise le sérialiseur avec les configurations Sui Move par défaut const bcs = nouveau BCS (getSuiMoveConfig ()) ;
//Définition de certains types de données de test entier constant = 10 ; tableau const = [1, 2, 3, 4] ; const string = « chaîne de test »
//utilise bcs.ser () pour sérialiser les données
const ser_integer = bcs.ser (BCS.U16, entier) ;
//utilisation de bcs.de () pour désérialiser les données
const de_integer = bcs.de (BCS.U16, SER_Integer.toBytes ()) ;
const de_array = bcs.de (
Examinons de plus près les champs sérialisés et désérialisés :
Les entiers sont des hexadécimaux de petite taille
0a00 10
le premier élément d'un vecteur indique la longueur totale,
alors c'est juste les éléments du vecteur
0401020304 1, 2, 3, 4
les chaînes ne sont que des vecteurs de u8, le premier élément étant égal à la longueur de la chaîne
0b7465737420737472696e67 chaîne de test Type d'enregistrement Nous pouvons enregistrer les types personnalisés sur lesquels nous allons travailler en utilisant la syntaxe suivante :
import {BCS, GetSuiMoveConfig} depuis « @mysten /bcs » ; const bcs = nouveau BCS (getSuiMoveConfig ()) ;
//Enregistrement du type de métadonnées BCS.RegisterStructType (« Métadonnées », { nom : BCS.STRING, }) ;
//Idem pour l'objet principal que nous avons l'intention de lire BCS.RegisterStructType (« BCSobject », { //BCS.ADDRESS est utilisé pour les types d'ID ainsi que pour les types d'adresses identifiant : BCS.ADDRESS, propriétaire : BCS.ADDRESS, meta : « Métadonnées », }) ; Utilisation de BCS dans Sui Smart Contracts Continuons notre exemple ci-dessus avec les structures.
Définition de la structure Nous commençons par les définitions de structure correspondantes dans le contrat Sui Move.
{ //.. struct Les métadonnées ont été supprimées, copiez { nom : std : :ascii : :String }
la structure BCSobject a été déposée, copiez { identifiant : identifiant, propriétaire : adresse, méta : Métadonnées } //.. } Désérialisation Écrivons maintenant la fonction permettant de désérialiser un objet dans un contrat Sui.
//Initialise l'instance bcs bytes let bcs = bcs : :new (bcs_bytes) ;
//Utilise peel_*
des fonctions pour extraire les valeurs des octets sérialisés.
//L'ordre doit être le même que celui que nous avons utilisé pour la sérialisation !
let (identifiant, propriétaire, méta) = (
bcs : :peel_address (&mut bcs), bcs : :peel_address (&mut bcs), bcs : :peel_vec_u8 (&mut bcs)
) ;
//Compresse une structure BCSobject avec les résultats de la sérialisation
BCSobject {id : object : :id_from_address (id), propriétaire, méta : Metadata {name : std : :ascii : :string (meta)}}}
Les différentes méthodes peel_* du module Sui Frame bcs sont utilisées pour « extraire » chaque champ individuel des octets sérialisés BCS. Notez que l'ordre dans lequel nous décorons les champs doit être exactement le même que celui des champs dans la définition de la structure.
Quiz : Pourquoi les résultats des deux premiers appels peel_address sur le même objet bcs ne sont-ils pas les mêmes ?
Notez également comment nous convertissons les types d'adresse en identifiant et de vecteur en <8>std : :ascii : :string avec des fonctions d'assistance.
Quiz : Que se passerait-il si BSCobject avait un type d'UID au lieu d'un type d'ID ?
Exemple Ser/De complet Trouvez l'intégralité des exemples de codes JavaScript et Sui Move dans le dossier example_projects.
Tout d'abord, nous sérialisons un objet de test à l'aide du programme JavaScript :
//Nous construisons un objet de test à sérialiser, notez que nous pouvons spécifier le format de la sortie en hexadécimal let _bytes = bcs .ser (« BCSobject », { identifiant : « 0x0000000000000000000000000000000000000000000000000005", propriétaire : « 0x000000000000000000000000000000000000000000000000000a », meta : {nom : « aaa"} }) .toString (« hexadécimal ») ; Nous voulons que la sortie du graveur BCS soit au format hexadécimal cette fois, ce qui peut être spécifié comme ci-dessus.
Fixez la chaîne hexadécimale du résultat de la sérialisation avec le préfixe 0x et exportez-la vers une variable d'environnement :
export Object_HexString=0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000A03616161 Nous pouvons maintenant soit exécuter les tests unitaires Move associés pour vérifier leur exactitude :
test de mouvement de costume Vous devriez voir ceci dans la console :
BÂTIMENT bcs_move Exécution de tests unitaires avec Move [PASS] 0x0 : :bcs_object : :test_désérialisation Résultat du test : OK. Nombre total de tests : 1 ; réussis : 1 ; échec : 0 Ou nous pouvons publier le module (et exporter le PACKAGE_ID) et appeler la méthode emit_object en utilisant la chaîne hexagonale sérialisée BCS ci-dessus :
appel client sui --function emit_object --module bcs_object --package $PACKAGE_ID --args $OBJECT_HEXSTRING Nous pouvons ensuite consulter l'onglet Événements de la transaction sur le Sui Explorer pour voir que nous avons émis le BCSObject correctement désérialisé :
- Sui
- SDKs and Developer Tools
Qu'est-ce que little-endian et big-endian ?
Sui is a Layer 1 protocol blockchain designed as the first internet-scale programmable blockchain platform.
Gagne ta part de 1000 Sui
Gagne des points de réputation et obtiens des récompenses pour avoir aidé la communauté Sui à se développer.

- ... SUIBigSneh+1396
- ... SUISuiLover+1333
- ... SUI0xduckmove+1207
- ... SUIThorfin+1202
- ... SUIOwen+970
- ... SUIharry phan+847
- ... SUItheking+742
- Pourquoi BCS exige-t-il un ordre de champs exact pour la désérialisation alors que les structures Move ont des champs nommés ?53
- « Erreurs de vérification de sources multiples » dans les publications du module Sui Move - Résolution automatique des erreurs43
- Échec de la transaction Sui : objets réservés pour une autre transaction25
- Comment les contraintes de capacité interagissent-elles avec les champs dynamiques dans des collections hétérogènes ?05