NOUVEAU : Helius acquiert Light Protocol
Le modèle de programmation de Solana
Blog/Fondamentaux

Le modèle de programmation de Solana : introduction au développement sur Solana

Developer Experience Engineer0xIchigo sur X0xIchigo sur LinkedIn0xIchigo sur GitHub
24 min de lecture

Quel est le sujet de cet article ?

L’approche de Solana en matière de calcul décentralisé repose sur un principe simple : chaque élément est stocké dans sa propre région mémoire, appelée compte. Solana fonctionne comme un magasin clé-valeur global dans lequel les clés publiques servent d’identifiants uniques pour les comptes correspondants. Les comptes constituent la colonne vertébrale de Solana, car ils stockent l’état ; ils contiennent aussi bien les programmes que les soldes de tokens. Les transactions servent à mettre à jour les comptes et à refléter les changements d’état.

Dans cet article, nous explorons les complexités de l’architecture de Solana. Nous commençons par une vue d’ensemble des clusters et du concept d’état, avant d’aborder le rôle des comptes et des programmes en tant que composants fondamentaux de Solana. Nous examinons ensuite comment les transactions permettent des interactions dynamiques entre les comptes et les programmes.

À la fin de cet article, vous comprendrez en profondeur le modèle de programmation de Solana. Vous connaîtrez l’architecture des clusters, le rôle crucial des comptes dans le stockage des données et le processus par lequel les transactions mettent à jour les données des comptes. Vous découvrirez également des fonctionnalités propres à Solana, comme son système de loyer et ses transactions versionnées.

Que sont les clusters Solana ?

Au cœur de l’architecture de Solana se trouvent les clusters, un ensemble de validateurs qui travaillent de concert pour traiter les transactions et maintenir un registre unique. Solana comporte plusieurs clusters distincts, chacun répondant à un objectif précis :

  • Localhost : un cluster de développement local disponible par défaut sur le port 8899. L’interface de ligne de commande Solana (CLI) comprend un validateur de test intégré, personnalisable selon les besoins de chaque développeur, sans nécessiter d’airdrops ni subir de limites de débit
  • Devnet : un environnement sandbox sans conséquences pour effectuer des tests et des expérimentations sur Solana
  • Testnet : un environnement dans lequel les principaux contributeurs de Solana testent de nouvelles mises à jour et fonctionnalités avant leur arrivée sur le mainnet. Il sert également d’environnement de test aux développeurs qui souhaitent réaliser des tests de performances
  • Mainnet Beta : le cluster actif et sans autorisation sur lequel ont lieu les transactions réelles. Il s’agit du « vrai » Solana, où utilisateurs, développeurs, détenteurs de tokens et validateurs interagissent chaque jour

Chaque cluster fonctionne indépendamment et n’a aucune connaissance des autres. Les transactions envoyées au mauvais cluster sont rejetées afin de garantir l’intégrité de chaque environnement opérationnel.

Imaginez les clusters comme un tas monolithique de données. En informatique, un tas désigne une région mémoire dans laquelle les données peuvent être stockées et modifiées dynamiquement. Il convient toutefois de noter que les clusters n’utilisent pas littéralement une structure de données en tas. Cette analogie est un outil conceptuel qui aide à comprendre que les clusters se composent de différentes régions mémoire pouvant être allouées et désallouées selon les besoins. Considérer les clusters comme un tas dynamique est essentiel pour comprendre comment les données sont gérées, consultées et sécurisées au sein du réseau.

Vous pouvez également voir ce tas monolithique de données comme une sorte d’entrepôt numérique. Les données y ressemblent à des boîtes placées sur des étagères, chacune dotée d’étiquettes uniques et soumise à des règles précises pour son déplacement et la modification de son contenu. Ce modèle garantit un système sécurisé et ordonné dans lequel seuls les déplacements ou changements autorisés sont permis.

Les smart contracts, appelés programmes sur Solana, disposent de leur propre partie de l’entrepôt, ou du tas, qu’ils peuvent gérer. Un programme peut lire n’importe quelle partie de cet entrepôt, mais il lui faut certaines autorisations pour modifier le contenu d’un espace qu’il ne possède pas. La seule action universellement autorisée consiste à transférer des lamports, la cryptomonnaie native de Solana, vers n’importe quel espace de l’entrepôt.

