Comment rédiger un contrat intelligent pour WebAssembly sur un réseau d'ontologie? Partie 2: C ++

image

Dans cet article, nous examinerons deux exemples de la façon d'écrire un contrat intelligent en C ++ à l'aide de WASM basé sur le réseau de blockchain d'Ontology. Aujourd'hui, aprÚs plusieurs mois de fonctionnement stable en mode test, Ontology a lancé WASM sur le réseau principal, ce qui permet de transférer des contrats dApp avec une logique métier complexe vers la blockchain sans douleur et à moindre coût, enrichissant ainsi considérablement l'écosystÚme dApp.

Ontology Wasm prend également en charge la création de contrats intelligents dans la langue Rust, vous pouvez en lire plus ici .

Voici deux exemples de contrat intelligent: tout d'abord, Ă©crivez «Bonjour tout le monde!» puis crĂ©ez une enveloppe d'argent virtuelle qui peut ĂȘtre envoyĂ©e Ă  un ami en cadeau.

DĂ©veloppement d'un contrat WASM en C ++



Exemple 1. Bonjour tout le monde


Commençons par Hello World:

#include<ontiolib/ontio.hpp> #include<stdio.h> using namespace ontio; class hello:public contract { public: using contract::contract: void sayHello(){ printf("hello world!"); } }; ONTIO_DISPATCH(hello, (sayHello)); 

Création de contrat


Le compilateur CDT d'Ontology Wasm contient un point d'entrée et des paramÚtres d'analyse, de sorte que les développeurs n'ont pas besoin de redéfinir les méthodes d'entrée. De plus, pour écrire la logique du service, vous pouvez appeler les méthodes API du contrat intelligent.

 ONTIO_DISPATCH(hello, (sayHello)); 

Dans l'exemple ci-dessus, nous ne prenons en charge que sayHello jusqu'à présent:

 printf("hello world!"); 

"Bonjour tout le monde!" sera affichĂ© dans le journal du nƓud de dĂ©bogage. Lors de l'Ă©criture directe d'un contrat intelligent, printf ne peut ĂȘtre utilisĂ© que pour le dĂ©bogage, car le contrat intelligent lui-mĂȘme contient des commandes plus fonctionnelles.

API de contrat intelligent


Ontology Wasm fournit les API suivantes pour interagir avec la blockchain du serveur:

image

Exemple 2: enveloppe d'argent


Voyons maintenant un exemple plus complexe utilisant l'API de contrat intelligent Wasm.

Dans cet exemple, nous allons écrire une enveloppe d'argent virtuelle, un analogue de l'enveloppe rouge (hongbao) est une caractéristique populaire du messager chinois Wechat, qui vous permet d'envoyer de l'argent à des amis dans un chat. L'utilisateur reçoit un message sous forme d'enveloppe rouge, l'ouvre et l'argent est automatiquement crédité sur le solde du compte.

Dans le cadre d'un contrat intelligent, les utilisateurs peuvent utiliser ce contrat pour envoyer des jetons ONT, ONG ou OEP-4 à l'aide d'enveloppes d'argent virtuel à leurs amis, qui peuvent ensuite transférer des jetons vers leurs portefeuilles blockchain.

Se préparer à créer un contrat


Créez d'abord le fichier de contrat source et nommez-le redEnvelope.cpp. Ensuite, nous avons besoin de trois API pour ce contrat:

  • createRedEnvelope : crĂ©er une enveloppe d'argent
  • queryEnvelope : demande d'informations sur l'enveloppe
  • claimEnvelope : ouvrez une enveloppe et recevez de l'argent

 #include<ontiolib/ontio.hpp> using namespace ontio; class redEnvlope: public contract{ } ONTIO_DISPATCH(redEnvlope, (createRedEnvlope)(queryEnvlope)(claimEnvelope)); 

Maintenant, nous devons enregistrer la valeur-clé. Dans un contrat intelligent, les données sont stockées dans le contexte du contrat en tant que valeur-clé, et nous devons ajouter un préfixe aux données KEY pour une demande ultérieure.

