
Comment créer des programmes Solana avec Pinocchio
Sommaire
- Qu’est-ce que la bibliothèque Pinocchio ?
- Pourquoi Pinocchio est-il plus performant que solana-program ?
- Comment les points d’entrée de Pinocchio désérialisent-ils différemment les entrées des programmes Solana ?
- Comment Pinocchio permet-il aux développeurs d’optimiser les CU ?
- Pinocchio ou Anchor
- Pinocchio ou Steel
- Comment créer un token avec Pinocchio
- 1. Définir un point d’entrée
- 2. Définir la structure des données d’instruction
- 3. Analyser les comptes et les données d’instruction
- 4. Créer le compte d’émission Token2022
- 5. Initialiser l’extension, le compte et les valeurs des métadonnées
- Outils complémentaires pour développer avec Pinocchio
- Bytemuck pour la (dé)sérialisation des comptes
- Shank pour générer des IDL
- Codama pour générer des clients
- L’avenir de Pinocchio
- Comment contribuer à Pinocchio
- Conclusion
- Ressources supplémentaires
Pinocchio est une bibliothèque sans dépendance et hautement optimisée qui permet de créer des programmes Solana natifs. Pinocchio a été créé par Anza, l’équipe principale qui développe le client Agave de Solana.
Exo Tech est une agence de développement Solana de premier plan qui compte parmi les premiers utilisateurs de Pinocchio. Dans le cadre de nos missions pour nos clients, nous avons développé plusieurs programmes en production avec Pinocchio et contribué au SDK pour ajouter des fonctionnalités manquantes.
Cet article examine en détail la création de programmes avec Pinocchio, ainsi que ses avantages et ses compromis. Notre objectif est de donner aux développeurs les connaissances nécessaires pour déterminer si Pinocchio convient à leur programme. Il est toutefois important de noter que Pinocchio n’est pas adapté aux débutants, car il privilégie l’optimisation au détriment de l’expérience développeur.
Qu’est-ce que la bibliothèque Pinocchio ?
La bibliothèque Pinocchio remplace le crate solana-program et optimise l’exécution des programmes grâce à une utilisation intensive des types zero-copy. zero-copy signifie qu’il n’est pas nécessaire de copier les données vers une autre adresse mémoire lors de leur lecture ou de leur écriture, ce qui économise des ressources de calcul (ou CU dans Solana).
La bibliothèque ne comporte aucune dépendance et est « no_std ». Le crate std de Rust fournit des méthodes courantes pour accéder aux ressources du système d’exploitation ainsi qu’un environnement d’exécution. Toutefois, puisque la Solana Virtual Machine (SVM) constitue elle-même un environnement d’exécution, cette surcharge est inutile.
Pourquoi Pinocchio est-il plus performant que solana-program ?
Chaque programme Solana a besoin d’un point d’entrée appelé par l’environnement d’exécution pour lancer son exécution. La bibliothèque solana-program expose la macro entrypoint!, qui désérialise l’entrée du programme, configure un allocateur de tas et crée un gestionnaire de panique.
macro_rules! entrypoint {
($process_instruction:ident) => {
/// # Safety
#[no_mangle]
pub unsafe extern "C" fn entrypoint(input: *mut u8) -> u64 {
let (program_id, accounts, instruction_data) =
unsafe { $crate::entrypoint::deserialize(input) };
match $process_instruction(&program_id, &accounts, &instruction_data) {
Ok(()) => $crate::entrypoint::SUCCESS,
Err(error) => error.into(),
}
}
$crate::custom_heap_default!();
$crate::custom_panic_default!();
};
}Pinocchio exporte trois macros de point d’entrée.
Pour les développeurs qui migrent depuis solana-program, la macro entrypoint! fonctionne globalement de la même manière : elle désérialise l’entrée du programme et configure l’allocateur et le gestionnaire.
Cependant, les deux autres macros dissocient le point d’entrée de la configuration de l’allocateur de tas et du gestionnaire de panique. Le développeur dispose ainsi d’un contrôle accru pour les omettre ou les optimiser avant l’exécution de la logique de son programme.
program_entrypoint! désérialise l’entrée du programme de manière similaire à solana-program, tandis que lazy_program_entrypoint! se contente d’encapsuler le tampon d’entrée et délègue son traitement au programme, ce qui offre un meilleur contrôle sur le calcul.
Comme ces macros ne configurent ni l’allocateur de tas ni le gestionnaire de panique, la bibliothèque Pinocchio expose des macros par défaut que le développeur peut utiliser.
Par ailleurs, si un programme sait qu’il n’aura jamais besoin de mémoire dans le tas, no_allocator! économise des unités de calcul (CU) en évitant de configurer un allocateur de mémoire.
Comment les points d’entrée de Pinocchio désérialisent-ils différemment les entrées des programmes Solana ?
Nous avons brièvement expliqué comment le point d’entrée de solana-program et celui de Pinocchio désérialisent l’entrée du programme. Il est toutefois important de comprendre en quoi ces désérialisations diffèrent, car c’est là que se réalisent d’importantes économies de CU.
À première vue, les entrées désérialisées transmises au gestionnaire d’instructions du programme semblent identiques :
/// solana-program and pinocchio both look the same
process_instruction(
program_id: &Pubkey,
accounts: &[AccountInfo],
instruction_data: &[u8],
) -> ProgramResult
La principale différence réside dans l’implémentation de AccountInfo.
Tandis que solana-program écrit les données dans une structure AccountInfo qui en est propriétaire, la structure AccountInfo de Pinocchio n’est elle-même qu’un pointeur vers les données d’entrée sous-jacentes représentant le compte. Cela réduit la quantité de données à copier et permet d’économiser beaucoup de CU.
Comment Pinocchio permet-il aux développeurs d’optimiser les CU ?
Comme le processeur d’instructions reçoit des références vers des pointeurs, les développeurs qui utilisent la bibliothèque Pinocchio constateront que leur logique est rarement propriétaire des données qu’elle manipule.
Cela se constate facilement lorsque vous tentez d’accéder aux valeurs de AccountInfo. La lecture de la clé publique du compte avec la méthode key() renvoie une référence vers Pubkey. La lecture des informations du compte pendant l’exécution du programme et la modification de ses données deviennent ainsi moins coûteuses.
Exemple d’optimisation des CU avec Pinocchio : P-token
Le programme p-token est un excellent exemple qui continue d’exploiter le zero-copy à des fins d’optimisation.
Ce programme est conçu pour remplacer le programme SPL Token canonique, mais il utilise Pinocchio afin de réduire considérablement le nombre d’unités de calcul de chaque transaction.
Vous remarquerez rapidement que tout accès à l’état s’effectue par l’intermédiaire de pointeurs.
Au lieu de désérialiser le compte de token, les données de AccountInfo sont vérifiées, puis un pointeur est renvoyé.
Chaque propriété est accessible par l’intermédiaire d’une fonction, et toutes les valeurs qui ne sont pas primitives renvoient une référence afin de préserver le zero-copy.
Pour mieux comprendre pourquoi cela réduit considérablement l’utilisation des CU, consultez cet article sur l’optimisation des CU.
Pinocchio ou Anchor
Anchor est un framework très populaire et directif pour développer des programmes Solana. Il est considéré comme étant de plus haut niveau que Pinocchio, car il ne contient aucune logique exposant les structures sous-jacentes telles que AccountInfo.
Anchor dépend plutôt du crate solana-program mentionné précédemment et expose des traits et des macros qui simplifient le processus de développement des programmes. Anchor fournit des modèles de discriminateurs d’instructions et une logique de désérialisation des comptes. La logique de désérialisation repose sur Borsh, qui nécessite de copier les données vers une autre adresse mémoire, car elle n’utilise pas le zero-copy.
Si la commodité offerte par Anchor accélère le développement de programmes Solana, elle entraîne aussi une plus grande utilisation des CU.
Pinocchio, en revanche, est une bibliothèque destinée à remplacer solana-program lorsque les développeurs ont besoin d’un contrôle précis de l’utilisation des ressources de calcul. Elle n’impose aucune convention et permet au développeur de structurer son programme comme il le souhaite. La structure de chaque projet Pinocchio peut être totalement différente, tandis que les projets Anchor suivent des structures clairement définies.
La bibliothèque Pinocchio ne gère aucune liaison ni implémentation côté client. Anchor, en revanche, prend nativement en charge la génération d’IDL, qui peuvent être utilisées côté client pour interagir avec le programme.
Les développeurs qui utilisent Pinocchio doivent écrire leurs propres outils ou recourir à des solutions telles que Shank et Codama, que nous présentons ci-dessous dans la section Outils complémentaires pour développer avec Pinocchio.
Pinocchio ou Steel
Steel est un autre framework permettant d’écrire des programmes Solana. Actuellement basé sur solana-program, Steel expose des macros, des fonctions et des modèles qui facilitent l’écriture de programmes sûrs et expressifs.
La nature directive de Steel facilite la lecture tout en préservant la modularité. Contrairement à Anchor, qui est un framework tout-en-un, les développeurs peuvent choisir de n’utiliser que les composants de Steel dont ils ont besoin.
La macro account! de Steel utilise bytemuck pour analyser les structures de comptes, tandis que Pinocchio ne gère pas du tout cette analyse. Steel inclut également des analyseurs chaînables et des assertions, ce qui facilite l’ajout de validations personnalisées. Pinocchio ne fournit aucun modèle de ce type et oblige le développeur à écrire ses propres modèles de validation.
Toutefois, pour les invocations inter-programmes (CPI) courantes, notamment celles du System Program et du Token Program, Pinocchio et Steel exposent tous deux des modèles qui facilitent ces invocations.
Pinocchio est hautement optimisé, mais laisse chaque détail à la charge du développeur. Steel est une couche modulaire pratique autour de la bibliothèque solana-program, conçue pour améliorer l’expérience développeur.
Comment créer un token avec Pinocchio
Pour présenter un programme écrit avec Pinocchio, nous allons réécrire le programme de création de token issu des exemples pour développeurs Solana.
Il s’agit d’un programme simple comportant une seule instruction, qui crée une émission de tokens Token2022 et utilise l’extension de token Metadata pour stocker les informations relatives au token. Les métadonnées sont fournies par les données d’instruction, qui contiennent un nom, un symbole et un URI.
1. Définir un point d’entrée
Commençons par définir le point d’entrée de notre programme.
Nous utilisons la macro de point d’entrée complète, car nous souhaitons utiliser l’allocateur et la gestion des paniques par défaut de Pinocchio.
entrypoint!(process_instruction);
fn process_instruction(
_program_id: &Pubkey,
accounts: &[AccountInfo],
instruction_data: &[u8],
) -> ProgramResult {
Ok(())
}2. Définir la structure des données d’instruction
Définissons ensuite la structure de nos données d’instruction afin qu’elle corresponde à celle des autres programmes d’exemple. Pour gagner du temps lors du développement, nous allons utiliser Borsh pour la désérialisation et réserver les méthodes de désérialisation plus optimales à un prochain article.
#[derive(BorshDeserialize, Debug)]
pub struct CreateTokenArgs {
pub name: String,
pub symbol: String,
pub uri: String,
pub decimals: u8,
}3. Analyser les comptes et les données d’instruction
Écrivons maintenant la logique de notre processeur d’instructions.
Nous devons d’abord déstructurer les comptes de la liste de comptes et désérialiser les données d’instruction dans notre CreateTokenArgs.
let [mint_account, mint_authority, payer, token_program, _system_program] = accounts else {
return Err(ProgramError::NotEnoughAccountKeys);
};
let args = CreateTokenArgs::try_from_slice(instruction_data)
.map_err(|_| ProgramError::InvalidInstructionData)?;4. Créer le compte d’émission Token2022
Une fois les comptes et les données d’instruction analysés, nous invoquons l’instruction CreateAccount du System Program.
Ci-dessous, nous utilisons la structure CreateAccount du crate `pinocchio_system crate as it makes it very convenient to CPI by setting values of the struct and calling invoke.
Contrairement à la création d’une émission SPL Token normale, nous devons déterminer l’espace supplémentaire requis par les extensions de token utilisées.
La taille de l’extension Metadata Pointer est fixe, tandis que celle de l’extension Token Metadata doit être calculée dynamiquement en fonction des arguments fournis.
/// [4 (extension discriminator) + 32 (update_authority) + 32 (metadata)]
const METADATA_POINTER_SIZE: usize = 4 + 32 + 32;
/// [4 (extension discriminator) + 32 (update_authority) + 32 (mint) + 4 (size of name ) + 4 (size of symbol) + 4 (size of uri) + 4 (size of additional_metadata)]
const METADATA_EXTENSION_BASE_SIZE: usize = 4 + 32 + 32 + 4 + 4 + 4 + 4;
/// Padding used so that Mint and Account extensions start at the same index
const EXTENSIONS_PADDING_AND_OFFSET: usize = 84;
/* within `process_instruction` */
let extension_size = METADATA_POINTER_SIZE
+ METADATA_EXTENSION_BASE_SIZE
+ args.name.len()
+ args.symbol.len()
+ args.uri.len();
let total_mint_size = Mint::LEN + EXTENSIONS_PADDING_AND_OFFSET + extension_size;
let rent = Rent::get()?;
// Create the account for the Mint
CreateAccount {
from: payer,
to: mint_account,
owner: token2022_program.key(),
lamports: rent.minimum_balance(Mint::LEN),
space: Mint::LEN as u64,
}
.invoke()?;
Après l’invocation de CreateAccount, le SystemProgram a enregistré le programme Token2022 comme propriétaire du compte d’émission.
5. Initialiser l’extension, le compte et les valeurs des métadonnées
Nous devons ensuite définir les données du compte en initialisant l’extension Metadata Pointer, en initialisant le compte d’émission avec le programme Token2022 et en initialisant les valeurs de métadonnées reçues par notre programme sous forme d’arguments.
Les CPI suivantes proviennent d’une branche du crate pinocchio_token en cours de développement actif. Il convient donc de noter que ce code risque d’être obsolète, car il est prévu de séparer les fonctionnalités Token2022 du crate SPL Token.
// Initialize MetadataPointer extension pointing to the Mint account
InitializeMetadataPointer {
mint: mint_account,
authority: Some(*payer.key()),
metadata_address: Some(*mint_account.key()),
}
.invoke()?;
// Now initialize that account as a Token2022 Mint
InitializeMint2 {
mint: mint_account,
decimals: args.decimals,
mint_authority: mint_authority.key(),
freeze_authority: None,
}
.invoke(TokenProgramVariant::Token2022)?;
// Set the metadata within the Mint account
InitializeTokenMetadata {
metadata: mint_account,
update_authority: payer,
mint: mint_account,
mint_authority: payer,
name: &args.name,
symbol: &args.symbol,
uri: &args.uri,
}
.invoke()?;Et voilà !
Nous disposons maintenant d’une émission de tokens avec des métadonnées autonomes, basée sur Token2022 et écrite avec Pinocchio.
Ce code peut encore être amélioré afin d’atteindre une optimisation maximale, mais nous espérons qu’il vous aide à comprendre comment écrire des programmes avec Pinocchio.
Outils complémentaires pour développer avec Pinocchio
Les outils propres à Pinocchio sont encore peu nombreux, mais leur nombre augmente.
Bytemuck pour la (dé)sérialisation des comptes
La (dé)sérialisation des comptes doit être implémentée par le développeur d’un programme Pinocchio. Effectué manuellement, ce processus est fastidieux et propice aux erreurs. Bytemuck est une excellente bibliothèque qui facilite la lecture et l’écriture de tableaux d’octets sous forme de structures. Elle est donc plutôt bien optimisée, car elle limite la quantité de données à copier en mémoire.
Borsh constitue une autre solution pour travailler avec des comptes dont la taille n’est pas fixe. Elle est toutefois moins économe en ressources de calcul, ce qui explique en partie pourquoi certains choisissent Pinocchio plutôt qu’Anchor.
Shank pour générer des IDL
Comme Pinocchio est une bibliothèque, elle ne propose pas de génération intégrée d’IDL comme Anchor. Une IDL (Interface Definition Language) est un fichier JSON qui définit l’interface publique d’un programme Solana, notamment ses instructions, les structures de ses comptes et ses codes d’erreur. Elle permet de standardiser les interactions et de simplifier le développement côté client.
Pour générer des IDL, nous recommandons d’utiliser Shank. Ce crate permet aux développeurs d’annoter très facilement leur code et d’utiliser une CLI pour générer une IDL valide. L’ajout de la macro ShankAccount à l’instruction derive d’une structure indique qu’il s’agit d’un compte qui doit pouvoir être (dé)sérialisé. Après l’exécution de la CLI Shank, cette structure apparaît comme un compte typé dans l’IDL et peut ensuite servir à générer le client.
Une autre macro importante est ShankInstruction, destinée à l’énumération des instructions du programme. Elle permet d’utiliser un attribut #[account] pour indiquer l’index et les autorisations de chaque compte dans la liste correspondant à cette instruction.
Consultez le dépôt shank-macro pour en savoir plus sur les annotations de code utiles qui facilitent la génération d’IDL pour les programmes ne reposant pas sur Anchor.
Codama pour générer des clients
Une fois votre IDL disponible, Codama facilite la génération de clients. Si le code généré ne répond pas à vos besoins, vous devrez écrire les clients manuellement.
Chez Exo Tech, nous avons créé un modèle de projet Pinocchio qui nous aide à mettre rapidement en place des dépôts de programmes Solana. N’hésitez pas à l’essayer et à ouvrir une pull request pour proposer des améliorations !
L’avenir de Pinocchio
Bien que Pinocchio soit destiné à remplacer directement solana-program, il ne propose pas encore toutes les mêmes fonctionnalités. Certaines sysvars ne sont pas encore prises en charge, et les crates qui ne font pas partie du cœur ne sont pas totalement compatibles ou n’existent pas. Par exemple, le crate du programme Token de Pinocchio ne prend pas en charge plusieurs signataires. Token2022 n’est pas non plus pris en charge, même si cette fonctionnalité est en cours de développement.
L’un des principaux inconvénients de Pinocchio tient au fait que tous les SDK développés pour d’autres programmes Solana utilisent le crate solana-program. Cela signifie que chaque SDK doit être propriétaire de AccountInfo ou des données transmises, ce qui rend l’interopérabilité avec un programme développé avec Pinocchio extrêmement difficile.
Lorsque vous intégrez des programmes tiers, il est très fréquent de devoir écrire une logique de CPI personnalisée pour chaque instruction. Des générateurs de code comme Codama pourraient finir par résoudre ce problème, mais ce n’est pas encore le cas.
Il est important de noter que Pinocchio est toujours en cours de développement actif et n’a pas été audité. La communauté s’efforce encore d’intégrer le reste des sysvars au SDK et d’améliorer la prise en charge des programmes SPL importants tels que Token et Token2022.
Comment contribuer à Pinocchio
Pinocchio offre de nombreuses possibilités de contribution facilement accessibles.
Des issues ouvertes et des pull requests existantes auraient besoin d’aide supplémentaire. Participez aux discussions ou ouvrez simplement une pull request afin que les responsables du projet puissent l’examiner !
Conclusion
Pinocchio est une bibliothèque considérablement plus performante que les solutions précédentes pour écrire des programmes Solana. En offrant aux développeurs davantage de flexibilité sur le point d’entrée de leur programme et en utilisant zero-copy pour accéder aux entrées du programme, elle peut les aider à réduire l’utilisation des CU. Toutefois, cette bibliothèque est encore récente et toutes les fonctionnalités ne sont pas encore disponibles. Elle n’avait pas été auditée au moment de la rédaction de cet article : utilisez-la donc avec prudence.
Pour déterminer s’il est pertinent d’utiliser Pinocchio, il est important d’évaluer les compromis par rapport aux autres bibliothèques et frameworks.
Les frameworks directifs comme Anchor accélèrent le développement des programmes et facilitent leur maintenance. Ils constituent donc un excellent choix lorsque la rapidité de mise sur le marché est essentielle.
Une fois votre produit stable et soumis à un volume élevé de transactions, il peut devenir plus pertinent d’optimiser vos programmes Solana avec une bibliothèque comme Pinocchio.
Ressources supplémentaires
Pour en savoir plus, regardez la présentation de Febo lors de Solana Accelerate 2025 et explorez ces ressources pédagogiques :
- Cours d’introduction à Pinocchio
- Leçon sur un coffre-fort Pinocchio
- Leçon sur un séquestre Pinocchio
- Leçon sur un coffre-fort Secp256r1 avec Pinocchio
- Programme de benchmark pour Bytemuck et Pinocchio
- Pinocchio-log pour une journalisation peu coûteuse
- Crate pinocchio-token
- Exécution d’un programme Solana : du code Rust au bytecode SBF
Articles associés
Abonnez-vous à Helius
Suivez les dernières actualités du développement sur Solana et recevez une notification à chaque publication