L’intégralité de l’état réside dans ce tas, y compris les programmes. Chaque région appartient à un programme qui la gère en conséquence. Les programmes, par exemple, appartiennent au BPFLoader, un programme chargé de charger, déployer et mettre à niveau les programmes on-chain. Ces régions mémoire, les boîtes de notre entrepôt numérique, sont appelées comptes.

Que sont les comptes ?

Sur Solana, tout est un compte. Considérez les comptes comme des conteneurs qui conservent durablement des données, à la manière de fichiers sur un ordinateur. Ce sont les composants de base du modèle de programmation de Solana utilisés pour stocker l’état (c’est-à-dire le solde du compte, les informations de propriété, le fait que le compte contienne ou non un programme et les informations de loyer).

Il existe trois types de comptes sur Solana :

  • Les comptes qui stockent des données
  • Les comptes qui stockent des programmes exécutables
  • Les comptes qui stockent des programmes natifs

Ces types de comptes peuvent être distingués plus précisément selon leurs capacités :

  • Comptes exécutables - comptes capables d’exécuter du code
  • Comptes non exécutables - comptes utilisés pour stocker des données sans pouvoir exécuter de code (puisqu’ils n’en contiennent aucun !)

L’image ci-dessus présente quelques exemples de comptes exécutables et non exécutables. Parmi les comptes exécutables, Bubblegum est un exemple de compte de programme. Il s’agit d’un programme de Metaplex utilisé pour créer et gérer des NFT compressés. Le Vote Program est un exemple de compte de programme natif. Il sert à créer et gérer des comptes qui suivent l’état des votes des validateurs et leurs récompenses. Nous expliquerons la différence entre les comptes de programme et de programme natif dans la section Que sont les programmes ?. Pour l’instant, retenez simplement qu’il existe différents types de comptes exécutables sur Solana.

En outre, chaque compte non exécutable peut être classé comme compte de données. Voici quelques exemples de comptes de données :

  • Un compte de token associé - un compte qui contient des informations sur un token précis, son solde et son propriétaire (par exemple, Alice possède 10 USDC)
  • Un compte système - un compte créé et détenu par le System Program
  • Un compte de staking - un compte utilisé pour déléguer des tokens à des validateurs afin de potentiellement obtenir des récompenses

Structure des comptes

Les comptes sont structurés selon la struct AccountInfo :

Code
pub struct AccountInfo<'a> {
    pub key: &'a Pubkey,
    pub lamports: Rc>,
    pub data: Rc>,
    pub owner: &'a Pubkey,
    pub rent_epoch: Epoch,
    pub is_signer: bool,
    pub is_writable: bool,
    pub executable: bool,
}

Les comptes sont identifiés par leur adresse (key), qui est une clé publique unique de 32 octets.

Le champ lamports contient le nombre de lamports détenus par ce compte. Un lamport correspond à un milliardième de SOL, le token natif de Solana.

data désigne le tableau d’octets de données brutes stocké par ce compte. Il peut contenir aussi bien les métadonnées d’un actif numérique que des soldes de tokens, et peut être modifié par les programmes.

Le champ owner contient le propriétaire de ce compte, représenté par l’adresse d’un compte de programme. La propriété des comptes est soumise à quelques règles :

  • Seul le propriétaire d’un compte peut modifier ses données et retirer des lamports
  • N’importe qui peut déposer des lamports sur un compte
  • Le propriétaire d’un compte peut en transférer la propriété à un nouveau propriétaire, à condition que les données du compte soient remises à zéro

Le champ is_signer est un booléen qui indique si une transaction a été signée par le propriétaire du compte concerné. Autrement dit, il indique aux programmes impliqués dans la transaction si le compte est signataire. Être signataire signifie que le compte détient la clé privée correspondant à la clé publique et dispose de l’autorité nécessaire pour approuver la transaction proposée.