Ci-dessous, nous définissons trois préfixes que nous utiliserons:

 std::string rePrefix = "RE_PREFIX_"; std::string sentPrefix = "SENT_COUNT_"; std::string claimPrefix = "CLAIM_PREFIX_"; 

Étant donnĂ© que le contrat prend en charge les jetons Ontology - ONT et ONG, nous pouvons dĂ©terminer Ă  l'avance leur adresse de contrat. Contrairement Ă  un contrat intelligent standard, la propre adresse de contrat d'Ontology est fixe et n'est pas dĂ©rivĂ©e du hachage du contrat.

 address ONTAddress = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; address ONGAddress = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2}; 

Ensuite, vous devez enregistrer des informations sur le jeton utilisé dans le contrat: l'adresse du jeton de contrat, le montant total de l'enveloppe et le nombre d'enveloppes.

 struct receiveRecord{ address account; //User address asset amount; //Received amount ONTLIB_SERIALIZE(receiveRecord,(account)(amount)) }; struct envlopeStruct{ address tokenAddress; //Token asset address asset totalAmount; //Total amount asset totalPackageCount; //Total number of red envelope asset remainAmount; //Remaining amount asset remainPackageCount; //Remaining number of red envelope std::vector<struct receiveRecord> records; //Received records ONTLIB_SERIALIZE( envlopeStruct, (tokenAddress)(totalAmount)(totalPackageCount)(remainAmount)(remainPackageCount)(records) ) }; 

Voici l'opération de macro définie par le CDT Ontology Wasm, qui est utilisé pour la sérialisation avant la structuration des données.

 ONTLIB_SERIALIZE(receiveRecord,(account)(amount)) 

Création d'une enveloppe


Maintenant que nous avons terminé les préparatifs nécessaires, nous allons commencer à développer la logique API.

1. Lors de la création d'une enveloppe monétaire, il est nécessaire d'indiquer l'adresse du propriétaire, le nombre et le montant des enveloppes, ainsi que l'adresse du token:

 bool createRedEnvlope(address owner,asset packcount, asset amount,address tokenAddr ){ return true; } 

2. Vérifiez la signature du propriétaire, sinon nous annulerons (annuler la transaction) et quitterons:

 ontio_assert(check_witness(owner),"checkwitness failed"); 

Remarque : ontio_assert (expr, errormsg): false expr renvoie une erreur et quitte le contrat.

3. Si un jeton ONT est utilisĂ© dans une enveloppe, il est important de se rappeler que ONT n'est pas fragmentĂ© (au moins 1 ONT). Ensuite, le montant total de l'enveloppe monĂ©taire doit ĂȘtre supĂ©rieur ou Ă©gal au nombre de jetons afin de s'assurer qu'il y a au moins 1 ONT dans chaque enveloppe:

 if (isONTToken(tokenAddr)){ ontio_assert(amount >= packcount,"ont amount should greater than packcount"); } 

4. Ensuite, nous déterminons pour le titulaire de l'enveloppe le nombre total d'enveloppes d'argent qu'il envoie:

 key sentkey = make_key(sentPrefix,owner.tohexstring()); asset sentcount = 0; storage_get(sentkey,sentcount); sentcount += 1; storage_put(sentkey,sentcount); 

5. Générez le hachage de l'enveloppe - l'identifiant qui marque cette enveloppe:

 H256 hash ; hash256(make_key(owner,sentcount),hash) ; key rekey = make_key(rePrefix,hash256ToHexstring(hash)); 

6. Nous traduirons les jetons dans le contrat. Nous découvrons l'adresse du contrat en cours d'exécution à l'aide de la commande self_address (), puis nous transférons la quantité de jetons attribuée au contrat en fonction du type de jetons:

 address selfaddr = self_address(); if (isONTToken(tokenAddr)){ bool result = ont::transfer(owner,selfaddr ,amount); ontio_assert(result,"transfer native token failed!"); }else if (isONGToken(tokenAddr)){ bool result = ong::transfer(owner,selfaddr ,amount); ontio_assert(result,"transfer native token failed!"); }else{ std::vector<char> params = pack(std::string("transfer"),owner,selfaddr,amount); bool res; call_contract(tokenAddr,params, res ); ontio_assert(res,"transfer oep4 token failed!"); } 

Note 1: pour ONT et ONG, Ontology Wasm CDT fournit l'API ont :: transfer pour transfĂ©rer des jetons; Les jetons OEP-4 doivent ĂȘtre envoyĂ©s en utilisant la mĂ©thode conventionnelle d'appel croisĂ©.

Remarque 2: comme une adresse de portefeuille classique, l'adresse du contrat peut accepter tout type de jeton. Cependant, l'adresse du contrat est générée par un hachage binaire compilé et n'a donc pas de clé privée correspondante et ne peut pas utiliser de jetons de contrat. Si vous n'avez pas configuré de clé privée, vous ne pourrez pas gérer ces jetons.

7. Enregistrez les informations sur le contrat dans l'entrepÎt de données:

 struct envlopeStruct es ; es.tokenAddress = tokenAddr; es.totalAmount = amount; es.totalPackageCount = packcount; es.remainAmount = amount; es.remainPackageCount = packcount; es.records = {}; storage_put(rekey, es); 

8. Envoyez une notification concernant la crĂ©ation de l'enveloppe. Il s'agit d'un processus asynchrone pour invoquer un contrat intelligent, le contrat enverra Ă©galement une notification du rĂ©sultat de l'exĂ©cution. Le format d'exĂ©cution peut ĂȘtre dĂ©terminĂ© par l'auteur du contrat.

 char buffer [100]; sprintf(buffer, "{\"states\":[\"%s\", \"%s\", \"%s\"]}","createEnvlope",owner.tohexstring().c_str(),hash256ToHexstring(hash).c_str()); notify(buffer); return true; 

Hourra, l'enveloppe d'argent est presque prĂȘte. Voyons maintenant comment demander des informations sur l'enveloppe.

Enveloppe de requĂȘte (requĂȘte


La logique de la demande est assez simple, il vous suffit d'obtenir les informations et le format du magasin de données, puis de sortir:

 std::string queryEnvlope(std::string hash){ key rekey = make_key(rePrefix,hash); struct envlopeStruct es; storage_get(rekey,es); return formatEnvlope(es); } 

Remarque: pour les opĂ©rations de contrat intelligent en lecture seule (par exemple, la requĂȘte), vous pouvez vĂ©rifier le rĂ©sultat via une prĂ©-exĂ©cution. Contrairement Ă  un appel de contrat rĂ©gulier, le prĂ©-exĂ©cutable ne nĂ©cessite pas de signature de portefeuille et ne nĂ©cessite donc pas de commission en ONG. Cela fait, les autres utilisateurs peuvent dĂ©sormais demander l'enveloppe s'ils ont un hachage d'enveloppe (ID enveloppe).

Enveloppe de réception


À ce stade, nous avons dĂ©jĂ  transfĂ©rĂ© avec succĂšs des jetons vers un contrat intelligent, afin que vos amis puissent rĂ©clamer avec succĂšs une part dans l'enveloppe, vous devez leur envoyer l'identifiant de l'enveloppe (hachage).

1. Pour recevoir une enveloppe, vous devez saisir l'adresse de votre compte et le hachage de l'enveloppe:

 bool claimEnvlope(address account, std::string hash){ return true; } 

2. Ensuite, le contrat vĂ©rifiera la signature de votre compte pour vous assurer que vous en ĂȘtes le propriĂ©taire. Chaque compte ne peut demander une enveloppe qu'une seule fois:

 ontio_assert(check_witness(account),"checkwitness failed"); key claimkey = make_key(claimPrefix,hash,account); asset claimed = 0 ; storage_get(claimkey,claimed); ontio_assert(claimed == 0,"you have claimed this envlope!"); 

3. Vérifiez si l'enveloppe est reçue conformément aux informations de hachage reçues du magasin:

 key rekey = make_key(rePrefix,hash); struct envlopeStruct es; storage_get(rekey,es); ontio_assert(es.remainAmount > 0, "the envlope has been claimed over!"); ontio_assert(es.remainPackageCount > 0, "the envlope has been claimed over!"); 

4. Création d'un dossier de réclamation:

 struct receiveRecord record ; record.account = account; asset claimAmount = 0; 

5. Calcul du montant pour chaque demandeur d'enveloppe.
Pour le dernier participant, le montant du solde est déterminé, pour tout autre, le montant déclaré est déterminé par un nombre aléatoire calculé par le hachage du bloc courant et les informations courantes sur l'enveloppe:

 if (es.remainPackageCount == 1){ claimAmount = es.remainAmount; record.amount = claimAmount; }else{ H256 random = current_blockhash() ; char part[8]; memcpy(part,&random,8); uint64_t random_num = *(uint64_t*)part; uint32_t percent = random_num % 100 + 1; claimAmount = es.remainAmount * percent / 100; //ont case if (claimAmount == 0){ claimAmount = 1; }else if(isONTToken(es.tokenAddress)){ if ( (es.remainAmount - claimAmount) < (es.remainPackageCount - 1)){ claimAmount = es.remainAmount - es.remainPackageCount + 1; } } record.amount = claimAmount; } es.remainAmount -= claimAmount; es.remainPackageCount -= 1; es.records.push_back(record); 

6. Créditer des fonds


Le montant correspondant de jetons est transféré sur le compte des demandeurs d'enveloppe en fonction du résultat du calcul:

 address selfaddr = self_address(); if (isONTToken(es.tokenAddress)){ bool result = ont::transfer(selfaddr,account ,claimAmount); ontio_assert(result,"transfer ont token failed!"); } else if (isONGToken(es.tokenAddress)){ bool result = ong::transfer(selfaddr,account ,claimAmount); ontio_assert(result,"transfer ong token failed!"); } else{ std::vector<char> params = pack(std::string("transfer"),selfaddr,account,claimAmount); bool res = false; call_contract(es.tokenAddress,params, res ); ontio_assert(res,"transfer oep4 token failed!"); } 

7. Nous noterons les informations sur la réception des fonds et les informations mises à jour sur l'enveloppe dans le coffre-fort et enverrons une notification sur l'exécution du contrat:

 storage_put(claimkey,claimAmount); storage_put(rekey,es); char buffer [100]; std::sprintf(buffer, "{\"states\":[\"%s\",\"%s\",\"%s\",\"%lld\"]}","claimEnvlope",hash.c_str(),account.tohexstring().c_str(),claimAmount); notify(buffer); return true; 

Comme mentionné ci-dessus, ce contrat peut envoyer des jetons du contrat via l'API claimEnvelope. Cela garantit la sécurité des jetons lorsqu'ils sont dans l'enveloppe, car personne ne peut retirer des actifs sans remplir les conditions requises.

C'est fait! Vous avez Ă©crit votre premier contrat intelligent. Le code de contrat complet peut ĂȘtre trouvĂ© sur GitHub ici .

Test de contrat


Il existe deux façons de vérifier un contrat:

  1. Utiliser CLI
  2. Utilisez Golang SDK

Conclusion


Dans cet article, nous avons expliquĂ© comment Ă©crire un contrat intelligent pour Ontolgy Wasm Ă  l'aide de l'API blockchain. Il reste Ă  rĂ©soudre le problĂšme de confidentialitĂ© pour que le contrat intelligent se transforme en un produit Ă  part entiĂšre. À ce stade du code, n'importe qui peut obtenir un hachage de l'enveloppe rouge en suivant les enregistrements du contrat, ce qui signifie que n'importe qui peut rĂ©clamer une part de l'enveloppe. Ce problĂšme peut ĂȘtre rĂ©solu simplement - nous dĂ©finissons une liste de comptes qui peuvent demander une enveloppe lors de sa crĂ©ation. Si vous le souhaitez, cette fonction peut Ă©galement ĂȘtre testĂ©e.



Obtenez une subvention en ontologie pour le développement de dApp à partir de 20 000 $

Postulez pour le programme de talent Ă©tudiant en ontologie



Êtes-vous dĂ©veloppeur? Rejoignez notre communautĂ© technologique sur Discord . De plus, jetez un Ɠil au Developer Center sur notre site Web, oĂč vous pouvez trouver des outils de dĂ©veloppement, de la documentation et bien plus encore.

Ontologie


Source: https://habr.com/ru/post/fr473784/


All Articles