Résumé : Suite à l'article précédent sur l'introduction de la technologie TON, j'ai étudié en profondeur les documents officiels de développement de TON au cours de cette période. J'ai l'impression qu'il existe encore des obstacles à l'apprentissage. Le contenu du document actuel semble plutôt être interne. document de développement, qui convient aux débutants. Il n'est pas très convivial pour les développeurs, j'essaie donc de trier une série d'articles sur le développement du projet TON Chain en fonction de mon propre parcours d'apprentissage, j'espère que cela sera utile à tout le monde pour l'obtenir rapidement. a commencé avec le développement de TON DApp. S'il y a des erreurs dans l'écriture, vous pouvez me corriger et apprendre ensemble.
L'émission d'un FT ou d'un NFT est généralement le besoin le plus élémentaire des développeurs DApp ? Je l'utilise donc également comme point d'entrée pour l'apprentissage. Tout d'abord, comprenons les différences suivantes entre le développement d'un NFT dans la pile technologique EVM et dans TON Chain. Les NFT basés sur EVM choisissent généralement d'hériter de la norme ERC-721. Ce qu'on appelle le NFT fait référence à un type indivisible d'actif crypté, et chaque actif est unique, c'est-à-dire qu'il possède certaines caractéristiques exclusives. ERC-721 est un paradigme de développement commun pour ce type d'actifs. Examinons quelles fonctions un contrat ERC721 commun doit mettre en œuvre et quelles informations sont enregistrées. L'image ci-dessous est une interface ERC721. On constate que contrairement à FT, ce qui doit être saisi dans l'interface de transfert, c'est le tokenId à transférer plutôt que le montant. Ce tokenId est également la manifestation la plus fondamentale du caractère unique des actifs NFT. Bien entendu, afin de transporter plus d'attributs, une métadonnée est généralement enregistrée pour chaque tokenId. Ces métadonnées sont un lien externe qui enregistre d'autres données évolutives du NFT, telles que. sous forme de liens vers des images PFP, certains noms d'attributs, etc.
Pour les développeurs familiers avec Solidity ou orientés objet, il est facile de mettre en œuvre un tel contrat intelligent tant que les types de données requis dans le contrat sont définis, comme certaines relations de mappage clés, et. sur la base des besoins Il est nécessaire de développer fonctionnellement la logique de modification correspondante pour ces données afin de réaliser un NFT.
Cependant, ce n'est pas la même chose dans TON Chain. Il y a deux raisons principales à la différence :
Bien sûr, d'autres différences techniques ont été abordées en détail dans l'article précédent. Cet article espère se concentrer sur le développement de contrats intelligents, il ne sera donc pas abordé. Les deux principes de conception ci-dessus font une grande différence entre le développement de contrats intelligents dans TON et EVM. Dans la discussion initiale, nous savons qu'un contrat NFT doit définir certaines relations de mappage, c'est-à-dire le mappage, pour enregistrer les données liées au NFT. Le plus important d'entre eux est celui des propriétaires. Ce mappage stocke la relation de mappage de l'adresse du propriétaire du NFT correspondant à un certain tokenID, qui détermine la propriété du NFT. Le transfert est une modification de la propriété. Puisqu’il s’agit d’une structure de données qui peut être illimitée en théorie, elle doit être évitée autant que possible. Par conséquent, il est officiellement recommandé d’utiliser l’existence de structures de données illimitées comme norme de partitionnement. Autrement dit, lorsqu'il existe des exigences similaires en matière de stockage de données, le paradigme du contrat maître-esclave est utilisé à la place et les données correspondant à chaque clé sont gérées en créant des sous-contrats. Et gérez les paramètres globaux via le contrat principal, ou aidez à gérer l'interaction des informations internes entre les sous-contrats.
Cela signifie que les NFT dans TON doivent également être conçus avec une architecture similaire. Chaque NFT est un sous-contrat indépendant, qui enregistre des données exclusives telles que l'adresse du propriétaire, les métadonnées, etc., et est géré via un contrat principal. données globales telles que le nom NFT, le symbole, l'offre totale, etc.
Après avoir clarifié l'architecture, l'étape suivante consiste à résoudre les exigences fonctionnelles de base. Puisque cette méthode de contrat maître-esclave est adoptée, il est nécessaire de clarifier quelles fonctions sont assurées par le contrat principal et quelles fonctions sont assurées par le sous-contrat. contrat, et quelles fonctions sont assurées par le sous-contrat, et quelles fonctions sont assurées par le sous-contrat. Quelles informations internes sont utilisées pour communiquer entre elles et comment restaurer les données précédentes lorsqu'une erreur d'exécution se produit. Habituellement, avant de développer un projet complexe à grande échelle, il est nécessaire de passer un diagramme de classes et de clarifier le flux d'informations entre eux, et de réfléchir attentivement à la logique de restauration après l'échec de l'appel interne. Bien sûr, le développement NFT ci-dessus est simple. , mais cela peut aussi être Effectuer une vérification similaire.
TON a choisi de concevoir un langage de type C, typé statiquement, nommé Func comme langage de développement de contrats intelligents. Apprenons ensuite à développer des contrats intelligents TON à partir du code source. J'ai choisi l'exemple NFT dans la documentation officielle de TON pour le présenter. Les amis intéressés peuvent le consulter par eux-mêmes. Dans ce cas, un exemple simple de TON NFT est implémenté. Jetons un coup d'œil à la structure du contrat, qui est divisée en deux contrats fonctionnels et trois bibliothèques nécessaires.
Les deux principaux contrats fonctionnels sont conçus selon les principes ci-dessus. Tout d'abord, regardons le code du contrat principal nft-collection :
Cela introduit le premier point de connaissance, comment stocker de manière persistante. de données dans les contrats intelligents TON. Nous savons que le stockage persistant des données dans Solidity est automatiquement géré par l'EVM en fonction du type de paramètres. Normalement, les variables d'état du contrat intelligent seront automatiquement conservées en fonction de la dernière valeur après l'exécution. . Stockage, les développeurs n'ont pas besoin de prendre en compte ce processus. Mais ce n'est pas le cas dans Func. Les développeurs doivent implémenter eux-mêmes la logique de traitement correspondante. Cette situation est quelque peu similaire à la nécessité de prendre en compte le processus GC en C et C++, mais d'autres nouveaux langages de développement automatisent généralement cette partie du processus. logique. Jetons un coup d'œil au code. Tout d'abord, nous introduisons quelques bibliothèques requises, puis nous voyons que la première fonction load_data est utilisée pour lire les données stockées de manière persistante. Sa logique est de renvoyer d'abord la cellule de stockage du contrat persistant via get_data. cela est fait par le standard Implémenté par la bibliothèque stdlib.fc, certaines de ces fonctions peuvent généralement être utilisées comme fonctions système.
Le type de valeur de retour de cette fonction est cell, qui est le type de cellule dans TVM. Dans l’introduction précédente, nous savons déjà que toutes les données persistantes de la blockchain TON sont stockées dans l’arborescence cellulaire. Chaque cellule contient jusqu'à 1 023 bits de données arbitraires et jusqu'à quatre références à d'autres cellules. Les cellules sont utilisées comme mémoire dans le TVM basé sur une pile. Ce qui est stocké dans la cellule sont des données codées de manière compacte. Pour obtenir les données en texte clair spécifiques, la cellule doit être convertie en un type appelé tranche. La cellule peut être convertie en type tranche via la fonction start_parse, puis les données de la cellule peuvent être obtenues en chargeant les bits de données de la tranche et les références à d'autres cellules. Notez que cette méthode d'appel à la ligne 15 est du sucre syntaxique dans func, et vous pouvez appeler directement la deuxième fonction qui renvoie la valeur de la première fonction. Et enfin chargez les données correspondantes dans l'ordre selon l'ordre de persistance des données. Notez que ce processus est différent de solidity et n'est pas appelé en fonction de hashmap, donc l'ordre des appels ne peut pas être gâché.
Dans la fonction save_data, la logique est similaire, sauf qu'il s'agit d'un processus inverse, qui introduit le point de connaissance suivant, un nouveau constructeur de type, qui est le type de constructeur de cellules. Les bits de données et les références à d'autres cellules peuvent être stockées dans des générateurs, qui peuvent ensuite être finalisées dans de nouvelles cellules. Créez d'abord un constructeur via la fonction standard start_cell et stockez tour à tour les fonctions associées via les fonctions liées au magasin. Notez que l'ordre d'appel ci-dessus doit être cohérent avec l'ordre de stockage ici. Enfin, la construction de la nouvelle cellule est terminée via end_cell. À ce stade, la cellule est gérée dans la mémoire. Enfin, via le set_data le plus externe, le stockage persistant de la cellule peut être terminé.
Ensuite, jetons un coup d'œil aux fonctions liées à l'entreprise. Tout d'abord, nous devons introduire le point de connaissance suivant, comment créer un nouveau contrat via un contrat, qui sera fréquemment utilisé dans l'architecture maître-esclave. introduit. Nous savons que dans TON, les appels entre contrats intelligents sont mis en œuvre par l'envoi de messages internes. Ceci est réalisé via un message appelé send_raw_message. Notez que le premier paramètre est la cellule codée du message et le deuxième paramètre est le bit d'identification, qui est utilisé pour indiquer la différence dans la méthode d'exécution de la transaction. Différents paramètres internes sont définis. dans TON, il existe actuellement 3 modes de message et 3 indicateurs de message pour la méthode d'exécution de l'envoi de messages. Un seul mode peut être combiné avec plusieurs indicateurs (peut-être aucun) pour obtenir le mode souhaité. Combiner signifie simplement remplir la somme de leurs valeurs. Le tableau de description des modes et des drapeaux est donné ci-dessous :
Jetons donc un coup d'œil à la première fonction principale, déployer_nft_item. Comme son nom l'indique, il s'agit d'une fonction utilisée pour créer ou lancer une nouvelle instance NFT. Après quelques opérations pour encoder un msg, le contrat interne est envoyé via send_raw_message et sélectionné. Le drapeau d'envoi du drapeau 1 utilise uniquement les frais spécifiés dans l'encodage comme frais de gaz pour cette exécution. Après l’introduction ci-dessus, on peut facilement se rendre compte que cette règle de codage doit correspondre à la manière de créer un nouveau contrat intelligent. Voyons donc comment cela est mis en œuvre.
Regardons directement la ligne 51. Les deux fonctions ci-dessus sont des fonctions auxiliaires utilisées pour générer les informations requises pour le message, nous y reviendrons donc plus tard. Il s'agit d'un processus d'encodage pour créer des messages internes de contrats intelligents. milieu En fait, ce sont aussi des bits d'identification utilisés pour expliquer les exigences du message interne. Le point de connaissance suivant est introduit ici. TON a choisi un langage binaire appelé TL-B pour décrire la méthode d'exécution du message, et différents bits d'indicateur. sont définis en fonction de Pour implémenter des messages internes pour certaines fonctions spécifiques, les deux scénarios d'utilisation les plus courants qui viennent à l'esprit sont la création de nouveaux contrats et les appels de fonctions de contrat déployés. La méthode de la ligne 51 correspond à la première, créant un nouveau contrat d'article nft, qui est principalement spécifié aux lignes 55, 56 et 57. Tout d'abord, la grande série de nombres de la ligne 55 est une série de bits d'identification. Notez que le premier paramètre d'entrée de store_uint est la valeur et le second est la longueur en bits, qui détermine si le message interne est créé par le contrat. , les trois derniers bits de marquage, et la valeur binaire correspondante est 111 (4+2+1 en décimal), dont les deux premiers indiquent que le message sera accompagné de données StateInit. Ces données sont le code source du nouveau. contrat et les données nécessaires à l’initialisation. Ce dernier bit indicateur indique la pièce jointe du message interne, c'est-à-dire que la logique pertinente et les paramètres requis devraient être exécutés. Par conséquent, vous verrez que les données à trois chiffres ne sont pas définies dans la ligne 66 du code, ce qui indique un appel de fonction au contrat déployé. Les règles de codage détaillées peuvent être trouvées ici.
Ensuite, les règles d'encodage de StateInit correspondent à 49 lignes de code, calculées via calculate_nft_item_state_init. Notez que l'encodage des données stateinit suit également une règle d'encodage TL-B établie. En plus de certains bits d'indicateur, il implique principalement deux parties du. nouveau code de contrat et données initialisées. L'ordre de codage des données doit être cohérent avec l'ordre de stockage des cellules de persistance spécifié par le nouveau contrat. Comme vous pouvez le voir à la ligne 36, les données d'initialisation incluent item_index, qui est similaire au tokenId dans ERC721, et l'adresse du contrat actuel renvoyée par la fonction standard my_address, qui est collection_address. L'ordre de ces données est cohérent avec la déclaration dans. article nft.
Le prochain point de connaissance est que dans TON, tous les contrats intelligents non générés peuvent pré-calculer leurs adresses générées. Ceci est similaire à la fonction create2 dans Solidity. La génération de nouvelles adresses dans TON se compose de deux parties. épissé avec la valeur de hachage de stateinit. Comme nous l'avons vu dans l'introduction précédente, la première doit être spécifiée afin de correspondre à l'architecture de partitionnement infinie TON. Il s'agit actuellement d'une valeur unifiée. Obtenu à partir de la chaîne de travail des fonctions standard. Cette dernière est obtenue par la fonction standard cell_hash. Revenons donc à cet exemple, calculate_nft_item_address est une fonction qui précalcule la nouvelle adresse du contrat. Et codez la valeur générée dans le message sur la ligne 53 comme adresse de réception du message interne. nft_content correspond à l'appel d'initialisation du contrat créé. L'implémentation spécifique sera présentée dans le prochain article.
Quant à send_royalty_params, il doit s'agir d'une réponse au message interne d'une requête en lecture seule. Dans l'introduction précédente, nous avons spécialement souligné que le message interne de TON contient non seulement des opérations susceptibles de modifier les données, mais également la lecture. -seule l'opération doit réussir. Elle est implémentée d'une certaine manière, donc le contrat est une telle opération. Tout d'abord, il convient de noter que la ligne 67 indique la marque de la fonction de rappel du demandeur après avoir répondu à la demande. et il renverra les données, qui sont l'index d'article demandé et les données de redevances correspondantes.
Présentons le point de connaissance suivant. Il n'y a que deux entrées unifiées pour les contrats intelligents dans TON, nommées recv_internal et recv_external, la première est l'entrée d'appel unifiée pour tous les messages internes, et la seconde est l'entrée d'appel unifiée pour tous les messages externes. messages. , les développeurs doivent utiliser une méthode de type commutateur pour répondre à différentes requêtes en fonction des différents bits d'indicateur spécifiés par le message dans la fonction selon les exigences. Le bit d'indicateur ici est l'indicateur de fonction de rappel de la ligne 67 ci-dessus. Revenons à cet exemple, effectuez d'abord une vérification des postes vacants sur le message, puis analysez les informations contenues dans le message respectivement. Commencez par analyser la ligne 83 pour obtenir l'adresse de l'expéditeur. Ce paramètre sera utilisé pour les vérifications d'autorisation ultérieures. ici appartient à une autre syntaxe. Je ne m’étendrai pas là-dessus ici. Ensuite, les bits d'indicateur d'opération opérationnelle sont analysés, puis les demandes correspondantes sont traitées en fonction de différents bits d'indicateur. Parmi elles, les fonctions ci-dessus sont appelées respectivement selon une certaine logique. Par exemple, répondez à une demande concernant le paramètre de redevance, ou lancez un nouveau nft et incrémentez l'index global.
Le point de connaissance suivant correspond à la ligne 108. Je pense que vous pouvez également connaître la logique de traitement de cette fonction en la nommant. Elle est similaire à la fonction require dans Solidity. Les exceptions sont levées dans Func via la fonction standard throw_unless. Le paramètre est un code d'erreur, la seconde consiste à vérifier la valeur booléenne du bit, si le bit est faux, une exception sera levée avec le code d'erreur. Dans cette ligne, equal_slices est utilisé pour déterminer si l'adresse de l'expéditeur analysée ci-dessus est égale à l'adresse du propriétaire du stockage persistant du contrat, et un jugement d'autorisation est effectué.
Enfin, afin de rendre la structure du code plus claire, une série de fonctions auxiliaires ont été développées pour aider à obtenir des informations de persistance, qui ne seront pas présentées ici. Les développeurs peuvent se référer à cette structure pour développer leurs propres contrats intelligents.
Le développement de DApp dans l'écosystème TON est vraiment intéressant. Il est très différent du paradigme de développement d'EVM, je vais donc vous présenter comment développer DApp dans TON Chain à travers une série d'articles. Apprenez ensemble avec tout le monde et saisissez cette vague d’opportunités. Vous êtes également invités à interagir avec moi sur Twitter pour proposer des idées de dapp nouvelles et intéressantes et les développer ensemble.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!