Le champ is_writable est un booléen qui indique si les données du compte peuvent être modifiées. Solana permet aux transactions de déclarer des comptes en lecture seule afin de faciliter le traitement parallèle. Si l’environnement d’exécution autorise l’accès simultané aux comptes en lecture seule par différents programmes, il gère les éventuels conflits d’écriture sur les comptes modifiables selon un ordre de traitement des transactions. Ainsi, seules les transactions sans conflit sont traitées en parallèle.

Le champ executable est un booléen qui indique si un compte peut traiter des instructions. Oui, cela signifie bien que les programmes sont stockés dans des comptes, et nous approfondirons ce point dans la prochaine section. Mais nous devons d’abord aborder le concept de loyer.

Le champ rent_epoch indique la prochaine époque à laquelle ce compte devra payer un loyer. Une époque correspond au nombre de slots pendant lesquels un calendrier de leaders est valide. Contrairement aux fichiers traditionnels d’un système d’exploitation, les comptes sur Solana ont une durée de vie exprimée en lamports. Le fait que l’existence continue d’un compte dépende de son solde en lamports nous amène au concept de loyer.

Loyer

Le loyer est un coût de stockage nécessaire pour maintenir les comptes actifs sur Solana et garantir leur conservation dans la mémoire des validateurs. Sa perception est évaluée selon les époques, une unité de temps définie par les slots pendant lesquels un calendrier de leaders est valide. Voici comment fonctionne le loyer :

  • Perception du loyer - le loyer est perçu une fois par époque. Il peut également l’être lorsqu’un compte est référencé par une transaction
  • Distribution du loyer - une partie du loyer perçu est brûlée, c’est-à-dire définitivement retirée de la circulation. Le reste est distribué aux comptes de vote après chaque slot
  • Paiement du loyer - si un compte ne contient pas assez de lamports pour payer le loyer, ses données sont supprimées et le compte est désalloué par un processus appelé ramasse-miettes
  • Exemption de loyer - les comptes peuvent être exemptés de loyer s’ils conservent un solde minimal équivalant à deux années de paiements de loyer. Tous les nouveaux comptes doivent respecter ce seuil d’exemption, qui dépend de leur taille
  • Récupération du loyer - les utilisateurs peuvent fermer un compte pour récupérer les lamports restants. Ils peuvent ainsi récupérer le loyer stocké sur un compte

Le loyer peut être estimé à l’aide de l’endpoint RPC getMinimumBalanceForRentExemption pour une taille de compte donnée. Le Test Drive simplifie cette opération en acceptant la longueur des données d’un compte en usize. La sous-commande Solana rent de la CLI permet également d’estimer la quantité minimale de SOL nécessaire pour qu’un compte soit exempté de loyer. Par exemple, au moment de la rédaction de cet article, l’exécution de la commande solana rent 20000 renvoie Rent-exempt minimum: 0.14009088 SOL.

Adresses sur Solana

Il existe en réalité deux « types » d’adresses sur Solana. Pour créer les adresses, Solana utilise ed25519, un schéma de signature EdDSA reposant sur SHA-512 (SHA-2) et la courbe elliptique Curve22519. Il en résulte des clés publiques de 32 octets, qui servent de format d’adresse principal. Elles peuvent être utilisées directement puisqu’elles ne sont pas hachées.

Pour être valide, une adresse doit correspondre à un point de la courbe ed25519. Toutefois, toutes les adresses ne doivent pas nécessairement être dérivées de cette courbe. Les Program Derived Addresses (PDA) sont générées hors courbe, ce qui signifie qu’elles n’ont pas de clé privée correspondante et ne peuvent pas servir à signer. Les PDA sont créées par le System Program et utilisées lorsque des programmes doivent gérer des comptes. Cette remarque vise simplement à vous informer, en tant que lecteur, des différents types d’adresses sur Solana. Nous aborderons les PDA dans un prochain article.

En quoi les comptes Solana diffèrent-ils des comptes Ethereum ?

Ethereum comporte deux grands types de comptes : les comptes détenus de manière externe (EOA) et les comptes de contrat. Les EOA sont contrôlés par des clés privées, tandis que les comptes de contrat sont régis par le code de leur contrat et ne peuvent pas initier de transactions par eux-mêmes.

Les EOA et les comptes de contrat suivent la même structure de compte :

  • Solde - chaque compte possède un solde mesuré en Ether
  • Nonce - pour les EOA, il s’agit du nombre de transactions envoyées depuis le compte. Pour les contrats, il s’agit du nombre de contrats créés par le compte
  • Racine de stockage - un hachage de 256 bits du nœud racine d’un arbre de Merkle Patricia, qui encode le contenu du stockage du compte
  • CodeHash - le hachage du code Ethereum Virtual Machine (EVM) du contrat. Il est immuable : son code ne change pas après sa création, contrairement à son état. Il convient de noter qu’il existe des exceptions pour mettre à niveau les contrats sur Ethereum, notamment l’utilisation de modèles de proxy, mais ce sujet dépasse le cadre de cet article. Pour les EOA, il s’agit du hachage d’une chaîne vide, car ils ne contiennent aucun code

Solana adopte un modèle de compte plus uniforme, dans lequel n’importe quel compte peut potentiellement être un programme. La séparation du code et des données favorise un environnement plus efficace et plus flexible. Les programmes Solana sont sans état et interagissent avec différents comptes de données sans déploiements redondants. C’est particulièrement avantageux pour les applications de finance décentralisée (DeFi), dans lesquelles un utilisateur souhaite interagir avec plusieurs protocoles sans déplacer ses actifs entre différents programmes. À l’inverse, le modèle de programmation d’Ethereum combine le code et l’état en une seule entité. Les interactions sont alors plus complexes et potentiellement plus coûteuses en raison du gas nécessaire aux changements d’état.

Les comptes Solana devaient auparavant payer un loyer et conserver un solde minimal pour rester actifs. Les comptes inutilisés ou insuffisamment financés finissaient ainsi par être récupérés par le réseau, ce qui réduisait l’accumulation excessive d’état. À la suite de mises à jour récentes, il n’existe plus de comptes payant un loyer sur le mainnet : les comptes doivent être exemptés de loyer. En comparaison, Ethereum utilise le gas pour gérer l’allocation des ressources. Dans ce modèle, le stockage d’un contrat persiste indéfiniment, sauf s’il est explicitement effacé. L’approche de Solana offre une structure de coûts plus prévisible pour le stockage de l’état, tandis que les coûts d’Ethereum peuvent varier et devenir prohibitifs lors des périodes de congestion du réseau.

Dans la section suivante, nous examinerons comment Solana sépare la logique de ses programmes de l’état. En comparaison avec le modèle de programmation d’Ethereum, vous verrez comment cette approche modulaire permet des opérations on-chain plus efficaces, tout en offrant aux développeurs une structure de coûts transparente et prévisible.

Que sont les programmes Solana ?

Les programmes sont des comptes exécutables détenus par le BPF Loader. Ils sont exécutés par l’environnement d’exécution Solana, conçu pour traiter les transactions et la logique des programmes.

L’une des caractéristiques distinctives du modèle de programmation de Solana est la séparation du code et des données. Les programmes sont sans état, ce qui signifie qu’ils ne stockent aucun état en interne. Toutes les données dont ils ont besoin sont stockées dans des comptes distincts, transmis aux programmes par référence via les transactions. Cette conception permet à un déploiement unique et générique d’un programme d’interagir avec différents comptes.

Les programmes sur Solana peuvent :

  • Détenir des comptes supplémentaires
  • Lire ou créditer d’autres comptes
  • Modifier les données ou débiter les comptes qu’ils détiennent

Il existe deux types de programmes :

  • Programmes on-chain - il s’agit de programmes écrits par les utilisateurs et déployés sur Solana. Ils peuvent être mis à niveau par leur autorité de mise à niveau, généralement le compte qui a déployé le programme
  • Programmes natifs - il s’agit de programmes intégrés au cœur de Solana. Ils fournissent les fonctionnalités fondamentales nécessaires au fonctionnement des validateurs. Les programmes natifs ne peuvent être mis à niveau qu’au moyen de mises à jour logicielles déployées sur l’ensemble du réseau. Parmi les exemples courants figurent le System Program, le BPF Loader Program et le Vote Program.

Les programmes on-chain et natifs peuvent être appelés par les utilisateurs et par d’autres programmes. Leur principale différence réside dans leurs mécanismes de mise à niveau : les programmes on-chain peuvent être mis à niveau par leur autorité de mise à niveau, tandis que les programmes natifs ne peuvent l’être que dans le cadre des mises à jour du cluster.

Solana Labs gère une sélection de programmes on-chain connue sous le nom de Solana Program Library. Cette bibliothèque facilite diverses opérations on-chain, notamment le prêt de tokens et la création de pools de staking. L’Associated Token Account Program, par exemple, définit une norme et un mécanisme permettant de relier le portefeuille d’un utilisateur à ses comptes de tokens respectifs. La SPL est par ailleurs dynamique. Des programmes comme Token-2022 développent et étendent les fonctionnalités fournies par le Token Program.

Le développement de programmes sur Solana s’effectue généralement en Rust avec l’aide d’Anchor, un framework à conventions qui simplifie la création de programmes en réduisant le code répétitif et en rationalisant la sérialisation et la désérialisation. Bien que Rust soit privilégié, les développeurs ne sont pas limités à ce langage : C, C++ et tout langage ciblant le backend BPF de LLVM (c’est-à-dire un composant de LLVM permettant de compiler des programmes en bytecode BPF) peuvent être utilisés. Les développements récents de Solang et Neon Labs permettent également aux développeurs d’utiliser Solidity pour développer des programmes.

Les programmes sont généralement développés et testés sur Localhost et Devnet avant d’être déployés sur Testnet ou Mainnet Beta. Les développeurs peuvent déployer leur programme avec la CLI Solana à l’aide de la commande solana program deploy <path to program>. Une fois compilé en objet partagé ELF contenant le bytecode BPF, le programme est chargé sur le cluster Solana désigné. Les programmes déployés résident dans des comptes marqués executable, l’adresse du compte servant de program_id.

À l’origine, les programmes sur Solana étaient déployés avec des comptes deux fois plus grands que le programme. La mise à jour 1.16 de Solana prend en charge les comptes redimensionnables afin d’offrir aux développeurs davantage de flexibilité et une meilleure allocation des ressources. Un développeur peut désormais déployer son programme avec un compte plus petit, puis augmenter sa taille ultérieurement.

Comme indiqué précédemment, les programmes sont considérés comme sans état, car toutes les données avec lesquelles ils interagissent sont stockées dans des comptes distincts transmis par référence. Tous les programmes disposent d’un point d’entrée unique où les instructions sont traitées. Celui-ci reçoit un program_id, un tableau de comptes et les données de l’instruction sous forme de tableau d’octets. Les programmes sont exécutés par l’environnement d’exécution Solana lorsqu’une transaction les invoque.

Que sont les transactions ?

Les transactions constituent la colonne vertébrale de l’activité on-chain. Elles sont le mécanisme par lequel les programmes sont invoqués et les changements d’état appliqués. Sur Solana, une transaction est un ensemble d’instructions qui indique aux validateurs les actions à effectuer, les comptes concernés et s’ils disposent des autorisations nécessaires.

Une transaction se compose de trois parties principales :

  • Un tableau de comptes à lire ou à modifier
  • Une ou plusieurs instructions
  • Une ou plusieurs signatures

Les transactions sur Solana suivent la struct Transaction. Celle-ci fournit les informations nécessaires au réseau pour traiter et valider les actions. Elle est définie comme suit :

Code
pub struct Transaction {
    pub signatures: Vec,
    pub message: Message,
}

Le champ signatures contient un ensemble de signatures correspondant au Message sérialisé. Chaque signature est associée à une clé de compte de la liste account_keys de Message, en commençant par le payeur des frais. Le payeur des frais est le compte chargé de couvrir les frais générés par le traitement d’une transaction. Il s’agit généralement du compte qui initie la transaction. Le nombre de signatures requises est égal à num_required_signatures, défini dans le MessageHeader du message.

Le message est lui-même une struct de type Message. Il est défini ainsi :

Code
pub struct Message {
    pub header: MessageHeader,
    pub account_keys: Vec,
    pub recent_blockhash: Hash,
    pub instructions: Vec,
}

Le header du message contient trois entiers non signés de 8 bits : le nombre de signatures requises (c’est-à-dire num_required_signatures), le nombre de signataires en lecture seule et le nombre de non-signataires en lecture seule.

Le champ account_keys répertorie toutes les adresses de comptes impliquées dans la transaction. Les comptes demandant un accès en lecture-écriture apparaissent en premier, suivis des comptes en lecture seule.

recent_blockhash est un blockhash récent contenant un hachage SHA-256 de 32 octets. Il est nécessaire pour indiquer la dernière fois qu’un client a observé le registre et sert de durée de validité aux transactions récentes. Les validateurs rejettent les transactions dont le blockhash est ancien. L’inclusion d’un blockhash récent permet également d’éviter les transactions en double, car toute transaction parfaitement identique à une transaction précédente est rejetée. Si, pour une raison quelconque, une transaction doit être signée bien avant son envoi au réseau, un nonce de transaction durable peut remplacer un blockhash récent afin de garantir son unicité.

Le champ instructions contient une ou plusieurs structs CompiledInstruction, chacune indiquant une action précise que les validateurs du réseau doivent effectuer.

Instructions

Une instruction est une directive correspondant à une invocation unique d’un programme Solana. Elle constitue la plus petite unité de logique d’exécution d’un programme et l’unité opérationnelle la plus élémentaire sur Solana. Les programmes interprètent les données transmises par une instruction et agissent sur les comptes indiqués. La struct Instruction est définie comme suit :

Code
pub struct Instruction {
    pub program_id: Pubkey,
    pub accounts: Vec,
    pub data: Vec,
}

Le champ program_id indique la clé publique du programme à exécuter. Il s’agit de l’adresse du programme qui traitera l’instruction. Le propriétaire du compte du programme, indiqué par cette clé publique, désigne le chargeur chargé d’initialiser et d’exécuter le programme. Après leur déploiement, le chargeur marque les programmes Solana Bytecode Format (SBF) on-chain comme exécutables. L’environnement d’exécution de Solana rejette toute transaction qui tente d’invoquer des comptes non marqués comme exécutables.

Le champ accounts répertorie les comptes que l’instruction peut lire ou modifier. Ces comptes doivent être fournis sous forme de valeurs AccountMeta. Tout compte dont les données peuvent être modifiées par l’instruction doit être déclaré modifiable, sans quoi la transaction échouera. En effet, les programmes ne peuvent pas écrire dans des comptes qu’ils ne détiennent pas ou pour lesquels ils ne disposent pas des autorisations requises. Cela s’applique aussi à la modification des lamports d’un compte : retirer des lamports d’un compte qui n’appartient pas au programme provoque l’échec de la transaction, tandis qu’il est permis d’ajouter des lamports à n’importe quel compte. Le champ accounts peut également indiquer des comptes qui ne sont ni lus ni modifiés par le programme. Cela permet d’influencer la planification de l’exécution du programme par l’environnement d’exécution, mais ces comptes seront autrement ignorés.

data est un vecteur générique d’entiers non signés de 8 bits qui sert d’entrée transmise au programme. Ce champ est essentiel, car il contient les instructions encodées que le programme exécutera.

Solana ne dépend d’aucun format particulier pour les données des instructions. Il prend toutefois en charge nativement la sérialisation via bincode et borsh (Binary Object Representation Serializer for Hashing). La sérialisation consiste à convertir des structures de données complexes en une série linéaire d’octets pouvant être transmise ou stockée. Le choix du mode d’encodage des données doit tenir compte du coût de décodage, puisque tout se déroule on-chain. La sérialisation Borsh est souvent préférée à bincode, car elle possède une spécification stable, une implémentation JavaScript et offre généralement une meilleure efficacité.

Les programmes utilisent des fonctions utilitaires pour simplifier la construction des instructions prises en charge. Par exemple, le System Program fournit une fonction utilitaire permettant de construire l’instruction SystemInstruction::Assign :

Code
pub fn assign(pubkey: &Pubkey, owner: &Pubkey) -> Instruction {
    let account_metas = vec![AccountMeta::new(*pubkey, true)];
    Instruction::new(
        system_program::id(),
        &SystemInstruction::Assign { owner: *owner },
        account_metas,
    )
}

Cette fonction construit une instruction qui, une fois traitée, attribue le compte indiqué au nouveau propriétaire fourni.

Une transaction peut contenir plusieurs instructions, exécutées séquentiellement et de manière atomique dans l’ordre où elles sont répertoriées. Cela signifie que soit toutes les instructions réussissent, soit aucune ne réussit. L’ordre des instructions peut donc être crucial. Les programmes doivent être renforcés pour traiter en toute sécurité toute séquence possible d’instructions et prévenir les exploitations potentielles.

Par exemple, lors de la désinitialisation, un programme peut tenter de désinitialiser un compte en ramenant son solde de lamports à zéro. Il suppose alors que l’environnement d’exécution Solana supprimera le compte. Cette hypothèse est valable entre les transactions, mais pas entre les instructions ou les invocations interprogrammes (nous aborderons les invocations interprogrammes dans un prochain article). Le programme doit explicitement remettre à zéro les données du compte pour se protéger contre cette faille potentielle du processus de désinitialisation. Dans le cas contraire, un attaquant pourrait émettre une instruction ultérieure pour exploiter cette suppression présumée, par exemple en réutilisant le compte avant la fin de la transaction.

Que sont les transactions versionnées ?

Les transactions sur Solana utilisent les normes IPv6 d’unité de transmission maximale (MTU) afin de garantir une transmission rapide et fiable des données au sein d’un cluster. La pile réseau de Solana utilise une taille MTU prudente de 1 280 octets. Une fois l’espace réservé aux en-têtes, 1 232 octets restent disponibles pour les données du paquet. La taille des transactions Solana est donc limitée à cette valeur.

Cette contrainte de taille permet diverses améliorations du réseau, mais limite aussi la complexité des opérations pouvant être effectuées dans une seule transaction. Comme chaque adresse de compte occupe 32 octets de stockage, une transaction peut contenir jusqu’à 35 comptes en l’absence d’instructions. Cette restriction pose problème pour les cas d’utilisation nécessitant plus de 35 comptes sans signature dans une seule transaction.

Pour résoudre ce problème, un nouveau format de transaction prenant en charge plusieurs versions de formats de transaction a été introduit. L’environnement d’exécution Solana prend actuellement en charge deux versions de transaction :

  • legacy - le format de transaction d’origine
  • 0 (Version 0) - le format de transaction le plus récent, qui prend en charge les tables de recherche d’adresses

La Version 0 a été publiée pour prendre en charge les tables de recherche d’adresses (ALT). Celles-ci stockent essentiellement les adresses de comptes dans une structure de données tabulaire on-chain. Ces tables sont des comptes distincts qui stockent les adresses de comptes et permettent de les référencer dans une transaction au moyen d’un index u8 de 1 octet. Cela réduit considérablement la taille d’une transaction, puisque chaque compte inclus n’utilise plus que 1 octet au lieu de 32. Les ALT sont particulièrement utiles pour les opérations complexes impliquant de nombreux comptes, comme celles courantes dans les applications DeFi.

Ce schéma est adapté de la section du Solana Cookbook consacrée aux transactions versionnées

Le terme « transactions versionnées » désigne la manière dont Solana prend en charge à la fois les formats de transaction hérités et ceux de Version 0. Cette approche garantit la composabilité tout en intégrant les améliorations de l’environnement d’exécution.

Structure d’une transaction versionnée

Un VersionedTransaction est défini ainsi :

Code
pub struct VersionedTransaction {
    pub signatures: Vec,
    pub message: VersionedMessage,
}

Le champ signatures est une liste des signatures des signataires de la transaction. Elles servent à authentifier la transaction et à en préserver l’intégrité. Le message constitue le contenu réel de la transaction. Il est encapsulé par le type VersionedMessage, un mince wrapper enum qui gère à la fois les messages hérités et ceux de Version 0 :

Code
pub enum VersionedMessage {
    Legacy(Message),
    V0(Message),
}

La version du message est déterminée par le premier bit du processus de sérialisation. Si le premier bit est activé, les 7 bits restants servent à déterminer quelle version de Message est sérialisée, à partir de la Version 0. Si le premier bit n’est pas activé, tous les octets servent à encoder le format Message hérité. Cela s’explique par l’existence de deux structs Message portant le même nom, mais réparties dans des modules différents : legacy et v0.

Un Message représente le format interne condensé d’une transaction. Il sert à la transmission sur le réseau et à la manipulation par l’environnement d’exécution. Il comprend une liste linéaire de tous les comptes utilisés par les instructions de la transaction, un MessageHeader décrivant la structure du tableau de comptes, un blockhash récent et un encodage compact des instructions du message. Voici la structure de la struct Message v0 :

Code
pub struct Message {
    pub header: MessageHeader,
    pub account_keys: Vec,
    pub recent_blockhash: Hash,
    pub instructions: Vec,
    pub address_table_lookups: Vec,
}

La différence entre un message hérité et un message v0 réside dans l’inclusion du champ address_table_lookups.

Intégration du modèle de programmation au flux de transactions de Solana

Le modèle de programmation de Solana est profondément intégré à ses systèmes de comptes et de transactions. Voici comment ces concepts s’articulent :

  • Les comptes comme état - les comptes sur Solana servent de conteneurs d’état aux programmes. Le modèle de programmation repose sur la modification des données stockées dans ces conteneurs en réponse aux instructions
  • Instructions - les programmes définissent la logique de traitement des instructions contenues dans une transaction. Ces instructions sont les composants exécutables qui interagissent avec les données des comptes
  • Sérialisation et traitement - lorsqu’une transaction est sérialisée, les instructions du programme déterminent les modifications apportées aux états des comptes. Le processus de sérialisation respecte la conception du programme, qu’il utilise le format de transaction hérité ou celui de Version 0
  • Atomicité - le modèle de programmation de Solana garantit le traitement atomique des instructions. Les programmes doivent être conçus pour gérer les transactions simultanées de manière sûre et efficace
  • Évolutivité - le modèle de programmation de Solana favorise l’évolutivité grâce à des fonctionnalités telles que les tables de recherche d’adresses (ALT). Ces tables réduisent la taille d’une transaction et augmentent le nombre de comptes qu’elle peut référencer

Le modèle de programmation de Solana ne consiste pas seulement à écrire du code : il faut comprendre comment ce code interagit avec l’écosystème au sens large. Les comptes sont essentiels à ce modèle, car ils constituent le principal moyen de stocker et de modifier les données sur le réseau. Les transactions rendent possible l’activité on-chain en indiquant aux validateurs quelles données doivent être créées, mises à jour ou supprimées. Une compréhension approfondie de ces aspects est indispensable pour permettre aux développeurs de créer des applications optimisées en matière de performances et de synergie au sein de l’écosystème Solana.

Conclusion

Félicitations ! Dans cet article, nous avons parcouru les complexités de l’architecture système de Solana et étudié le concept des clusters comme tas monolithiques de données. Nous avons découvert comment ce tas est organisé en régions mémoire distinctes appelées comptes, qui constituent la colonne vertébrale du modèle de programmation de Solana. Les comptes stockent aussi bien les tokens des utilisateurs que les programmes qui définissent le comportement du réseau, et tous sont modifiés au moyen de transactions.

Pour les développeurs, il est crucial de comprendre l’approche de Solana en matière de calcul décentralisé. Maîtriser les subtilités des comptes, des programmes et des transactions est indispensable pour créer des applications qui exploitent pleinement les capacités de Solana. Il s’agit de comprendre un système dans lequel le code est découplé de l’état. Il en résulte des programmes sans état qui interagissent avec les données par l’intermédiaire de comptes, à un niveau inédit de composabilité et de capacité de mise à niveau.

Pour les investisseurs comme pour les utilisateurs occasionnels, comprendre comment la conception de Solana crée un écosystème robuste, flexible et efficace est essentiel pour apprécier la viabilité de la plateforme et sa capacité à favoriser des applications innovantes qui ne sont possibles que sur Solana.

Si vous avez lu jusqu’ici, anon, merci ! Vous voulez aller plus loin ? Rejoignez notre Discord pour commencer dès aujourd’hui à programmer sur Solana.

Ressources supplémentaires / Pour aller plus loin

Abonnez-vous à Helius

Suivez les dernières actualités du développement sur Solana et recevez une notification à chaque publication

Image agrandie